diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2009-04-06 10:19:36 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2009-04-06 10:19:36 -0700 |
commit | d080581db1f9ee4e1e6d07d2b01c13c67908a391 (patch) | |
tree | cc484b289fa5a30c4631f9faa1d8b456bffeebfc /src | |
parent | 7a7c4c5fca83a8d47c7e71c9c080a882ebe204a9 (diff) | |
parent | 639cb0a42d953ee32bc7e96b0cdfa96cd40e9fc1 (diff) | |
download | gem5-d080581db1f9ee4e1e6d07d2b01c13c67908a391.tar.xz |
Merge ARM into the head. ARM will compile but may not actually work.
Diffstat (limited to 'src')
812 files changed, 50839 insertions, 24571 deletions
diff --git a/src/SConscript b/src/SConscript index 69c5b946d..c02bf239d 100644 --- a/src/SConscript +++ b/src/SConscript @@ -28,11 +28,15 @@ # # Authors: Nathan Binkert +import array import imp +import marshal import os +import re import sys +import zlib -from os.path import basename, exists, isdir, isfile, join as joinpath +from os.path import basename, dirname, exists, isdir, isfile, join as joinpath import SCons @@ -44,6 +48,8 @@ Import('*') # Children need to see the environment Export('env') +build_env = dict([(opt, env[opt]) for opt in env.ExportVariables]) + def sort_list(_list): """return a sorted copy of '_list'""" if isinstance(_list, list): @@ -54,39 +60,60 @@ def sort_list(_list): return _list class PySourceFile(object): - def __init__(self, package, source): - filename = str(source) + invalid_sym_char = re.compile('[^A-z0-9_]') + def __init__(self, package, tnode): + snode = tnode.srcnode() + filename = str(tnode) pyname = basename(filename) assert pyname.endswith('.py') name = pyname[:-3] - path = package.split('.') - modpath = path + if package: + path = package.split('.') + else: + path = [] + + modpath = path[:] if name != '__init__': modpath += [name] modpath = '.'.join(modpath) - arcpath = package.split('.') + [ pyname + 'c' ] + arcpath = path + [ pyname ] arcname = joinpath(*arcpath) - self.source = source + debugname = snode.abspath + if not exists(debugname): + debugname = tnode.abspath + + self.tnode = tnode + self.snode = snode self.pyname = pyname - self.srcpath = source.srcnode().abspath self.package = package self.modpath = modpath self.arcname = arcname - self.filename = filename + self.debugname = debugname self.compiled = File(filename + 'c') + self.assembly = File(filename + '.s') + self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath) + ######################################################################## # Code for adding source files of various types # -cc_sources = [] +cc_lib_sources = [] def Source(source): - '''Add a C/C++ source file to the build''' + '''Add a source file to the libm5 build''' if not isinstance(source, SCons.Node.FS.File): source = File(source) - cc_sources.append(source) + cc_lib_sources.append(source) + +cc_bin_sources = [] +def BinSource(source): + '''Add a source file to the m5 binary build''' + if not isinstance(source, SCons.Node.FS.File): + source = File(source) + + cc_bin_sources.append(source) py_sources = [] def PySource(package, source): @@ -123,40 +150,50 @@ def SwigSource(package, source): val = source,package swig_sources.append(val) +unit_tests = [] +def UnitTest(target, sources): + if not isinstance(sources, (list, tuple)): + sources = [ sources ] + + srcs = [] + for source in sources: + if not isinstance(source, SCons.Node.FS.File): + source = File(source) + srcs.append(source) + + unit_tests.append((target, srcs)) + # Children should have access Export('Source') +Export('BinSource') Export('PySource') Export('SimObject') Export('SwigSource') +Export('UnitTest') ######################################################################## # # Trace Flags # -all_flags = {} -trace_flags = [] -def TraceFlag(name, desc=''): - if name in all_flags: +trace_flags = {} +def TraceFlag(name, desc=None): + if name in trace_flags: raise AttributeError, "Flag %s already specified" % name - flag = (name, (), desc) - trace_flags.append(flag) - all_flags[name] = () + trace_flags[name] = (name, (), desc) -def CompoundFlag(name, flags, desc=''): - if name in all_flags: +def CompoundFlag(name, flags, desc=None): + if name in trace_flags: raise AttributeError, "Flag %s already specified" % name compound = tuple(flags) for flag in compound: - if flag not in all_flags: + if flag not in trace_flags: raise AttributeError, "Trace flag %s not found" % flag - if all_flags[flag]: + if trace_flags[flag][1]: raise AttributeError, \ "Compound flag can't point to another compound flag" - flag = (name, compound, desc) - trace_flags.append(flag) - all_flags[name] = compound + trace_flags[name] = (name, compound, desc) Export('TraceFlag') Export('CompoundFlag') @@ -172,26 +209,40 @@ Export('CompoundFlag') # files. env.Append(CPPPATH=Dir('.')) +for extra_dir in extras_dir_list: + env.Append(CPPPATH=Dir(extra_dir)) + # Add a flag defining what THE_ISA should be for all compilation env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) +# Workaround for bug in SCons version > 0.97d20071212 +# Scons bug id: 2006 M5 Bug id: 308 +for root, dirs, files in os.walk(base_dir, topdown=True): + Dir(root[len(base_dir) + 1:]) + ######################################################################## # # Walk the tree and execute all SConscripts in subdirectories # -for base_dir in base_dir_list: - here = Dir('.').srcnode().abspath - for root, dirs, files in os.walk(base_dir, topdown=True): - if root == here: - # we don't want to recurse back into this SConscript - continue +here = Dir('.').srcnode().abspath +for root, dirs, files in os.walk(base_dir, topdown=True): + if root == here: + # we don't want to recurse back into this SConscript + continue + if 'SConscript' in files: + build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) + SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) + +for extra_dir in extras_dir_list: + prefix_len = len(dirname(extra_dir)) + 1 + for root, dirs, files in os.walk(extra_dir, topdown=True): if 'SConscript' in files: - build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:]) + build_dir = joinpath(env['BUILDDIR'], root[prefix_len:]) SConscript(joinpath(root, 'SConscript'), build_dir=build_dir) -for opt in env.ExportOptions: +for opt in env.ExportVariables: env.ConfigFile(opt) ######################################################################## @@ -199,55 +250,150 @@ for opt in env.ExportOptions: # Prevent any SimObjects from being added after this point, they # should all have been added in the SConscripts above # -sim_objects_fixed = True +class DictImporter(object): + '''This importer takes a dictionary of arbitrary module names that + map to arbitrary filenames.''' + def __init__(self, modules): + self.modules = modules + self.installed = set() -######################################################################## -# -# Manually turn python/generate.py into a python module and import it -# -generate_file = File('python/generate.py') -generate_module = imp.new_module('generate') -sys.modules['generate'] = generate_module -exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__ + def __del__(self): + self.unload() -######################################################################## -# -# build a generate -# -from generate import Generate -optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) -generate = Generate(py_sources, sim_object_modfiles, optionDict) -m5 = generate.m5 + def unload(self): + import sys + for module in self.installed: + del sys.modules[module] + self.installed = set() + + def find_module(self, fullname, path): + if fullname == 'defines': + return self + + if fullname == 'm5.objects': + return self + + if fullname.startswith('m5.internal'): + return None + + if fullname in self.modules and exists(self.modules[fullname]): + return self + + return None + + def load_module(self, fullname): + mod = imp.new_module(fullname) + sys.modules[fullname] = mod + self.installed.add(fullname) + + mod.__loader__ = self + if fullname == 'm5.objects': + mod.__path__ = fullname.split('.') + return mod + + if fullname == 'defines': + mod.__dict__['buildEnv'] = build_env + return mod + + srcfile = self.modules[fullname] + if basename(srcfile) == '__init__.py': + mod.__path__ = fullname.split('.') + mod.__file__ = srcfile + + exec file(srcfile, 'r') in mod.__dict__ + + return mod + +py_modules = {} +for source in py_sources: + py_modules[source.modpath] = source.snode.abspath + +# install the python importer so we can grab stuff from the source +# tree itself. We can't have SimObjects added after this point or +# else we won't know about them for the rest of the stuff. +sim_objects_fixed = True +importer = DictImporter(py_modules) +sys.meta_path[0:0] = [ importer ] + +import m5 + +# import all sim objects so we can populate the all_objects list +# make sure that we're working with a list, then let's sort it +sim_objects = list(sim_object_modfiles) +sim_objects.sort() +for simobj in sim_objects: + exec('from m5.objects import %s' % simobj) + +# we need to unload all of the currently imported modules so that they +# will be re-imported the next time the sconscript is run +importer.unload() +sys.meta_path.remove(importer) + +sim_objects = m5.SimObject.allClasses +all_enums = m5.params.allEnums + +all_params = {} +for name,obj in sim_objects.iteritems(): + for param in obj._params.local.values(): + if not hasattr(param, 'swig_decl'): + continue + pname = param.ptype_str + if pname not in all_params: + all_params[pname] = param ######################################################################## # # calculate extra dependencies # module_depends = ["m5", "m5.SimObject", "m5.params"] -module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ] -file_depends = [ generate_file ] -depends = module_depends + file_depends +depends = [ File(py_modules[dep]) for dep in module_depends ] ######################################################################## # # Commands for the basic automatically generated python files # +# Generate Python file containing a dict specifying the current +# build_env flags. +def makeDefinesPyFile(target, source, env): + f = file(str(target[0]), 'w') + build_env, hg_info = [ x.get_contents() for x in source ] + print >>f, "buildEnv = %s" % build_env + print >>f, "hgRev = '%s'" % hg_info + f.close() + +defines_info = [ Value(build_env), Value(env['HG_INFO']) ] # Generate a file with all of the compile options in it -env.Command('python/m5/defines.py', Value(optionDict), - generate.makeDefinesPyFile) +env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile) PySource('m5', 'python/m5/defines.py') +# Generate python file containing info about the M5 source code +def makeInfoPyFile(target, source, env): + f = file(str(target[0]), 'w') + for src in source: + data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) + print >>f, "%s = %s" % (src, repr(data)) + f.close() + # Generate a file that wraps the basic top level files env.Command('python/m5/info.py', [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], - generate.makeInfoPyFile) + makeInfoPyFile) PySource('m5', 'python/m5/info.py') +# Generate the __init__.py file for m5.objects +def makeObjectsInitFile(target, source, env): + f = file(str(target[0]), 'w') + print >>f, 'from params import *' + print >>f, 'from m5.SimObject import *' + for module in source: + print >>f, 'from %s import *' % module.get_contents() + f.close() + # Generate an __init__.py file for the objects package env.Command('python/m5/objects/__init__.py', [ Value(o) for o in sort_list(sim_object_modfiles) ], - generate.makeObjectsInitFile) + makeObjectsInitFile) PySource('m5.objects', 'python/m5/objects/__init__.py') ######################################################################## @@ -255,51 +401,189 @@ PySource('m5.objects', 'python/m5/objects/__init__.py') # Create all of the SimObject param headers and enum headers # +def createSimObjectParam(target, source, env): + assert len(target) == 1 and len(source) == 1 + + hh_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = sim_objects[name] + + print >>hh_file, obj.cxx_decl() + +def createSwigParam(target, source, env): + assert len(target) == 1 and len(source) == 1 + + i_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + param = all_params[name] + + for line in param.swig_decl(): + print >>i_file, line + +def createEnumStrings(target, source, env): + assert len(target) == 1 and len(source) == 1 + + cc_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = all_enums[name] + + print >>cc_file, obj.cxx_def() + cc_file.close() + +def createEnumParam(target, source, env): + assert len(target) == 1 and len(source) == 1 + + hh_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = all_enums[name] + + print >>hh_file, obj.cxx_decl() + # Generate all of the SimObject param struct header files params_hh_files = [] -for name,simobj in generate.sim_objects.iteritems(): - extra_deps = [ File(generate.py_modules[simobj.__module__]) ] +for name,simobj in sim_objects.iteritems(): + extra_deps = [ File(py_modules[simobj.__module__]) ] hh_file = File('params/%s.hh' % name) params_hh_files.append(hh_file) - env.Command(hh_file, Value(name), generate.createSimObjectParam) + env.Command(hh_file, Value(name), createSimObjectParam) env.Depends(hh_file, depends + extra_deps) # Generate any parameter header files needed -for name,param in generate.params.iteritems(): +params_i_files = [] +for name,param in all_params.iteritems(): if isinstance(param, m5.params.VectorParamDesc): ext = 'vptype' else: ext = 'ptype' i_file = File('params/%s_%s.i' % (name, ext)) - env.Command(i_file, Value(name), generate.createSwigParam) + params_i_files.append(i_file) + env.Command(i_file, Value(name), createSwigParam) env.Depends(i_file, depends) # Generate all enum header files -for name,enum in generate.enums.iteritems(): - extra_deps = [ File(generate.py_modules[enum.__module__]) ] +for name,enum in all_enums.iteritems(): + extra_deps = [ File(py_modules[enum.__module__]) ] cc_file = File('enums/%s.cc' % name) - env.Command(cc_file, Value(name), generate.createEnumStrings) + env.Command(cc_file, Value(name), createEnumStrings) env.Depends(cc_file, depends + extra_deps) Source(cc_file) hh_file = File('enums/%s.hh' % name) - env.Command(hh_file, Value(name), generate.createEnumParam) + env.Command(hh_file, Value(name), createEnumParam) env.Depends(hh_file, depends + extra_deps) # Build the big monolithic swigged params module (wraps all SimObject # param structs and enum structs) +def buildParams(target, source, env): + names = [ s.get_contents() for s in source ] + objs = [ sim_objects[name] for name in names ] + out = file(target[0].abspath, 'w') + + ordered_objs = [] + obj_seen = set() + def order_obj(obj): + name = str(obj) + if name in obj_seen: + return + + obj_seen.add(name) + if str(obj) != 'SimObject': + order_obj(obj.__bases__[0]) + + ordered_objs.append(obj) + + for obj in objs: + order_obj(obj) + + enums = set() + predecls = [] + pd_seen = set() + + def add_pds(*pds): + for pd in pds: + if pd not in pd_seen: + predecls.append(pd) + pd_seen.add(pd) + + for obj in ordered_objs: + params = obj._params.local.values() + for param in params: + ptype = param.ptype + if issubclass(ptype, m5.params.Enum): + if ptype not in enums: + enums.add(ptype) + pds = param.swig_predecls() + if isinstance(pds, (list, tuple)): + add_pds(*pds) + else: + add_pds(pds) + + print >>out, '%module params' + + print >>out, '%{' + for obj in ordered_objs: + print >>out, '#include "params/%s.hh"' % obj + print >>out, '%}' + + for pd in predecls: + print >>out, pd + + enums = list(enums) + enums.sort() + for enum in enums: + print >>out, '%%include "enums/%s.hh"' % enum.__name__ + print >>out + + for obj in ordered_objs: + if obj.swig_objdecls: + for decl in obj.swig_objdecls: + print >>out, decl + continue + + class_path = obj.cxx_class.split('::') + classname = class_path[-1] + namespaces = class_path[:-1] + namespaces.reverse() + + code = '' + + if namespaces: + code += '// avoid name conflicts\n' + sep_string = '_COLONS_' + flat_name = sep_string.join(class_path) + code += '%%rename(%s) %s;\n' % (flat_name, classname) + + code += '// stop swig from creating/wrapping default ctor/dtor\n' + code += '%%nodefault %s;\n' % classname + code += 'class %s ' % classname + if obj._base: + code += ': public %s' % obj._base.cxx_class + code += ' {};\n' + + for ns in namespaces: + new_code = 'namespace %s {\n' % ns + new_code += code + new_code += '}\n' + code = new_code + + print >>out, code + + print >>out, '%%include "src/sim/sim_object_params.hh"' % obj + for obj in ordered_objs: + print >>out, '%%include "params/%s.hh"' % obj + params_file = File('params/params.i') -names = sort_list(generate.sim_objects.keys()) -env.Command(params_file, [ Value(v) for v in names ], - generate.buildParams) -env.Depends(params_file, params_hh_files + depends) +names = sort_list(sim_objects.keys()) +env.Command(params_file, [ Value(v) for v in names ], buildParams) +env.Depends(params_file, params_hh_files + params_i_files + depends) SwigSource('m5.objects', params_file) # Build all swig modules swig_modules = [] +cc_swig_sources = [] for source,package in swig_sources: filename = str(source) assert filename.endswith('.i') @@ -316,37 +600,316 @@ for source,package in swig_sources: env.Depends(cc_file, source) swig_modules.append(Value(module)) - Source(cc_file) + cc_swig_sources.append(File(cc_file)) PySource(package, py_file) # Generate the main swig init file -env.Command('swig/init.cc', swig_modules, generate.makeSwigInit) -Source('swig/init.cc') +def makeSwigInit(target, source, env): + f = file(str(target[0]), 'w') + print >>f, 'extern "C" {' + for module in source: + print >>f, ' void init_%s();' % module.get_contents() + print >>f, '}' + print >>f, 'void initSwig() {' + for module in source: + print >>f, ' init_%s();' % module.get_contents() + print >>f, '}' + f.close() + +env.Command('python/swig/init.cc', swig_modules, makeSwigInit) +Source('python/swig/init.cc') # Generate traceflags.py -flags = [ Value(f) for f in trace_flags ] -env.Command('base/traceflags.py', flags, generate.traceFlagsPy) +def traceFlagsPy(target, source, env): + assert(len(target) == 1) + + f = file(str(target[0]), 'w') + + allFlags = [] + for s in source: + val = eval(s.get_contents()) + allFlags.append(val) + + allFlags.sort() + + print >>f, 'basic = [' + for flag, compound, desc in allFlags: + if not compound: + print >>f, " '%s'," % flag + print >>f, " ]" + print >>f + + print >>f, 'compound = [' + print >>f, " 'All'," + for flag, compound, desc in allFlags: + if compound: + print >>f, " '%s'," % flag + print >>f, " ]" + print >>f + + print >>f, "all = frozenset(basic + compound)" + print >>f + + print >>f, 'compoundMap = {' + all = tuple([flag for flag,compound,desc in allFlags if not compound]) + print >>f, " 'All' : %s," % (all, ) + for flag, compound, desc in allFlags: + if compound: + print >>f, " '%s' : %s," % (flag, compound) + print >>f, " }" + print >>f + + print >>f, 'descriptions = {' + print >>f, " 'All' : 'All flags'," + for flag, compound, desc in allFlags: + print >>f, " '%s' : '%s'," % (flag, desc) + print >>f, " }" + + f.close() + +def traceFlagsCC(target, source, env): + assert(len(target) == 1) + + f = file(str(target[0]), 'w') + + allFlags = [] + for s in source: + val = eval(s.get_contents()) + allFlags.append(val) + + # file header + print >>f, ''' +/* + * DO NOT EDIT THIS FILE! Automatically generated + */ + +#include "base/traceflags.hh" + +using namespace Trace; + +const char *Trace::flagStrings[] = +{''' + + # The string array is used by SimpleEnumParam to map the strings + # provided by the user to enum values. + for flag, compound, desc in allFlags: + if not compound: + print >>f, ' "%s",' % flag + + print >>f, ' "All",' + for flag, compound, desc in allFlags: + if compound: + print >>f, ' "%s",' % flag + + print >>f, '};' + print >>f + print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) + print >>f + + # + # Now define the individual compound flag arrays. There is an array + # for each compound flag listing the component base flags. + # + all = tuple([flag for flag,compound,desc in allFlags if not compound]) + print >>f, 'static const Flags AllMap[] = {' + for flag, compound, desc in allFlags: + if not compound: + print >>f, " %s," % flag + print >>f, '};' + print >>f + + for flag, compound, desc in allFlags: + if not compound: + continue + print >>f, 'static const Flags %sMap[] = {' % flag + for flag in compound: + print >>f, " %s," % flag + print >>f, " (Flags)-1" + print >>f, '};' + print >>f + + # + # Finally the compoundFlags[] array maps the compound flags + # to their individual arrays/ + # + print >>f, 'const Flags *Trace::compoundFlags[] =' + print >>f, '{' + print >>f, ' AllMap,' + for flag, compound, desc in allFlags: + if compound: + print >>f, ' %sMap,' % flag + # file trailer + print >>f, '};' + + f.close() + +def traceFlagsHH(target, source, env): + assert(len(target) == 1) + + f = file(str(target[0]), 'w') + + allFlags = [] + for s in source: + val = eval(s.get_contents()) + allFlags.append(val) + + # file header boilerplate + print >>f, ''' +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.py + */ + +#ifndef __BASE_TRACE_FLAGS_HH__ +#define __BASE_TRACE_FLAGS_HH__ + +namespace Trace { + +enum Flags {''' + + # Generate the enum. Base flags come first, then compound flags. + idx = 0 + for flag, compound, desc in allFlags: + if not compound: + print >>f, ' %s = %d,' % (flag, idx) + idx += 1 + + numBaseFlags = idx + print >>f, ' NumFlags = %d,' % idx + + # put a comment in here to separate base from compound flags + print >>f, ''' +// The remaining enum values are *not* valid indices for Trace::flags. +// They are "compound" flags, which correspond to sets of base +// flags, and are used by changeFlag.''' + + print >>f, ' All = %d,' % idx + idx += 1 + for flag, compound, desc in allFlags: + if compound: + print >>f, ' %s = %d,' % (flag, idx) + idx += 1 + + numCompoundFlags = idx - numBaseFlags + print >>f, ' NumCompoundFlags = %d' % numCompoundFlags + + # trailer boilerplate + print >>f, '''\ +}; // enum Flags + +// Array of strings for SimpleEnumParam +extern const char *flagStrings[]; +extern const int numFlagStrings; + +// Array of arraay pointers: for each compound flag, gives the list of +// base flags to set. Inidividual flag arrays are terminated by -1. +extern const Flags *compoundFlags[]; + +/* namespace Trace */ } + +#endif // __BASE_TRACE_FLAGS_HH__ +''' + + f.close() + +flags = [ Value(f) for f in trace_flags.values() ] +env.Command('base/traceflags.py', flags, traceFlagsPy) PySource('m5', 'base/traceflags.py') -env.Command('base/traceflags.hh', flags, generate.traceFlagsHH) -env.Command('base/traceflags.cc', flags, generate.traceFlagsCC) +env.Command('base/traceflags.hh', flags, traceFlagsHH) +env.Command('base/traceflags.cc', flags, traceFlagsCC) Source('base/traceflags.cc') -# Build the zip file -py_compiled = [] -py_zip_depends = [] -for source in py_sources: - env.Command(source.compiled, source.source, generate.compilePyFile) - py_compiled.append(source.compiled) +# embed python files. All .py files that have been indicated by a +# PySource() call in a SConscript need to be embedded into the M5 +# library. To do that, we compile the file to byte code, marshal the +# byte code, compress it, and then generate an assembly file that +# inserts the result into the data section with symbols indicating the +# beginning, and end (and with the size at the end) +py_sources_tnodes = {} +for pysource in py_sources: + py_sources_tnodes[pysource.tnode] = pysource + +def objectifyPyFile(target, source, env): + '''Action function to compile a .py into a code object, marshal + it, compress it, and stick it into an asm file so the code appears + as just bytes with a label in the data section''' + + src = file(str(source[0]), 'r').read() + dst = file(str(target[0]), 'w') + + pysource = py_sources_tnodes[source[0]] + compiled = compile(src, pysource.debugname, 'exec') + marshalled = marshal.dumps(compiled) + compressed = zlib.compress(marshalled) + data = compressed + + # Some C/C++ compilers prepend an underscore to global symbol + # names, so if they're going to do that, we need to prepend that + # leading underscore to globals in the assembly file. + if env['LEADING_UNDERSCORE']: + sym = '_' + pysource.symname + else: + sym = pysource.symname + + step = 16 + print >>dst, ".data" + print >>dst, ".globl %s_beg" % sym + print >>dst, ".globl %s_end" % sym + print >>dst, "%s_beg:" % sym + for i in xrange(0, len(data), step): + x = array.array('B', data[i:i+step]) + print >>dst, ".byte", ','.join([str(d) for d in x]) + print >>dst, "%s_end:" % sym + print >>dst, ".long %d" % len(marshalled) - # make the zipfile depend on the archive name so that the archive - # is rebuilt if the name changes - py_zip_depends.append(Value(source.arcname)) +for source in py_sources: + env.Command(source.assembly, source.tnode, objectifyPyFile) + Source(source.assembly) + +# Generate init_python.cc which creates a bunch of EmbeddedPyModule +# structs that describe the embedded python code. One such struct +# contains information about the importer that python uses to get at +# the embedded files, and then there's a list of all of the rest that +# the importer uses to load the rest on demand. +py_sources_symbols = {} +for pysource in py_sources: + py_sources_symbols[pysource.symname] = pysource +def pythonInit(target, source, env): + dst = file(str(target[0]), 'w') + + def dump_mod(sym, endchar=','): + pysource = py_sources_symbols[sym] + print >>dst, ' { "%s",' % pysource.arcname + print >>dst, ' "%s",' % pysource.modpath + print >>dst, ' %s_beg, %s_end,' % (sym, sym) + print >>dst, ' %s_end - %s_beg,' % (sym, sym) + print >>dst, ' *(int *)%s_end }%s' % (sym, endchar) + + print >>dst, '#include "sim/init.hh"' + + for sym in source: + sym = sym.get_contents() + print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym) + + print >>dst, "const EmbeddedPyModule embeddedPyImporter = " + dump_mod("PyEMB_importer", endchar=';'); + print >>dst + + print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {" + for i,sym in enumerate(source): + sym = sym.get_contents() + if sym == "PyEMB_importer": + # Skip the importer since we've already exported it + continue + dump_mod(sym) + print >>dst, " { 0, 0, 0, 0, 0, 0 }" + print >>dst, "};" -# Add the zip file target to the environment. -m5zip = File('m5py.zip') -env.Command(m5zip, py_compiled, generate.buildPyZip) -env.Depends(m5zip, py_zip_depends) +symbols = [Value(s.symname) for s in py_sources] +env.Command('sim/init_python.cc', symbols, pythonInit) +Source('sim/init_python.cc') ######################################################################## # @@ -362,11 +925,18 @@ envList = [] # Object nodes (including an extra one for date.cc). We explicitly # add the Object nodes so we can set up special dependencies for # date.cc. -def make_objs(sources, env): - objs = [env.Object(s) for s in sources] +def make_objs(sources, env, static): + if static: + XObject = env.StaticObject + else: + XObject = env.SharedObject + + objs = [ XObject(s) for s in sources ] + # make date.cc depend on all other objects so it always gets # recompiled whenever anything else does - date_obj = env.Object('base/date.cc') + date_obj = XObject('base/date.cc') + env.Depends(date_obj, objs) objs.append(date_obj) return objs @@ -376,23 +946,50 @@ def make_objs(sources, env): # binary. Additional keyword arguments are appended to corresponding # build environment vars. def makeEnv(label, objsfx, strip = False, **kwargs): - newEnv = env.Copy(OBJSUFFIX=objsfx) - newEnv.Label = label - newEnv.Append(**kwargs) - exe = 'm5.' + label # final executable - bin = exe + '.bin' # executable w/o appended Python zip archive - newEnv.Program(bin, make_objs(cc_sources, newEnv)) + # SCons doesn't know to append a library suffix when there is a '.' in the + # name. Use '_' instead. + libname = 'm5_' + label + exename = 'm5.' + label + + new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's') + new_env.Label = label + new_env.Append(**kwargs) + + swig_env = new_env.Clone() + if env['GCC']: + swig_env.Append(CCFLAGS='-Wno-uninitialized') + swig_env.Append(CCFLAGS='-Wno-sign-compare') + swig_env.Append(CCFLAGS='-Wno-parentheses') + + static_objs = make_objs(cc_lib_sources, new_env, static=True) + shared_objs = make_objs(cc_lib_sources, new_env, static=False) + static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ] + shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ] + + # First make a library of everything but main() so other programs can + # link against m5. + static_lib = new_env.StaticLibrary(libname, static_objs) + shared_lib = new_env.SharedLibrary(libname, shared_objs) + + for target, sources in unit_tests: + objs = [ new_env.StaticObject(s) for s in sources ] + new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs) + + # Now link a stub with main() and the static library. + objects = [new_env.Object(s) for s in cc_bin_sources] + static_objs if strip: - stripped_bin = bin + '.stripped' + unstripped_exe = exename + '.unstripped' + new_env.Program(unstripped_exe, objects) if sys.platform == 'sunos5': cmd = 'cp $SOURCE $TARGET; strip $TARGET' else: cmd = 'strip $SOURCE -o $TARGET' - newEnv.Command(stripped_bin, bin, cmd) - bin = stripped_bin - targets = newEnv.Concat(exe, [bin, 'm5py.zip']) - newEnv.M5Binary = targets[0] - envList.append(newEnv) + targets = new_env.Command(exename, unstripped_exe, cmd) + else: + targets = new_env.Program(exename, objects) + + new_env.M5Binary = targets[0] + envList.append(new_env) # Debug binary ccflags = {} diff --git a/src/arch/SConscript b/src/arch/SConscript index 66f93870e..b85ffbd89 100644 --- a/src/arch/SConscript +++ b/src/arch/SConscript @@ -49,13 +49,13 @@ isa_switch_hdrs = Split(''' isa_traits.hh kernel_stats.hh locked_mem.hh + microcode_rom.hh mmaped_ipr.hh process.hh predecoder.hh regfile.hh remote_gdb.hh stacktrace.hh - syscallreturn.hh tlb.hh types.hh utility.hh @@ -125,3 +125,8 @@ else: emitter = isa_desc_emitter) env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder }) + +TraceFlag('IntRegs') +TraceFlag('FloatRegs') +TraceFlag('MiscRegs') +CompoundFlag('Registers', [ 'IntRegs', 'FloatRegs', 'MiscRegs' ]) diff --git a/src/arch/alpha/AlphaInterrupts.py b/src/arch/alpha/AlphaInterrupts.py new file mode 100644 index 000000000..ecfcf5c21 --- /dev/null +++ b/src/arch/alpha/AlphaInterrupts.py @@ -0,0 +1,33 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject + +class AlphaInterrupts(SimObject): + type = 'AlphaInterrupts' + cxx_class = 'AlphaISA::Interrupts' diff --git a/src/arch/alpha/AlphaTLB.py b/src/arch/alpha/AlphaTLB.py index fec245b75..099327470 100644 --- a/src/arch/alpha/AlphaTLB.py +++ b/src/arch/alpha/AlphaTLB.py @@ -28,21 +28,20 @@ from m5.SimObject import SimObject from m5.params import * -class AlphaTLB(SimObject): + +from BaseTLB import BaseTLB + +class AlphaTLB(BaseTLB): type = 'AlphaTLB' abstract = True size = Param.Int("TLB size") class AlphaDTB(AlphaTLB): type = 'AlphaDTB' - cxx_namespace = 'AlphaISA' - cxx_class = 'DTB' - + cxx_class = 'AlphaISA::DTB' size = 64 class AlphaITB(AlphaTLB): type = 'AlphaITB' - cxx_namespace = 'AlphaISA' - cxx_class = 'ITB' - + cxx_class = 'AlphaISA::ITB' size = 48 diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript index 04bac3996..069db2551 100644 --- a/src/arch/alpha/SConscript +++ b/src/arch/alpha/SConscript @@ -47,9 +47,11 @@ if env['TARGET_ISA'] == 'alpha': SimObject('AlphaTLB.py') if env['FULL_SYSTEM']: + SimObject('AlphaInterrupts.py') SimObject('AlphaSystem.py') Source('idle_event.cc') + Source('interrupts.cc') Source('kernel_stats.cc') Source('osfpal.cc') Source('stacktrace.cc') diff --git a/src/arch/alpha/SConsopts b/src/arch/alpha/SConsopts index 633eeb06f..b418e27c8 100644 --- a/src/arch/alpha/SConsopts +++ b/src/arch/alpha/SConsopts @@ -33,5 +33,5 @@ Import('*') all_isa_list.append('alpha') # Alpha can be compiled with Turbolaser support instead of Tsunami -sticky_opts.Add(BoolOption('ALPHA_TLASER', +sticky_vars.Add(BoolVariable('ALPHA_TLASER', 'Model Alpha TurboLaser platform (vs. Tsunami)', False)) diff --git a/src/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h index 58991256a..bcf004d05 100644 --- a/src/arch/alpha/aout_machdep.h +++ b/src/arch/alpha/aout_machdep.h @@ -36,35 +36,35 @@ /// Funky Alpha 64-bit a.out header used for PAL code. /// struct aout_exechdr { - uint16_t magic; ///< magic number - uint16_t vstamp; ///< version stamp? - uint16_t bldrev; ///< ??? - uint16_t padcell; ///< padding - uint64_t tsize; ///< text segment size - uint64_t dsize; ///< data segment size - uint64_t bsize; ///< bss segment size - uint64_t entry; ///< entry point - uint64_t text_start; ///< text base address - uint64_t data_start; ///< data base address - uint64_t bss_start; ///< bss base address - uint32_t gprmask; ///< GPR mask (unused, AFAIK) - uint32_t fprmask; ///< FPR mask (unused, AFAIK) - uint64_t gp_value; ///< global pointer reg value + uint16_t magic; ///< magic number + uint16_t vstamp; ///< version stamp? + uint16_t bldrev; ///< ??? + uint16_t padcell; ///< padding + uint64_t tsize; ///< text segment size + uint64_t dsize; ///< data segment size + uint64_t bsize; ///< bss segment size + uint64_t entry; ///< entry point + uint64_t text_start; ///< text base address + uint64_t data_start; ///< data base address + uint64_t bss_start; ///< bss base address + uint32_t gprmask; ///< GPR mask (unused, AFAIK) + uint32_t fprmask; ///< FPR mask (unused, AFAIK) + uint64_t gp_value; ///< global pointer reg value }; -#define AOUT_LDPGSZ 8192 +#define AOUT_LDPGSZ 8192 -#define N_GETMAGIC(ex) ((ex).magic) +#define N_GETMAGIC(ex) ((ex).magic) #define N_BADMAX -#define N_TXTADDR(ex) ((ex).text_start) -#define N_DATADDR(ex) ((ex).data_start) -#define N_BSSADDR(ex) ((ex).bss_start) +#define N_TXTADDR(ex) ((ex).text_start) +#define N_DATADDR(ex) ((ex).data_start) +#define N_BSSADDR(ex) ((ex).bss_start) -#define N_TXTOFF(ex) \ +#define N_TXTOFF(ex) \ (N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr)) -#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize) +#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize) #endif /* !__AOUT_MACHDEP_H__*/ diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc index 5dc49623e..02497e282 100644 --- a/src/arch/alpha/ev5.cc +++ b/src/arch/alpha/ev5.cc @@ -35,32 +35,33 @@ #include "arch/alpha/osfpal.hh" #include "arch/alpha/tlb.hh" #include "arch/alpha/kgdb.h" +#include "base/cp_annotate.hh" +#include "base/debug.hh" #include "base/remote_gdb.hh" #include "base/stats/events.hh" #include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" -#include "sim/debug.hh" #include "sim/sim_exit.hh" -#if FULL_SYSTEM +namespace AlphaISA { -using namespace EV5; +#if FULL_SYSTEM //////////////////////////////////////////////////////////////////////// // // Machine dependent functions // void -AlphaISA::initCPU(ThreadContext *tc, int cpuId) +initCPU(ThreadContext *tc, int cpuId) { initIPRs(tc, cpuId); tc->setIntReg(16, cpuId); tc->setIntReg(0, cpuId); - AlphaISA::AlphaFault *reset = new AlphaISA::ResetFault; + AlphaFault *reset = new ResetFault; tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + reset->vect()); tc->setNextPC(tc->readPC() + sizeof(MachInst)); @@ -71,7 +72,7 @@ AlphaISA::initCPU(ThreadContext *tc, int cpuId) template <class CPU> void -AlphaISA::processInterrupts(CPU *cpu) +processInterrupts(CPU *cpu) { //Check if there are any outstanding interrupts //Handle the interrupts @@ -117,7 +118,7 @@ AlphaISA::processInterrupts(CPU *cpu) template <class CPU> void -AlphaISA::zeroRegisters(CPU *cpu) +zeroRegisters(CPU *cpu) { // Insure ISA semantics // (no longer very clean due to the change in setIntReg() in the @@ -126,33 +127,16 @@ AlphaISA::zeroRegisters(CPU *cpu) cpu->thread->setFloatReg(ZeroReg, 0.0); } -Fault -SimpleThread::hwrei() -{ - if (!(readPC() & 0x3)) - return new UnimplementedOpcodeFault; - - setNextPC(readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR)); - - if (!misspeculating()) { - if (kernelStats) - kernelStats->hwrei(); - } - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - int -AlphaISA::MiscRegFile::getInstAsid() +MiscRegFile::getInstAsid() { - return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); + return ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } int -AlphaISA::MiscRegFile::getDataAsid() +MiscRegFile::getDataAsid() { - return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); + return DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } #endif @@ -162,90 +146,90 @@ AlphaISA::MiscRegFile::getDataAsid() // // void -AlphaISA::initIPRs(ThreadContext *tc, int cpuId) +initIPRs(ThreadContext *tc, int cpuId) { for (int i = 0; i < NumInternalProcRegs; ++i) { tc->setMiscRegNoEffect(i, 0); } - tc->setMiscRegNoEffect(IPR_PAL_BASE, EV5::PalBase); + tc->setMiscRegNoEffect(IPR_PAL_BASE, PalBase); tc->setMiscRegNoEffect(IPR_MCSR, 0x6); tc->setMiscRegNoEffect(IPR_PALtemp16, cpuId); } -AlphaISA::MiscReg -AlphaISA::MiscRegFile::readIpr(int idx, ThreadContext *tc) +MiscReg +MiscRegFile::readIpr(int idx, ThreadContext *tc) { - uint64_t retval = 0; // return value, default 0 + uint64_t retval = 0; // return value, default 0 switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PALtemp23: - case AlphaISA::IPR_PAL_BASE: - - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: - case AlphaISA::IPR_ISR: - case AlphaISA::IPR_EXC_ADDR: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_MCSR: - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: - case AlphaISA::IPR_SIRR: - case AlphaISA::IPR_ICSR: - case AlphaISA::IPR_ICM: - case AlphaISA::IPR_DTB_CM: - case AlphaISA::IPR_IPLR: - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_PMCTR: + case IPR_PALtemp0: + case IPR_PALtemp1: + case IPR_PALtemp2: + case IPR_PALtemp3: + case IPR_PALtemp4: + case IPR_PALtemp5: + case IPR_PALtemp6: + case IPR_PALtemp7: + case IPR_PALtemp8: + case IPR_PALtemp9: + case IPR_PALtemp10: + case IPR_PALtemp11: + case IPR_PALtemp12: + case IPR_PALtemp13: + case IPR_PALtemp14: + case IPR_PALtemp15: + case IPR_PALtemp16: + case IPR_PALtemp17: + case IPR_PALtemp18: + case IPR_PALtemp19: + case IPR_PALtemp20: + case IPR_PALtemp21: + case IPR_PALtemp22: + case IPR_PALtemp23: + case IPR_PAL_BASE: + + case IPR_IVPTBR: + case IPR_DC_MODE: + case IPR_MAF_MODE: + case IPR_ISR: + case IPR_EXC_ADDR: + case IPR_IC_PERR_STAT: + case IPR_DC_PERR_STAT: + case IPR_MCSR: + case IPR_ASTRR: + case IPR_ASTER: + case IPR_SIRR: + case IPR_ICSR: + case IPR_ICM: + case IPR_DTB_CM: + case IPR_IPLR: + case IPR_INTID: + case IPR_PMCTR: // no side-effect retval = ipr[idx]; break; - case AlphaISA::IPR_CC: + case IPR_CC: retval |= ipr[idx] & ULL(0xffffffff00000000); retval |= tc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff); break; - case AlphaISA::IPR_VA: + case IPR_VA: retval = ipr[idx]; break; - case AlphaISA::IPR_VA_FORM: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_IFAULT_VA_FORM: - case AlphaISA::IPR_EXC_MASK: - case AlphaISA::IPR_EXC_SUM: + case IPR_VA_FORM: + case IPR_MM_STAT: + case IPR_IFAULT_VA_FORM: + case IPR_EXC_MASK: + case IPR_EXC_SUM: retval = ipr[idx]; break; - case AlphaISA::IPR_DTB_PTE: + case IPR_DTB_PTE: { - AlphaISA::TlbEntry &entry + TlbEntry &entry = tc->getDTBPtr()->index(!tc->misspeculating()); retval |= ((uint64_t)entry.ppn & ULL(0x7ffffff)) << 32; @@ -259,15 +243,15 @@ AlphaISA::MiscRegFile::readIpr(int idx, ThreadContext *tc) break; // write only registers - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: - case AlphaISA::IPR_ALT_MODE: - case AlphaISA::IPR_DTB_IA: - case AlphaISA::IPR_DTB_IAP: - case AlphaISA::IPR_ITB_IA: - case AlphaISA::IPR_ITB_IAP: + case IPR_HWINT_CLR: + case IPR_SL_XMIT: + case IPR_DC_FLUSH: + case IPR_IC_FLUSH: + case IPR_ALT_MODE: + case IPR_DTB_IA: + case IPR_DTB_IAP: + case IPR_ITB_IA: + case IPR_ITB_IAP: panic("Tried to read write only register %d\n", idx); break; @@ -286,7 +270,7 @@ int break_ipl = -1; #endif void -AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) +MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) { uint64_t old; @@ -294,52 +278,52 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) return; switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PAL_BASE: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_PMCTR: + case IPR_PALtemp0: + case IPR_PALtemp1: + case IPR_PALtemp2: + case IPR_PALtemp3: + case IPR_PALtemp4: + case IPR_PALtemp5: + case IPR_PALtemp6: + case IPR_PALtemp7: + case IPR_PALtemp8: + case IPR_PALtemp9: + case IPR_PALtemp10: + case IPR_PALtemp11: + case IPR_PALtemp12: + case IPR_PALtemp13: + case IPR_PALtemp14: + case IPR_PALtemp15: + case IPR_PALtemp16: + case IPR_PALtemp17: + case IPR_PALtemp18: + case IPR_PALtemp19: + case IPR_PALtemp20: + case IPR_PALtemp21: + case IPR_PALtemp22: + case IPR_PAL_BASE: + case IPR_IC_PERR_STAT: + case IPR_DC_PERR_STAT: + case IPR_PMCTR: // write entire quad w/ no side-effect ipr[idx] = val; break; - case AlphaISA::IPR_CC_CTL: + case IPR_CC_CTL: // This IPR resets the cycle counter. We assume this only // happens once... let's verify that. assert(ipr[idx] == 0); ipr[idx] = 1; break; - case AlphaISA::IPR_CC: + case IPR_CC: // This IPR only writes the upper 64 bits. It's ok to write // all 64 here since we mask out the lower 32 in rpcc (see // isa_desc). ipr[idx] = val; break; - case AlphaISA::IPR_PALtemp23: + case IPR_PALtemp23: // write entire quad w/ no side-effect old = ipr[idx]; ipr[idx] = val; @@ -349,23 +333,23 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) #endif break; - case AlphaISA::IPR_DTB_PTE: + case IPR_DTB_PTE: // write entire quad w/ no side-effect, tag is forthcoming ipr[idx] = val; break; - case AlphaISA::IPR_EXC_ADDR: + case IPR_EXC_ADDR: // second least significant bit in PC is always zero ipr[idx] = val & ~2; break; - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: + case IPR_ASTRR: + case IPR_ASTER: // only write least significant four bits - privilege mask ipr[idx] = val & 0xf; break; - case AlphaISA::IPR_IPLR: + case IPR_IPLR: #ifdef DEBUG if (break_ipl != -1 && break_ipl == (val & 0x1f)) debug_break(); @@ -379,175 +363,173 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) #endif break; - case AlphaISA::IPR_DTB_CM: + case IPR_DTB_CM: #if FULL_SYSTEM if (val & 0x18) { if (tc->getKernelStats()) - tc->getKernelStats()->mode(TheISA::Kernel::user, tc); + tc->getKernelStats()->mode(Kernel::user, tc); } else { if (tc->getKernelStats()) - tc->getKernelStats()->mode(TheISA::Kernel::kernel, tc); + tc->getKernelStats()->mode(Kernel::kernel, tc); } #endif - case AlphaISA::IPR_ICM: + case IPR_ICM: // only write two mode bits - processor mode ipr[idx] = val & 0x18; break; - case AlphaISA::IPR_ALT_MODE: + case IPR_ALT_MODE: // only write two mode bits - processor mode ipr[idx] = val & 0x18; break; - case AlphaISA::IPR_MCSR: + case IPR_MCSR: // more here after optimization... ipr[idx] = val; break; - case AlphaISA::IPR_SIRR: + case IPR_SIRR: // only write software interrupt mask ipr[idx] = val & 0x7fff0; break; - case AlphaISA::IPR_ICSR: + case IPR_ICSR: ipr[idx] = val & ULL(0xffffff0300); break; - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_MVPTBR: + case IPR_IVPTBR: + case IPR_MVPTBR: ipr[idx] = val & ULL(0xffffffffc0000000); break; - case AlphaISA::IPR_DC_TEST_CTL: + case IPR_DC_TEST_CTL: ipr[idx] = val & 0x1ffb; break; - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: + case IPR_DC_MODE: + case IPR_MAF_MODE: ipr[idx] = val & 0x3f; break; - case AlphaISA::IPR_ITB_ASN: + case IPR_ITB_ASN: ipr[idx] = val & 0x7f0; break; - case AlphaISA::IPR_DTB_ASN: + case IPR_DTB_ASN: ipr[idx] = val & ULL(0xfe00000000000000); break; - case AlphaISA::IPR_EXC_SUM: - case AlphaISA::IPR_EXC_MASK: + case IPR_EXC_SUM: + case IPR_EXC_MASK: // any write to this register clears it ipr[idx] = 0; break; - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_SL_RCV: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_ITB_PTE_TEMP: - case AlphaISA::IPR_DTB_PTE_TEMP: + case IPR_INTID: + case IPR_SL_RCV: + case IPR_MM_STAT: + case IPR_ITB_PTE_TEMP: + case IPR_DTB_PTE_TEMP: // read-only registers panic("Tried to write read only ipr %d\n", idx); - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: + case IPR_HWINT_CLR: + case IPR_SL_XMIT: + case IPR_DC_FLUSH: + case IPR_IC_FLUSH: // the following are write only ipr[idx] = val; break; - case AlphaISA::IPR_DTB_IA: + case IPR_DTB_IA: // really a control write ipr[idx] = 0; tc->getDTBPtr()->flushAll(); break; - case AlphaISA::IPR_DTB_IAP: + case IPR_DTB_IAP: // really a control write ipr[idx] = 0; tc->getDTBPtr()->flushProcesses(); break; - case AlphaISA::IPR_DTB_IS: + case IPR_DTB_IS: // really a control write ipr[idx] = val; - tc->getDTBPtr()->flushAddr(val, - EV5::DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); + tc->getDTBPtr()->flushAddr(val, DTB_ASN_ASN(ipr[IPR_DTB_ASN])); break; - case AlphaISA::IPR_DTB_TAG: { - struct AlphaISA::TlbEntry entry; + case IPR_DTB_TAG: { + struct TlbEntry entry; // FIXME: granularity hints NYI... - if (EV5::DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0) + if (DTB_PTE_GH(ipr[IPR_DTB_PTE]) != 0) panic("PTE GH field != 0"); // write entire quad ipr[idx] = val; // construct PTE for new entry - entry.ppn = EV5::DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]); - entry.xre = EV5::DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]); - entry.xwe = EV5::DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]); - entry.fonr = EV5::DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]); - entry.fonw = EV5::DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]); - entry.asma = EV5::DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]); - entry.asn = EV5::DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]); + entry.ppn = DTB_PTE_PPN(ipr[IPR_DTB_PTE]); + entry.xre = DTB_PTE_XRE(ipr[IPR_DTB_PTE]); + entry.xwe = DTB_PTE_XWE(ipr[IPR_DTB_PTE]); + entry.fonr = DTB_PTE_FONR(ipr[IPR_DTB_PTE]); + entry.fonw = DTB_PTE_FONW(ipr[IPR_DTB_PTE]); + entry.asma = DTB_PTE_ASMA(ipr[IPR_DTB_PTE]); + entry.asn = DTB_ASN_ASN(ipr[IPR_DTB_ASN]); // insert new TAG/PTE value into data TLB tc->getDTBPtr()->insert(val, entry); } break; - case AlphaISA::IPR_ITB_PTE: { - struct AlphaISA::TlbEntry entry; + case IPR_ITB_PTE: { + struct TlbEntry entry; // FIXME: granularity hints NYI... - if (EV5::ITB_PTE_GH(val) != 0) + if (ITB_PTE_GH(val) != 0) panic("PTE GH field != 0"); // write entire quad ipr[idx] = val; // construct PTE for new entry - entry.ppn = EV5::ITB_PTE_PPN(val); - entry.xre = EV5::ITB_PTE_XRE(val); + entry.ppn = ITB_PTE_PPN(val); + entry.xre = ITB_PTE_XRE(val); entry.xwe = 0; - entry.fonr = EV5::ITB_PTE_FONR(val); - entry.fonw = EV5::ITB_PTE_FONW(val); - entry.asma = EV5::ITB_PTE_ASMA(val); - entry.asn = EV5::ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]); + entry.fonr = ITB_PTE_FONR(val); + entry.fonw = ITB_PTE_FONW(val); + entry.asma = ITB_PTE_ASMA(val); + entry.asn = ITB_ASN_ASN(ipr[IPR_ITB_ASN]); // insert new TAG/PTE value into data TLB - tc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], entry); + tc->getITBPtr()->insert(ipr[IPR_ITB_TAG], entry); } break; - case AlphaISA::IPR_ITB_IA: + case IPR_ITB_IA: // really a control write ipr[idx] = 0; tc->getITBPtr()->flushAll(); break; - case AlphaISA::IPR_ITB_IAP: + case IPR_ITB_IAP: // really a control write ipr[idx] = 0; tc->getITBPtr()->flushProcesses(); break; - case AlphaISA::IPR_ITB_IS: + case IPR_ITB_IS: // really a control write ipr[idx] = val; - tc->getITBPtr()->flushAddr(val, - EV5::ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN])); + tc->getITBPtr()->flushAddr(val, ITB_ASN_ASN(ipr[IPR_ITB_ASN])); break; default: @@ -558,17 +540,38 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) // no error... } - void -AlphaISA::copyIprs(ThreadContext *src, ThreadContext *dest) +copyIprs(ThreadContext *src, ThreadContext *dest) { - for (int i = 0; i < NumInternalProcRegs; ++i) { + for (int i = 0; i < NumInternalProcRegs; ++i) dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i)); - } } +} // namespace AlphaISA + #if FULL_SYSTEM +using namespace AlphaISA; + +Fault +SimpleThread::hwrei() +{ + if (!(readPC() & 0x3)) + return new UnimplementedOpcodeFault; + + setNextPC(readMiscRegNoEffect(IPR_EXC_ADDR)); + + CPA::cpa()->swAutoBegin(tc, readNextPC()); + + if (!misspeculating()) { + if (kernelStats) + kernelStats->hwrei(); + } + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + /** * Check for special simulator handling of specific PAL calls. * If return value is false, actual PAL call will be suppressed. diff --git a/src/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh index 4dd225786..1915d822b 100644 --- a/src/arch/alpha/ev5.hh +++ b/src/arch/alpha/ev5.hh @@ -36,10 +36,7 @@ #include "config/alpha_tlaser.hh" #include "arch/alpha/isa_traits.hh" -namespace EV5 { - -//It seems like a safe assumption EV5 only applies to alpha -using namespace AlphaISA; +namespace AlphaISA { #if ALPHA_TLASER const uint64_t AsnMask = ULL(0x7f); @@ -51,8 +48,8 @@ const int VAddrImplBits = 43; const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1; const Addr VAddrUnImplMask = ~VAddrImplMask; inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; } -inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; } -inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; } +inline Addr VAddrVPN(Addr a) { return a >> PageShift; } +inline Addr VAddrOffset(Addr a) { return a & PageOffset; } inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; } inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; } @@ -68,7 +65,9 @@ const Addr PAddrUncachedBit39 = ULL(0x8000000000); const Addr PAddrUncachedBit40 = ULL(0x10000000000); const Addr PAddrUncachedBit43 = ULL(0x80000000000); const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35> -inline Addr Phys2K0Seg(Addr addr) + +inline Addr +Phys2K0Seg(Addr addr) { #if !ALPHA_TLASER if (addr & PAddrUncachedBit43) { @@ -76,12 +75,12 @@ inline Addr Phys2K0Seg(Addr addr) addr |= PAddrUncachedBit40; } #endif - return addr | AlphaISA::K0SegBase; + return addr | K0SegBase; } inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; } inline Addr DTB_PTE_PPN(uint64_t reg) -{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +{ return reg >> 32 & ((ULL(1) << (PAddrImplBits - PageShift)) - 1); } inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; } inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } @@ -91,7 +90,7 @@ inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; } inline Addr ITB_PTE_PPN(uint64_t reg) -{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +{ return reg >> 32 & ((ULL(1) << (PAddrImplBits - PageShift)) - 1); } inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } @@ -114,12 +113,12 @@ const uint64_t MM_STAT_FONW_MASK = ULL(0x0008); const uint64_t MM_STAT_FONR_MASK = ULL(0x0004); const uint64_t MM_STAT_ACV_MASK = ULL(0x0002); const uint64_t MM_STAT_WR_MASK = ULL(0x0001); -inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; } -inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; } +inline int Opcode(MachInst inst) { return inst >> 26 & 0x3f; } +inline int Ra(MachInst inst) { return inst >> 21 & 0x1f; } const Addr PalBase = 0x4000; const Addr PalMax = 0x10000; -/* namespace EV5 */ } +} // namespace AlphaISA #endif // __ARCH_ALPHA_EV5_HH__ diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc index 20591b357..e93e16711 100644 --- a/src/arch/alpha/faults.cc +++ b/src/arch/alpha/faults.cc @@ -40,8 +40,7 @@ #include "mem/page_table.hh" #endif -namespace AlphaISA -{ +namespace AlphaISA { FaultName MachineCheckFault::_name = "mchk"; FaultVect MachineCheckFault::_vect = 0x0401; @@ -109,64 +108,67 @@ FaultStat IntegerOverflowFault::_count; #if FULL_SYSTEM -void AlphaFault::invoke(ThreadContext * tc) +void +AlphaFault::invoke(ThreadContext *tc) { FaultBase::invoke(tc); countStat()++; // exception restart address if (setRestartAddress() || !(tc->readPC() & 0x3)) - tc->setMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, tc->readPC()); + tc->setMiscRegNoEffect(IPR_EXC_ADDR, tc->readPC()); if (skipFaultingInstruction()) { // traps... skip faulting instruction. - tc->setMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, - tc->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR) + 4); + tc->setMiscRegNoEffect(IPR_EXC_ADDR, + tc->readMiscRegNoEffect(IPR_EXC_ADDR) + 4); } - tc->setPC(tc->readMiscRegNoEffect(AlphaISA::IPR_PAL_BASE) + vect()); + tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + vect()); tc->setNextPC(tc->readPC() + sizeof(MachInst)); } -void ArithmeticFault::invoke(ThreadContext * tc) +void +ArithmeticFault::invoke(ThreadContext *tc) { FaultBase::invoke(tc); panic("Arithmetic traps are unimplemented!"); } -void DtbFault::invoke(ThreadContext * tc) +void +DtbFault::invoke(ThreadContext *tc) { // Set fault address and flags. Even though we're modeling an // EV5, we use the EV6 technique of not latching fault registers // on VPTE loads (instead of locking the registers until IPR_VA is // read, like the EV5). The EV6 approach is cleaner and seems to // work with EV5 PAL code, but not the other way around. - if (!tc->misspeculating() - && !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) { + if (!tc->misspeculating() && + reqFlags.noneSet(Request::VPTE|Request::NO_FAULT)) { // set VA register with faulting address - tc->setMiscRegNoEffect(AlphaISA::IPR_VA, vaddr); + tc->setMiscRegNoEffect(IPR_VA, vaddr); // set MM_STAT register flags - tc->setMiscRegNoEffect(AlphaISA::IPR_MM_STAT, - (((EV5::Opcode(tc->getInst()) & 0x3f) << 11) - | ((EV5::Ra(tc->getInst()) & 0x1f) << 6) - | (flags & 0x3f))); + tc->setMiscRegNoEffect(IPR_MM_STAT, + (((Opcode(tc->getInst()) & 0x3f) << 11) | + ((Ra(tc->getInst()) & 0x1f) << 6) | + (flags & 0x3f))); // set VA_FORM register with faulting formatted address - tc->setMiscRegNoEffect(AlphaISA::IPR_VA_FORM, - tc->readMiscRegNoEffect(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3)); + tc->setMiscRegNoEffect(IPR_VA_FORM, + tc->readMiscRegNoEffect(IPR_MVPTBR) | (vaddr.vpn() << 3)); } AlphaFault::invoke(tc); } -void ItbFault::invoke(ThreadContext * tc) +void +ItbFault::invoke(ThreadContext *tc) { if (!tc->misspeculating()) { - tc->setMiscRegNoEffect(AlphaISA::IPR_ITB_TAG, pc); - tc->setMiscRegNoEffect(AlphaISA::IPR_IFAULT_VA_FORM, - tc->readMiscRegNoEffect(AlphaISA::IPR_IVPTBR) | - (AlphaISA::VAddr(pc).vpn() << 3)); + tc->setMiscRegNoEffect(IPR_ITB_TAG, pc); + tc->setMiscRegNoEffect(IPR_IFAULT_VA_FORM, + tc->readMiscRegNoEffect(IPR_IVPTBR) | (VAddr(pc).vpn() << 3)); } AlphaFault::invoke(tc); @@ -174,12 +176,13 @@ void ItbFault::invoke(ThreadContext * tc) #else -void ItbPageFault::invoke(ThreadContext * tc) +void +ItbPageFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); TlbEntry entry; bool success = p->pTable->lookup(pc, entry); - if(!success) { + if (!success) { panic("Tried to execute unmapped address %#x.\n", pc); } else { VAddr vaddr(pc); @@ -187,16 +190,17 @@ void ItbPageFault::invoke(ThreadContext * tc) } } -void NDtbMissFault::invoke(ThreadContext * tc) +void +NDtbMissFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); TlbEntry entry; bool success = p->pTable->lookup(vaddr, entry); - if(!success) { + if (!success) { p->checkAndAllocNextPage(vaddr); success = p->pTable->lookup(vaddr, entry); } - if(!success) { + if (!success) { panic("Tried to access unmapped address %#x.\n", (Addr)vaddr); } else { tc->getDTBPtr()->insert(vaddr.page(), entry); diff --git a/src/arch/alpha/faults.hh b/src/arch/alpha/faults.hh index 74699b2b5..9d90c7719 100644 --- a/src/arch/alpha/faults.hh +++ b/src/arch/alpha/faults.hh @@ -29,18 +29,16 @@ * Kevin Lim */ -#ifndef __ALPHA_FAULTS_HH__ -#define __ALPHA_FAULTS_HH__ +#ifndef __ARCH_ALPHA_FAULTS_HH__ +#define __ARCH_ALPHA_FAULTS_HH__ +#include "arch/alpha/pagetable.hh" #include "config/full_system.hh" #include "sim/faults.hh" -#include "arch/alpha/pagetable.hh" - // The design of the "name" and "vect" functions is in sim/faults.hh -namespace AlphaISA -{ +namespace AlphaISA { typedef const Addr FaultVect; @@ -63,6 +61,7 @@ class MachineCheckFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -76,6 +75,7 @@ class AlignmentFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -94,6 +94,7 @@ class ResetFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -102,12 +103,14 @@ class ResetFault : public AlphaFault class ArithmeticFault : public AlphaFault { - protected: - bool skipFaultingInstruction() {return true;} private: static FaultName _name; static FaultVect _vect; static FaultStat _count; + + protected: + bool skipFaultingInstruction() {return true;} + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -119,12 +122,14 @@ class ArithmeticFault : public AlphaFault class InterruptFault : public AlphaFault { - protected: - bool setRestartAddress() {return false;} private: static FaultName _name; static FaultVect _vect; static FaultStat _count; + + protected: + bool setRestartAddress() {return false;} + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -134,11 +139,12 @@ class InterruptFault : public AlphaFault class DtbFault : public AlphaFault { protected: - AlphaISA::VAddr vaddr; - uint32_t reqFlags; + VAddr vaddr; + Request::Flags reqFlags; uint64_t flags; + public: - DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags) + DtbFault(VAddr _vaddr, Request::Flags _reqFlags, uint64_t _flags) : vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags) { } FaultName name() const = 0; @@ -155,8 +161,9 @@ class NDtbMissFault : public DtbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + NDtbMissFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags) : DtbFault(vaddr, reqFlags, flags) { } FaultName name() const {return _name;} @@ -173,8 +180,9 @@ class PDtbMissFault : public DtbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + PDtbMissFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags) : DtbFault(vaddr, reqFlags, flags) { } FaultName name() const {return _name;} @@ -188,8 +196,9 @@ class DtbPageFault : public DtbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + DtbPageFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags) : DtbFault(vaddr, reqFlags, flags) { } FaultName name() const {return _name;} @@ -203,8 +212,9 @@ class DtbAcvFault : public DtbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + DtbAcvFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags) : DtbFault(vaddr, reqFlags, flags) { } FaultName name() const {return _name;} @@ -218,8 +228,9 @@ class DtbAlignmentFault : public DtbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + DtbAlignmentFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags) : DtbFault(vaddr, reqFlags, flags) { } FaultName name() const {return _name;} @@ -231,10 +242,9 @@ class ItbFault : public AlphaFault { protected: Addr pc; + public: - ItbFault(Addr _pc) - : pc(_pc) - { } + ItbFault(Addr _pc) : pc(_pc) { } FaultName name() const = 0; FaultVect vect() = 0; FaultStat & countStat() = 0; @@ -249,10 +259,9 @@ class ItbPageFault : public ItbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - ItbPageFault(Addr pc) - : ItbFault(pc) - { } + ItbPageFault(Addr pc) : ItbFault(pc) { } FaultName name() const {return _name;} FaultVect vect() {return _vect;} FaultStat & countStat() {return _count;} @@ -267,10 +276,9 @@ class ItbAcvFault : public ItbFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: - ItbAcvFault(Addr pc) - : ItbFault(pc) - { } + ItbAcvFault(Addr pc) : ItbFault(pc) { } FaultName name() const {return _name;} FaultVect vect() {return _vect;} FaultStat & countStat() {return _count;} @@ -282,6 +290,7 @@ class UnimplementedOpcodeFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -294,6 +303,7 @@ class FloatEnableFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -302,12 +312,14 @@ class FloatEnableFault : public AlphaFault class PalFault : public AlphaFault { - protected: - bool skipFaultingInstruction() {return true;} private: static FaultName _name; static FaultVect _vect; static FaultStat _count; + + protected: + bool skipFaultingInstruction() {return true;} + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} @@ -320,12 +332,13 @@ class IntegerOverflowFault : public AlphaFault static FaultName _name; static FaultVect _vect; static FaultStat _count; + public: FaultName name() const {return _name;} FaultVect vect() {return _vect;} FaultStat & countStat() {return _count;} }; -} // AlphaISA namespace +} // namespace AlphaISA -#endif // __FAULTS_HH__ +#endif // __ARCH_ALPHA_FAULTS_HH__ diff --git a/src/arch/alpha/floatregfile.cc b/src/arch/alpha/floatregfile.cc index 512b0df95..192b0f1d4 100644 --- a/src/arch/alpha/floatregfile.cc +++ b/src/arch/alpha/floatregfile.cc @@ -30,20 +30,28 @@ * Kevin Lim */ +#include <cstring> + #include "arch/alpha/floatregfile.hh" #include "sim/serialize.hh" -namespace AlphaISA +namespace AlphaISA { +void +FloatRegFile::clear() { - void - FloatRegFile::serialize(std::ostream &os) - { - SERIALIZE_ARRAY(q, NumFloatRegs); - } + std::memset(d, 0, sizeof(d)); +} - void - FloatRegFile::unserialize(Checkpoint *cp, const std::string §ion) - { - UNSERIALIZE_ARRAY(q, NumFloatRegs); - } +void +FloatRegFile::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(q, NumFloatRegs); } + +void +FloatRegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(q, NumFloatRegs); +} + +} // namespace AlphaISA diff --git a/src/arch/alpha/floatregfile.hh b/src/arch/alpha/floatregfile.hh index 0c5fe17a7..d5f9eec0f 100644 --- a/src/arch/alpha/floatregfile.hh +++ b/src/arch/alpha/floatregfile.hh @@ -32,37 +32,30 @@ #ifndef __ARCH_ALPHA_FLOATREGFILE_HH__ #define __ARCH_ALPHA_FLOATREGFILE_HH__ +#include <iosfwd> +#include <string> + #include "arch/alpha/isa_traits.hh" #include "arch/alpha/types.hh" -#include <cstring> -#include <iostream> - class Checkpoint; -namespace AlphaISA -{ - static inline std::string getFloatRegName(RegIndex) - { - return ""; - } - - class FloatRegFile - { - public: +namespace AlphaISA { - union { - uint64_t q[NumFloatRegs]; // integer qword view - double d[NumFloatRegs]; // double-precision floating point view - }; +class FloatRegFile +{ + public: + union { + uint64_t q[NumFloatRegs]; // integer qword view + double d[NumFloatRegs]; // double-precision floating point view + }; - void serialize(std::ostream &os); + void clear(); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); +}; - void clear() - { std::memset(d, 0, sizeof(d)); } - }; -} +} // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_FLOATREGFILE_HH__ diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc index f666de604..e541b260c 100644 --- a/src/arch/alpha/freebsd/system.cc +++ b/src/arch/alpha/freebsd/system.cc @@ -62,29 +62,25 @@ FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks"); } - FreebsdAlphaSystem::~FreebsdAlphaSystem() { delete skipDelayEvent; delete skipCalibrateClocks; } - void FreebsdAlphaSystem::doCalibrateClocks(ThreadContext *tc) { Addr ppc_vaddr = 0; Addr timer_vaddr = 0; - assert(NumArgumentRegs >= 3); - ppc_vaddr = (Addr)tc->readIntReg(ArgumentReg[1]); - timer_vaddr = (Addr)tc->readIntReg(ArgumentReg[2]); + ppc_vaddr = (Addr)tc->readIntReg(17); + timer_vaddr = (Addr)tc->readIntReg(18); virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency); virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY); } - void FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ThreadContext *tc) { diff --git a/src/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh index 8e8493f97..48f6238c0 100644 --- a/src/arch/alpha/freebsd/system.hh +++ b/src/arch/alpha/freebsd/system.hh @@ -57,7 +57,6 @@ class FreebsdAlphaSystem : public AlphaSystem ~FreebsdAlphaSystem(); void doCalibrateClocks(ThreadContext *tc); - }; #endif // __ARCH_ALPHA_FREEBSD_SYSTEM_HH__ diff --git a/src/arch/alpha/idle_event.cc b/src/arch/alpha/idle_event.cc index f0f1eab7a..bb68782e7 100644 --- a/src/arch/alpha/idle_event.cc +++ b/src/arch/alpha/idle_event.cc @@ -33,13 +33,14 @@ #include "arch/alpha/kernel_stats.hh" #include "cpu/thread_context.hh" -using namespace TheISA; +using namespace AlphaISA; void IdleStartEvent::process(ThreadContext *tc) { - if (tc->getKernelStats()) - tc->getKernelStats()->setIdleProcess( - tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23), tc); + if (tc->getKernelStats()) { + MiscReg val = tc->readMiscRegNoEffect(IPR_PALtemp23); + tc->getKernelStats()->setIdleProcess(val, tc); + } remove(); } diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/arch/alpha/interrupts.cc index d85aff502..4b5dc5661 100755..100644 --- a/src/cpu/o3/sparc/thread_context.cc +++ b/src/arch/alpha/interrupts.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,8 +28,10 @@ * Authors: Gabe Black */ -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" - -template class O3ThreadContext<SparcSimpleImpl>; +#include "arch/alpha/interrupts.hh" +AlphaISA::Interrupts * +AlphaInterruptsParams::create() +{ + return new AlphaISA::Interrupts(this); +} diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh index 6453edf97..f8e0ad4ef 100644 --- a/src/arch/alpha/interrupts.hh +++ b/src/arch/alpha/interrupts.hh @@ -35,142 +35,163 @@ #include "arch/alpha/faults.hh" #include "arch/alpha/isa_traits.hh" #include "base/compiler.hh" +#include "base/trace.hh" #include "cpu/thread_context.hh" +#include "params/AlphaInterrupts.hh" +#include "sim/sim_object.hh" -namespace AlphaISA +namespace AlphaISA { + +class Interrupts : public SimObject { - class Interrupts + private: + bool newInfoSet; + int newIpl; + int newSummary; + BaseCPU * cpu; + + protected: + uint64_t interrupts[NumInterruptLevels]; + uint64_t intstatus; + + public: + typedef AlphaInterruptsParams Params; + + const Params * + params() const { - protected: - uint64_t interrupts[NumInterruptLevels]; - uint64_t intstatus; - - public: - Interrupts() - { - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; - newInfoSet = false; - } + return dynamic_cast<const Params *>(_params); + } - void post(int int_num, int index) - { - DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + Interrupts(Params * p) : SimObject(p), cpu(NULL) + { + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; + newInfoSet = false; + } - if (int_num < 0 || int_num >= NumInterruptLevels) - panic("int_num out of bounds\n"); + void + setCPU(BaseCPU * _cpu) + { + cpu = _cpu; + } - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); + void + post(int int_num, int index) + { + DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); - interrupts[int_num] |= 1 << index; - intstatus |= (ULL(1) << int_num); - } + if (int_num < 0 || int_num >= NumInterruptLevels) + panic("int_num out of bounds\n"); - void clear(int int_num, int index) - { - DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); + if (index < 0 || index >= (int)sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); + interrupts[int_num] |= 1 << index; + intstatus |= (ULL(1) << int_num); + } - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); + void + clear(int int_num, int index) + { + DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); - interrupts[int_num] &= ~(1 << index); - if (interrupts[int_num] == 0) - intstatus &= ~(ULL(1) << int_num); - } + if (int_num < 0 || int_num >= NumInterruptLevels) + panic("int_num out of bounds\n"); - void clear_all() - { - DPRINTF(Interrupt, "Interrupts all cleared\n"); + if (index < 0 || index >= (int)sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; - } + interrupts[int_num] &= ~(1 << index); + if (interrupts[int_num] == 0) + intstatus &= ~(ULL(1) << int_num); + } - void serialize(std::ostream &os) - { - SERIALIZE_ARRAY(interrupts, NumInterruptLevels); - SERIALIZE_SCALAR(intstatus); - } + void + clearAll() + { + DPRINTF(Interrupt, "Interrupts all cleared\n"); - void unserialize(Checkpoint *cp, const std::string §ion) - { - UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); - UNSERIALIZE_SCALAR(intstatus); - } + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; + } - bool check_interrupts(ThreadContext * tc) const - { - return (intstatus != 0) && !(tc->readPC() & 0x3); - } + void + serialize(std::ostream &os) + { + SERIALIZE_ARRAY(interrupts, NumInterruptLevels); + SERIALIZE_SCALAR(intstatus); + } - Fault getInterrupt(ThreadContext * tc) - { - int ipl = 0; - int summary = 0; - - if (tc->readMiscRegNoEffect(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (tc->readMiscRegNoEffect(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (tc->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } + void + unserialize(Checkpoint *cp, const std::string §ion) + { + UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); + UNSERIALIZE_SCALAR(intstatus); + } + + bool + checkInterrupts(ThreadContext *tc) const + { + return (intstatus != 0) && !(tc->readPC() & 0x3); + } - uint64_t interrupts = intstatus; - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } + Fault + getInterrupt(ThreadContext *tc) + { + int ipl = 0; + int summary = 0; + + if (tc->readMiscRegNoEffect(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (tc->readMiscRegNoEffect(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (tc->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); } } + } - if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) { - newIpl = ipl; - newSummary = summary; - newInfoSet = true; - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary); - - return new InterruptFault; - } else { - return NoFault; + uint64_t interrupts = intstatus; + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } } } - void updateIntrInfo(ThreadContext *tc) - { - assert(newInfoSet); - tc->setMiscRegNoEffect(IPR_ISR, newSummary); - tc->setMiscRegNoEffect(IPR_INTID, newIpl); - newInfoSet = false; - } + if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) { + newIpl = ipl; + newSummary = summary; + newInfoSet = true; + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary); - uint64_t get_vec(int int_num) - { - panic("Shouldn't be called for Alpha\n"); - M5_DUMMY_RETURN + return new InterruptFault; + } else { + return NoFault; } + } + + void + updateIntrInfo(ThreadContext *tc) + { + assert(newInfoSet); + tc->setMiscRegNoEffect(IPR_ISR, newSummary); + tc->setMiscRegNoEffect(IPR_INTID, newIpl); + newInfoSet = false; + } +}; - private: - bool newInfoSet; - int newIpl; - int newSummary; - }; -} +} // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_INTERRUPT_HH__ diff --git a/src/arch/alpha/intregfile.cc b/src/arch/alpha/intregfile.cc index 0188cb2cd..8f692f856 100644 --- a/src/arch/alpha/intregfile.cc +++ b/src/arch/alpha/intregfile.cc @@ -30,36 +30,45 @@ * Kevin Lim */ +#include <cstring> + #include "arch/alpha/isa_traits.hh" #include "arch/alpha/intregfile.hh" #include "sim/serialize.hh" -namespace AlphaISA -{ +namespace AlphaISA { + #if FULL_SYSTEM - const int reg_redir[AlphaISA::NumIntRegs] = { - /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, - /* 8 */ 32, 33, 34, 35, 36, 37, 38, 15, - /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23, - /* 24 */ 24, 39, 26, 27, 28, 29, 30, 31 }; +const int reg_redir[NumIntRegs] = { + /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, + /* 8 */ 32, 33, 34, 35, 36, 37, 38, 15, + /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23, + /* 24 */ 24, 39, 26, 27, 28, 29, 30, 31 }; #else - const int reg_redir[AlphaISA::NumIntRegs] = { - /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, - /* 8 */ 8, 9, 10, 11, 12, 13, 14, 15, - /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23, - /* 24 */ 24, 25, 26, 27, 28, 29, 30, 31 }; +const int reg_redir[NumIntRegs] = { + /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, + /* 8 */ 8, 9, 10, 11, 12, 13, 14, 15, + /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23, + /* 24 */ 24, 25, 26, 27, 28, 29, 30, 31 }; #endif - void - IntRegFile::serialize(std::ostream &os) - { - SERIALIZE_ARRAY(regs, NumIntRegs); - } +void +IntRegFile::clear() +{ + std::memset(regs, 0, sizeof(regs)); +} + +void +IntRegFile::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(regs, NumIntRegs); +} - void - IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) - { - UNSERIALIZE_ARRAY(regs, NumIntRegs); - } +void +IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(regs, NumIntRegs); } +} // namespace AlphaISA + diff --git a/src/arch/alpha/intregfile.hh b/src/arch/alpha/intregfile.hh index dea160992..3aa7d92c4 100644 --- a/src/arch/alpha/intregfile.hh +++ b/src/arch/alpha/intregfile.hh @@ -32,47 +32,42 @@ #ifndef __ARCH_ALPHA_INTREGFILE_HH__ #define __ARCH_ALPHA_INTREGFILE_HH__ -#include "arch/alpha/types.hh" +#include <iosfwd> +#include <string> -#include <iostream> -#include <cstring> +#include "arch/alpha/types.hh" class Checkpoint; -namespace AlphaISA +namespace AlphaISA { + +// redirected register map, really only used for the full system case. +extern const int reg_redir[NumIntRegs]; + +class IntRegFile { - static inline std::string getIntRegName(RegIndex) + protected: + IntReg regs[NumIntRegs]; + + public: + IntReg + readReg(int intReg) { - return ""; + return regs[intReg]; } - // redirected register map, really only used for the full system case. - extern const int reg_redir[NumIntRegs]; - - class IntRegFile + void + setReg(int intReg, const IntReg &val) { - protected: - IntReg regs[NumIntRegs]; - - public: - - IntReg readReg(int intReg) - { - return regs[intReg]; - } - - void setReg(int intReg, const IntReg &val) - { - regs[intReg] = val; - } + regs[intReg] = val; + } - void serialize(std::ostream &os); + void clear(); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); +}; - void clear() - { std::memset(regs, 0, sizeof(regs)); } - }; -} +} // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_INTREGFILE_HH__ diff --git a/src/arch/alpha/ipr.cc b/src/arch/alpha/ipr.cc index 8e83102eb..502ada5eb 100644 --- a/src/arch/alpha/ipr.cc +++ b/src/arch/alpha/ipr.cc @@ -28,113 +28,115 @@ * Authors: Gabe Black */ -#include <assert.h> -#include <string.h> +#include <cassert> +#include <cstring> #include "arch/alpha/ipr.hh" -namespace AlphaISA +namespace AlphaISA { + +md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs] = { + + //Write only + RAW_IPR_HWINT_CLR, // H/W interrupt clear register + RAW_IPR_SL_XMIT, // serial line transmit register + RAW_IPR_DC_FLUSH, + RAW_IPR_IC_FLUSH, // instruction cache flush control + RAW_IPR_ALT_MODE, // alternate mode register + RAW_IPR_DTB_IA, // DTLB invalidate all register + RAW_IPR_DTB_IAP, // DTLB invalidate all process register + RAW_IPR_ITB_IA, // ITLB invalidate all register + RAW_IPR_ITB_IAP, // ITLB invalidate all process register + + //Read only + RAW_IPR_INTID, // interrupt ID register + RAW_IPR_SL_RCV, // serial line receive register + RAW_IPR_MM_STAT, // data MMU fault status register + RAW_IPR_ITB_PTE_TEMP, // ITLB page table entry temp register + RAW_IPR_DTB_PTE_TEMP, // DTLB page table entry temporary register + + RAW_IPR_ISR, // interrupt summary register + RAW_IPR_ITB_TAG, // ITLB tag register + RAW_IPR_ITB_PTE, // ITLB page table entry register + RAW_IPR_ITB_ASN, // ITLB address space register + RAW_IPR_ITB_IS, // ITLB invalidate select register + RAW_IPR_SIRR, // software interrupt request register + RAW_IPR_ASTRR, // asynchronous system trap request register + RAW_IPR_ASTER, // asynchronous system trap enable register + RAW_IPR_EXC_ADDR, // exception address register + RAW_IPR_EXC_SUM, // exception summary register + RAW_IPR_EXC_MASK, // exception mask register + RAW_IPR_PAL_BASE, // PAL base address register + RAW_IPR_ICM, // instruction current mode + RAW_IPR_IPLR, // interrupt priority level register + RAW_IPR_IFAULT_VA_FORM, // formatted faulting virtual addr register + RAW_IPR_IVPTBR, // virtual page table base register + RAW_IPR_ICSR, // instruction control and status register + RAW_IPR_IC_PERR_STAT, // inst cache parity error status register + RAW_IPR_PMCTR, // performance counter register + + // PAL temporary registers... + // register meanings gleaned from osfpal.s source code + RAW_IPR_PALtemp0, // local scratch + RAW_IPR_PALtemp1, // local scratch + RAW_IPR_PALtemp2, // entUna + RAW_IPR_PALtemp3, // CPU specific impure area pointer + RAW_IPR_PALtemp4, // memory management temp + RAW_IPR_PALtemp5, // memory management temp + RAW_IPR_PALtemp6, // memory management temp + RAW_IPR_PALtemp7, // entIF + RAW_IPR_PALtemp8, // intmask + RAW_IPR_PALtemp9, // entSys + RAW_IPR_PALtemp10, // ?? + RAW_IPR_PALtemp11, // entInt + RAW_IPR_PALtemp12, // entArith + RAW_IPR_PALtemp13, // reserved for platform specific PAL + RAW_IPR_PALtemp14, // reserved for platform specific PAL + RAW_IPR_PALtemp15, // reserved for platform specific PAL + RAW_IPR_PALtemp16, // scratch / whami<7:0> / mces<4:0> + RAW_IPR_PALtemp17, // sysval + RAW_IPR_PALtemp18, // usp + RAW_IPR_PALtemp19, // ksp + RAW_IPR_PALtemp20, // PTBR + RAW_IPR_PALtemp21, // entMM + RAW_IPR_PALtemp22, // kgp + RAW_IPR_PALtemp23, // PCBB + + RAW_IPR_DTB_ASN, // DTLB address space number register + RAW_IPR_DTB_CM, // DTLB current mode register + RAW_IPR_DTB_TAG, // DTLB tag register + RAW_IPR_DTB_PTE, // DTLB page table entry register + + RAW_IPR_VA, // fault virtual address register + RAW_IPR_VA_FORM, // formatted virtual address register + RAW_IPR_MVPTBR, // MTU virtual page table base register + RAW_IPR_DTB_IS, // DTLB invalidate single register + RAW_IPR_CC, // cycle counter register + RAW_IPR_CC_CTL, // cycle counter control register + RAW_IPR_MCSR, // MTU control register + + RAW_IPR_DC_PERR_STAT, // Dcache parity error status register + RAW_IPR_DC_TEST_CTL, // Dcache test tag control register + RAW_IPR_DC_TEST_TAG, // Dcache test tag register + RAW_IPR_DC_TEST_TAG_TEMP, // Dcache test tag temporary register + RAW_IPR_DC_MODE, // Dcache mode register + RAW_IPR_MAF_MODE // miss address file mode register +}; + +int IprToMiscRegIndex[MaxInternalProcRegs]; + +void +initializeIprTable() { - md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs] = - { - //Write only - RAW_IPR_HWINT_CLR, // H/W interrupt clear register - RAW_IPR_SL_XMIT, // serial line transmit register - RAW_IPR_DC_FLUSH, - RAW_IPR_IC_FLUSH, // instruction cache flush control - RAW_IPR_ALT_MODE, // alternate mode register - RAW_IPR_DTB_IA, // DTLB invalidate all register - RAW_IPR_DTB_IAP, // DTLB invalidate all process register - RAW_IPR_ITB_IA, // ITLB invalidate all register - RAW_IPR_ITB_IAP, // ITLB invalidate all process register - - //Read only - RAW_IPR_INTID, // interrupt ID register - RAW_IPR_SL_RCV, // serial line receive register - RAW_IPR_MM_STAT, // data MMU fault status register - RAW_IPR_ITB_PTE_TEMP, // ITLB page table entry temp register - RAW_IPR_DTB_PTE_TEMP, // DTLB page table entry temporary register - - RAW_IPR_ISR, // interrupt summary register - RAW_IPR_ITB_TAG, // ITLB tag register - RAW_IPR_ITB_PTE, // ITLB page table entry register - RAW_IPR_ITB_ASN, // ITLB address space register - RAW_IPR_ITB_IS, // ITLB invalidate select register - RAW_IPR_SIRR, // software interrupt request register - RAW_IPR_ASTRR, // asynchronous system trap request register - RAW_IPR_ASTER, // asynchronous system trap enable register - RAW_IPR_EXC_ADDR, // exception address register - RAW_IPR_EXC_SUM, // exception summary register - RAW_IPR_EXC_MASK, // exception mask register - RAW_IPR_PAL_BASE, // PAL base address register - RAW_IPR_ICM, // instruction current mode - RAW_IPR_IPLR, // interrupt priority level register - RAW_IPR_IFAULT_VA_FORM, // formatted faulting virtual addr register - RAW_IPR_IVPTBR, // virtual page table base register - RAW_IPR_ICSR, // instruction control and status register - RAW_IPR_IC_PERR_STAT, // inst cache parity error status register - RAW_IPR_PMCTR, // performance counter register - - // PAL temporary registers... - // register meanings gleaned from osfpal.s source code - RAW_IPR_PALtemp0, // local scratch - RAW_IPR_PALtemp1, // local scratch - RAW_IPR_PALtemp2, // entUna - RAW_IPR_PALtemp3, // CPU specific impure area pointer - RAW_IPR_PALtemp4, // memory management temp - RAW_IPR_PALtemp5, // memory management temp - RAW_IPR_PALtemp6, // memory management temp - RAW_IPR_PALtemp7, // entIF - RAW_IPR_PALtemp8, // intmask - RAW_IPR_PALtemp9, // entSys - RAW_IPR_PALtemp10, // ?? - RAW_IPR_PALtemp11, // entInt - RAW_IPR_PALtemp12, // entArith - RAW_IPR_PALtemp13, // reserved for platform specific PAL - RAW_IPR_PALtemp14, // reserved for platform specific PAL - RAW_IPR_PALtemp15, // reserved for platform specific PAL - RAW_IPR_PALtemp16, // scratch / whami<7:0> / mces<4:0> - RAW_IPR_PALtemp17, // sysval - RAW_IPR_PALtemp18, // usp - RAW_IPR_PALtemp19, // ksp - RAW_IPR_PALtemp20, // PTBR - RAW_IPR_PALtemp21, // entMM - RAW_IPR_PALtemp22, // kgp - RAW_IPR_PALtemp23, // PCBB - - RAW_IPR_DTB_ASN, // DTLB address space number register - RAW_IPR_DTB_CM, // DTLB current mode register - RAW_IPR_DTB_TAG, // DTLB tag register - RAW_IPR_DTB_PTE, // DTLB page table entry register - - RAW_IPR_VA, // fault virtual address register - RAW_IPR_VA_FORM, // formatted virtual address register - RAW_IPR_MVPTBR, // MTU virtual page table base register - RAW_IPR_DTB_IS, // DTLB invalidate single register - RAW_IPR_CC, // cycle counter register - RAW_IPR_CC_CTL, // cycle counter control register - RAW_IPR_MCSR, // MTU control register - - RAW_IPR_DC_PERR_STAT, // Dcache parity error status register - RAW_IPR_DC_TEST_CTL, // Dcache test tag control register - RAW_IPR_DC_TEST_TAG, // Dcache test tag register - RAW_IPR_DC_TEST_TAG_TEMP, // Dcache test tag temporary register - RAW_IPR_DC_MODE, // Dcache mode register - RAW_IPR_MAF_MODE // miss address file mode register - }; - - int IprToMiscRegIndex[MaxInternalProcRegs]; - - void initializeIprTable() - { - static bool initialized = false; - if(initialized) - return; - - memset(IprToMiscRegIndex, -1, MaxInternalProcRegs * sizeof(int)); - - for(int x = 0; x < NumInternalProcRegs; x++) - IprToMiscRegIndex[MiscRegIndexToIpr[x]] = x; - } + static bool initialized = false; + if (initialized) + return; + + memset(IprToMiscRegIndex, -1, MaxInternalProcRegs * sizeof(int)); + + for (int x = 0; x < NumInternalProcRegs; x++) + IprToMiscRegIndex[MiscRegIndexToIpr[x]] = x; } +} // namespace AlphaISA + diff --git a/src/arch/alpha/ipr.hh b/src/arch/alpha/ipr.hh index b55154764..4e7bf1fa4 100644 --- a/src/arch/alpha/ipr.hh +++ b/src/arch/alpha/ipr.hh @@ -32,206 +32,208 @@ #ifndef __ARCH_ALPHA_IPR_HH__ #define __ARCH_ALPHA_IPR_HH__ -namespace AlphaISA +namespace AlphaISA { + +//////////////////////////////////////////////////////////////////////// +// +// Internal Processor Reigsters +// +enum md_ipr_names { + RAW_IPR_ISR = 0x100, // interrupt summary + RAW_IPR_ITB_TAG = 0x101, // ITLB tag + RAW_IPR_ITB_PTE = 0x102, // ITLB page table entry + RAW_IPR_ITB_ASN = 0x103, // ITLB address space + RAW_IPR_ITB_PTE_TEMP = 0x104, // ITLB page table entry temp + RAW_IPR_ITB_IA = 0x105, // ITLB invalidate all + RAW_IPR_ITB_IAP = 0x106, // ITLB invalidate all process + RAW_IPR_ITB_IS = 0x107, // ITLB invalidate select + RAW_IPR_SIRR = 0x108, // software interrupt request + RAW_IPR_ASTRR = 0x109, // asynchronous system trap request + RAW_IPR_ASTER = 0x10a, // asynchronous system trap enable + RAW_IPR_EXC_ADDR = 0x10b, // exception address + RAW_IPR_EXC_SUM = 0x10c, // exception summary + RAW_IPR_EXC_MASK = 0x10d, // exception mask + RAW_IPR_PAL_BASE = 0x10e, // PAL base address + RAW_IPR_ICM = 0x10f, // instruction current mode + RAW_IPR_IPLR = 0x110, // interrupt priority level + RAW_IPR_INTID = 0x111, // interrupt ID + RAW_IPR_IFAULT_VA_FORM = 0x112, // formatted faulting virtual addr + RAW_IPR_IVPTBR = 0x113, // virtual page table base + RAW_IPR_HWINT_CLR = 0x115, // H/W interrupt clear + RAW_IPR_SL_XMIT = 0x116, // serial line transmit + RAW_IPR_SL_RCV = 0x117, // serial line receive + RAW_IPR_ICSR = 0x118, // instruction control and status + RAW_IPR_IC_FLUSH = 0x119, // instruction cache flush control + RAW_IPR_IC_PERR_STAT = 0x11a, // inst cache parity error status + RAW_IPR_PMCTR = 0x11c, // performance counter + + // PAL temporary registers... + // register meanings gleaned from osfpal.s source code + RAW_IPR_PALtemp0 = 0x140, // local scratch + RAW_IPR_PALtemp1 = 0x141, // local scratch + RAW_IPR_PALtemp2 = 0x142, // entUna + RAW_IPR_PALtemp3 = 0x143, // CPU specific impure area pointer + RAW_IPR_PALtemp4 = 0x144, // memory management temp + RAW_IPR_PALtemp5 = 0x145, // memory management temp + RAW_IPR_PALtemp6 = 0x146, // memory management temp + RAW_IPR_PALtemp7 = 0x147, // entIF + RAW_IPR_PALtemp8 = 0x148, // intmask + RAW_IPR_PALtemp9 = 0x149, // entSys + RAW_IPR_PALtemp10 = 0x14a, // ?? + RAW_IPR_PALtemp11 = 0x14b, // entInt + RAW_IPR_PALtemp12 = 0x14c, // entArith + RAW_IPR_PALtemp13 = 0x14d, // reserved for platform specific PAL + RAW_IPR_PALtemp14 = 0x14e, // reserved for platform specific PAL + RAW_IPR_PALtemp15 = 0x14f, // reserved for platform specific PAL + RAW_IPR_PALtemp16 = 0x150, // scratch / whami<7:0> / mces<4:0> + RAW_IPR_PALtemp17 = 0x151, // sysval + RAW_IPR_PALtemp18 = 0x152, // usp + RAW_IPR_PALtemp19 = 0x153, // ksp + RAW_IPR_PALtemp20 = 0x154, // PTBR + RAW_IPR_PALtemp21 = 0x155, // entMM + RAW_IPR_PALtemp22 = 0x156, // kgp + RAW_IPR_PALtemp23 = 0x157, // PCBB + + RAW_IPR_DTB_ASN = 0x200, // DTLB address space number + RAW_IPR_DTB_CM = 0x201, // DTLB current mode + RAW_IPR_DTB_TAG = 0x202, // DTLB tag + RAW_IPR_DTB_PTE = 0x203, // DTLB page table entry + RAW_IPR_DTB_PTE_TEMP = 0x204, // DTLB page table entry temporary + + RAW_IPR_MM_STAT = 0x205, // data MMU fault status + RAW_IPR_VA = 0x206, // fault virtual address + RAW_IPR_VA_FORM = 0x207, // formatted virtual address + RAW_IPR_MVPTBR = 0x208, // MTU virtual page table base + RAW_IPR_DTB_IAP = 0x209, // DTLB invalidate all process + RAW_IPR_DTB_IA = 0x20a, // DTLB invalidate all + RAW_IPR_DTB_IS = 0x20b, // DTLB invalidate single + RAW_IPR_ALT_MODE = 0x20c, // alternate mode + RAW_IPR_CC = 0x20d, // cycle counter + RAW_IPR_CC_CTL = 0x20e, // cycle counter control + RAW_IPR_MCSR = 0x20f, // MTU control + + RAW_IPR_DC_FLUSH = 0x210, + RAW_IPR_DC_PERR_STAT = 0x212, // Dcache parity error status + RAW_IPR_DC_TEST_CTL = 0x213, // Dcache test tag control + RAW_IPR_DC_TEST_TAG = 0x214, // Dcache test tag + RAW_IPR_DC_TEST_TAG_TEMP = 0x215, // Dcache test tag temporary + RAW_IPR_DC_MODE = 0x216, // Dcache mode + RAW_IPR_MAF_MODE = 0x217, // miss address file mode + + MaxInternalProcRegs // number of IPRs +}; + +enum MiscRegIpr { - //////////////////////////////////////////////////////////////////////// - // - // Internal Processor Reigsters - // - enum md_ipr_names - { - RAW_IPR_ISR = 0x100, // interrupt summary register - RAW_IPR_ITB_TAG = 0x101, // ITLB tag register - RAW_IPR_ITB_PTE = 0x102, // ITLB page table entry register - RAW_IPR_ITB_ASN = 0x103, // ITLB address space register - RAW_IPR_ITB_PTE_TEMP = 0x104, // ITLB page table entry temp register - RAW_IPR_ITB_IA = 0x105, // ITLB invalidate all register - RAW_IPR_ITB_IAP = 0x106, // ITLB invalidate all process register - RAW_IPR_ITB_IS = 0x107, // ITLB invalidate select register - RAW_IPR_SIRR = 0x108, // software interrupt request register - RAW_IPR_ASTRR = 0x109, // asynchronous system trap request register - RAW_IPR_ASTER = 0x10a, // asynchronous system trap enable register - RAW_IPR_EXC_ADDR = 0x10b, // exception address register - RAW_IPR_EXC_SUM = 0x10c, // exception summary register - RAW_IPR_EXC_MASK = 0x10d, // exception mask register - RAW_IPR_PAL_BASE = 0x10e, // PAL base address register - RAW_IPR_ICM = 0x10f, // instruction current mode - RAW_IPR_IPLR = 0x110, // interrupt priority level register - RAW_IPR_INTID = 0x111, // interrupt ID register - RAW_IPR_IFAULT_VA_FORM = 0x112, // formatted faulting virtual addr register - RAW_IPR_IVPTBR = 0x113, // virtual page table base register - RAW_IPR_HWINT_CLR = 0x115, // H/W interrupt clear register - RAW_IPR_SL_XMIT = 0x116, // serial line transmit register - RAW_IPR_SL_RCV = 0x117, // serial line receive register - RAW_IPR_ICSR = 0x118, // instruction control and status register - RAW_IPR_IC_FLUSH = 0x119, // instruction cache flush control - RAW_IPR_IC_PERR_STAT = 0x11a, // inst cache parity error status register - RAW_IPR_PMCTR = 0x11c, // performance counter register - - // PAL temporary registers... - // register meanings gleaned from osfpal.s source code - RAW_IPR_PALtemp0 = 0x140, // local scratch - RAW_IPR_PALtemp1 = 0x141, // local scratch - RAW_IPR_PALtemp2 = 0x142, // entUna - RAW_IPR_PALtemp3 = 0x143, // CPU specific impure area pointer - RAW_IPR_PALtemp4 = 0x144, // memory management temp - RAW_IPR_PALtemp5 = 0x145, // memory management temp - RAW_IPR_PALtemp6 = 0x146, // memory management temp - RAW_IPR_PALtemp7 = 0x147, // entIF - RAW_IPR_PALtemp8 = 0x148, // intmask - RAW_IPR_PALtemp9 = 0x149, // entSys - RAW_IPR_PALtemp10 = 0x14a, // ?? - RAW_IPR_PALtemp11 = 0x14b, // entInt - RAW_IPR_PALtemp12 = 0x14c, // entArith - RAW_IPR_PALtemp13 = 0x14d, // reserved for platform specific PAL - RAW_IPR_PALtemp14 = 0x14e, // reserved for platform specific PAL - RAW_IPR_PALtemp15 = 0x14f, // reserved for platform specific PAL - RAW_IPR_PALtemp16 = 0x150, // scratch / whami<7:0> / mces<4:0> - RAW_IPR_PALtemp17 = 0x151, // sysval - RAW_IPR_PALtemp18 = 0x152, // usp - RAW_IPR_PALtemp19 = 0x153, // ksp - RAW_IPR_PALtemp20 = 0x154, // PTBR - RAW_IPR_PALtemp21 = 0x155, // entMM - RAW_IPR_PALtemp22 = 0x156, // kgp - RAW_IPR_PALtemp23 = 0x157, // PCBB - - RAW_IPR_DTB_ASN = 0x200, // DTLB address space number register - RAW_IPR_DTB_CM = 0x201, // DTLB current mode register - RAW_IPR_DTB_TAG = 0x202, // DTLB tag register - RAW_IPR_DTB_PTE = 0x203, // DTLB page table entry register - RAW_IPR_DTB_PTE_TEMP = 0x204, // DTLB page table entry temporary register - - RAW_IPR_MM_STAT = 0x205, // data MMU fault status register - RAW_IPR_VA = 0x206, // fault virtual address register - RAW_IPR_VA_FORM = 0x207, // formatted virtual address register - RAW_IPR_MVPTBR = 0x208, // MTU virtual page table base register - RAW_IPR_DTB_IAP = 0x209, // DTLB invalidate all process register - RAW_IPR_DTB_IA = 0x20a, // DTLB invalidate all register - RAW_IPR_DTB_IS = 0x20b, // DTLB invalidate single register - RAW_IPR_ALT_MODE = 0x20c, // alternate mode register - RAW_IPR_CC = 0x20d, // cycle counter register - RAW_IPR_CC_CTL = 0x20e, // cycle counter control register - RAW_IPR_MCSR = 0x20f, // MTU control register - - RAW_IPR_DC_FLUSH = 0x210, - RAW_IPR_DC_PERR_STAT = 0x212, // Dcache parity error status register - RAW_IPR_DC_TEST_CTL = 0x213, // Dcache test tag control register - RAW_IPR_DC_TEST_TAG = 0x214, // Dcache test tag register - RAW_IPR_DC_TEST_TAG_TEMP = 0x215, // Dcache test tag temporary register - RAW_IPR_DC_MODE = 0x216, // Dcache mode register - RAW_IPR_MAF_MODE = 0x217, // miss address file mode register - - MaxInternalProcRegs // number of IPR registers - }; - - enum MiscRegIpr - { - //Write only - MinWriteOnlyIpr, - IPR_HWINT_CLR = MinWriteOnlyIpr, - IPR_SL_XMIT, - IPR_DC_FLUSH, - IPR_IC_FLUSH, - IPR_ALT_MODE, - IPR_DTB_IA, - IPR_DTB_IAP, - IPR_ITB_IA, - MaxWriteOnlyIpr, - IPR_ITB_IAP = MaxWriteOnlyIpr, - - //Read only - MinReadOnlyIpr, - IPR_INTID = MinReadOnlyIpr, - IPR_SL_RCV, - IPR_MM_STAT, - IPR_ITB_PTE_TEMP, - MaxReadOnlyIpr, - IPR_DTB_PTE_TEMP = MaxReadOnlyIpr, - - IPR_ISR, - IPR_ITB_TAG, - IPR_ITB_PTE, - IPR_ITB_ASN, - IPR_ITB_IS, - IPR_SIRR, - IPR_ASTRR, - IPR_ASTER, - IPR_EXC_ADDR, - IPR_EXC_SUM, - IPR_EXC_MASK, - IPR_PAL_BASE, - IPR_ICM, - IPR_IPLR, - IPR_IFAULT_VA_FORM, - IPR_IVPTBR, - IPR_ICSR, - IPR_IC_PERR_STAT, - IPR_PMCTR, - - // PAL temporary registers... - // register meanings gleaned from osfpal.s source code - IPR_PALtemp0, - IPR_PALtemp1, - IPR_PALtemp2, - IPR_PALtemp3, - IPR_PALtemp4, - IPR_PALtemp5, - IPR_PALtemp6, - IPR_PALtemp7, - IPR_PALtemp8, - IPR_PALtemp9, - IPR_PALtemp10, - IPR_PALtemp11, - IPR_PALtemp12, - IPR_PALtemp13, - IPR_PALtemp14, - IPR_PALtemp15, - IPR_PALtemp16, - IPR_PALtemp17, - IPR_PALtemp18, - IPR_PALtemp19, - IPR_PALtemp20, - IPR_PALtemp21, - IPR_PALtemp22, - IPR_PALtemp23, - - IPR_DTB_ASN, - IPR_DTB_CM, - IPR_DTB_TAG, - IPR_DTB_PTE, - - IPR_VA, - IPR_VA_FORM, - IPR_MVPTBR, - IPR_DTB_IS, - IPR_CC, - IPR_CC_CTL, - IPR_MCSR, - - IPR_DC_PERR_STAT, - IPR_DC_TEST_CTL, - IPR_DC_TEST_TAG, - IPR_DC_TEST_TAG_TEMP, - IPR_DC_MODE, - IPR_MAF_MODE, - - NumInternalProcRegs // number of IPR registers - }; - - inline bool IprIsWritable(int index) - { - return index < MinReadOnlyIpr || index > MaxReadOnlyIpr; - } - - inline bool IprIsReadable(int index) - { - return index < MinWriteOnlyIpr || index > MaxWriteOnlyIpr; - } - - extern md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs]; - extern int IprToMiscRegIndex[MaxInternalProcRegs]; - - void initializeIprTable(); + //Write only + MinWriteOnlyIpr, + IPR_HWINT_CLR = MinWriteOnlyIpr, + IPR_SL_XMIT, + IPR_DC_FLUSH, + IPR_IC_FLUSH, + IPR_ALT_MODE, + IPR_DTB_IA, + IPR_DTB_IAP, + IPR_ITB_IA, + MaxWriteOnlyIpr, + IPR_ITB_IAP = MaxWriteOnlyIpr, + + //Read only + MinReadOnlyIpr, + IPR_INTID = MinReadOnlyIpr, + IPR_SL_RCV, + IPR_MM_STAT, + IPR_ITB_PTE_TEMP, + MaxReadOnlyIpr, + IPR_DTB_PTE_TEMP = MaxReadOnlyIpr, + + IPR_ISR, + IPR_ITB_TAG, + IPR_ITB_PTE, + IPR_ITB_ASN, + IPR_ITB_IS, + IPR_SIRR, + IPR_ASTRR, + IPR_ASTER, + IPR_EXC_ADDR, + IPR_EXC_SUM, + IPR_EXC_MASK, + IPR_PAL_BASE, + IPR_ICM, + IPR_IPLR, + IPR_IFAULT_VA_FORM, + IPR_IVPTBR, + IPR_ICSR, + IPR_IC_PERR_STAT, + IPR_PMCTR, + + // PAL temporary registers... + // register meanings gleaned from osfpal.s source code + IPR_PALtemp0, + IPR_PALtemp1, + IPR_PALtemp2, + IPR_PALtemp3, + IPR_PALtemp4, + IPR_PALtemp5, + IPR_PALtemp6, + IPR_PALtemp7, + IPR_PALtemp8, + IPR_PALtemp9, + IPR_PALtemp10, + IPR_PALtemp11, + IPR_PALtemp12, + IPR_PALtemp13, + IPR_PALtemp14, + IPR_PALtemp15, + IPR_PALtemp16, + IPR_PALtemp17, + IPR_PALtemp18, + IPR_PALtemp19, + IPR_PALtemp20, + IPR_PALtemp21, + IPR_PALtemp22, + IPR_PALtemp23, + + IPR_DTB_ASN, + IPR_DTB_CM, + IPR_DTB_TAG, + IPR_DTB_PTE, + + IPR_VA, + IPR_VA_FORM, + IPR_MVPTBR, + IPR_DTB_IS, + IPR_CC, + IPR_CC_CTL, + IPR_MCSR, + + IPR_DC_PERR_STAT, + IPR_DC_TEST_CTL, + IPR_DC_TEST_TAG, + IPR_DC_TEST_TAG_TEMP, + IPR_DC_MODE, + IPR_MAF_MODE, + + NumInternalProcRegs // number of IPR registers +}; + +inline bool +IprIsWritable(int index) +{ + return index < MinReadOnlyIpr || index > MaxReadOnlyIpr; +} + +inline bool +IprIsReadable(int index) +{ + return index < MinWriteOnlyIpr || index > MaxWriteOnlyIpr; } -#endif +extern md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs]; +extern int IprToMiscRegIndex[MaxInternalProcRegs]; + +void initializeIprTable(); + +} // namespace AlphaISA + +#endif // __ARCH_ALPHA_IPR_HH__ diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa index 2177e8c4f..0b2a31410 100644 --- a/src/arch/alpha/isa/decoder.isa +++ b/src/arch/alpha/isa/decoder.isa @@ -638,7 +638,7 @@ decode OPCODE default Unknown::unknown() { /* Rb is a fake dependency so here is a fun way to get * the parser to understand that. */ - Ra = xc->readMiscReg(AlphaISA::IPR_CC) + (Rb & 0); + Ra = xc->readMiscReg(IPR_CC) + (Rb & 0); #else Ra = curTick; @@ -690,7 +690,7 @@ decode OPCODE default Unknown::unknown() { 0x00: CallPal::call_pal({{ if (!palValid || (palPriv - && xc->readMiscReg(AlphaISA::IPR_ICM) != AlphaISA::mode_kernel)) { + && xc->readMiscReg(IPR_ICM) != mode_kernel)) { // invalid pal function code, or attempt to do privileged // PAL call in non-kernel mode fault = new UnimplementedOpcodeFault; @@ -701,8 +701,8 @@ decode OPCODE default Unknown::unknown() { bool dopal = xc->simPalCheck(palFunc); if (dopal) { - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, NPC); - NPC = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + palOffset; + xc->setMiscReg(IPR_EXC_ADDR, NPC); + NPC = xc->readMiscReg(IPR_PAL_BASE) + palOffset; } } }}, IsNonSpeculative); @@ -783,14 +783,19 @@ decode OPCODE default Unknown::unknown() { } } - format BasicOperate { - 0x1e: decode PALMODE { - 0: OpcdecFault::hw_rei(); - 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); + 0x1e: decode PALMODE { + 0: OpcdecFault::hw_rei(); + format BasicOperate { + 1: hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); } + } + +#endif + format BasicOperate { // M5 special opcodes use the reserved 0x01 opcode space 0x01: decode M5FUNC { +#if FULL_SYSTEM 0x00: arm({{ PseudoInst::arm(xc->tcBase()); }}, IsNonSpeculative); @@ -806,22 +811,34 @@ decode OPCODE default Unknown::unknown() { 0x04: quiesceTime({{ R0 = PseudoInst::quiesceTime(xc->tcBase()); }}, IsNonSpeculative, IsUnverifiable); - 0x10: ivlb({{ - warn_once("Obsolete M5 instruction ivlb encountered.\n"); +#endif + 0x07: rpns({{ + R0 = PseudoInst::rpns(xc->tcBase()); + }}, IsNonSpeculative, IsUnverifiable); + 0x09: wakeCPU({{ + PseudoInst::wakeCPU(xc->tcBase(), R16); + }}, IsNonSpeculative, IsUnverifiable); + 0x10: deprecated_ivlb({{ + warn_once("Obsolete M5 ivlb instruction encountered.\n"); }}); - 0x11: ivle({{ - warn_once("Obsolete M5 instruction ivlb encountered.\n"); + 0x11: deprecated_ivle({{ + warn_once("Obsolete M5 ivlb instruction encountered.\n"); }}); - 0x20: m5exit_old({{ - PseudoInst::m5exit_old(xc->tcBase()); + 0x20: deprecated_exit ({{ + warn_once("deprecated M5 exit instruction encountered.\n"); + PseudoInst::m5exit(xc->tcBase(), 0); }}, No_OpClass, IsNonSpeculative); 0x21: m5exit({{ PseudoInst::m5exit(xc->tcBase(), R16); }}, No_OpClass, IsNonSpeculative); +#if FULL_SYSTEM 0x31: loadsymbol({{ PseudoInst::loadsymbol(xc->tcBase()); }}, No_OpClass, IsNonSpeculative); - 0x30: initparam({{ Ra = xc->tcBase()->getCpuPtr()->system->init_param; }}); + 0x30: initparam({{ + Ra = xc->tcBase()->getCpuPtr()->system->init_param; + }}); +#endif 0x40: resetstats({{ PseudoInst::resetstats(xc->tcBase(), R16, R17); }}, IsNonSpeculative); @@ -834,28 +851,93 @@ decode OPCODE default Unknown::unknown() { 0x43: m5checkpoint({{ PseudoInst::m5checkpoint(xc->tcBase(), R16, R17); }}, IsNonSpeculative); +#if FULL_SYSTEM 0x50: m5readfile({{ R0 = PseudoInst::readfile(xc->tcBase(), R16, R17, R18); }}, IsNonSpeculative); +#endif 0x51: m5break({{ PseudoInst::debugbreak(xc->tcBase()); }}, IsNonSpeculative); 0x52: m5switchcpu({{ PseudoInst::switchcpu(xc->tcBase()); }}, IsNonSpeculative); +#if FULL_SYSTEM 0x53: m5addsymbol({{ PseudoInst::addsymbol(xc->tcBase(), R16, R17); }}, IsNonSpeculative); +#endif 0x54: m5panic({{ panic("M5 panic instruction called at pc=%#x.", xc->readPC()); }}, IsNonSpeculative); - 0x55: m5anBegin({{ - PseudoInst::anBegin(xc->tcBase(), R16); +#define CPANN(lbl) CPA::cpa()->lbl(xc->tcBase()) + 0x55: decode RA { + 0x00: m5a_old({{ + panic("Deprecated M5 annotate instruction executed at pc=%#x\n", + xc->readPC()); + }}, IsNonSpeculative); + 0x01: m5a_bsm({{ + CPANN(swSmBegin); + }}, IsNonSpeculative); + 0x02: m5a_esm({{ + CPANN(swSmEnd); + }}, IsNonSpeculative); + 0x03: m5a_begin({{ + CPANN(swExplictBegin); + }}, IsNonSpeculative); + 0x04: m5a_end({{ + CPANN(swEnd); + }}, IsNonSpeculative); + 0x06: m5a_q({{ + CPANN(swQ); + }}, IsNonSpeculative); + 0x07: m5a_dq({{ + CPANN(swDq); + }}, IsNonSpeculative); + 0x08: m5a_wf({{ + CPANN(swWf); + }}, IsNonSpeculative); + 0x09: m5a_we({{ + CPANN(swWe); + }}, IsNonSpeculative); + 0x0C: m5a_sq({{ + CPANN(swSq); + }}, IsNonSpeculative); + 0x0D: m5a_aq({{ + CPANN(swAq); + }}, IsNonSpeculative); + 0x0E: m5a_pq({{ + CPANN(swPq); + }}, IsNonSpeculative); + 0x0F: m5a_l({{ + CPANN(swLink); + }}, IsNonSpeculative); + 0x10: m5a_identify({{ + CPANN(swIdentify); + }}, IsNonSpeculative); + 0x11: m5a_getid({{ + R0 = CPANN(swGetId); + }}, IsNonSpeculative); + 0x13: m5a_scl({{ + CPANN(swSyscallLink); + }}, IsNonSpeculative); + 0x14: m5a_rq({{ + CPANN(swRq); + }}, IsNonSpeculative); + } // M5 Annotate Operations +#undef CPANN + 0x56: m5reserved2({{ + warn("M5 reserved opcode ignored"); + }}, IsNonSpeculative); + 0x57: m5reserved3({{ + warn("M5 reserved opcode ignored"); }}, IsNonSpeculative); - 0x56: m5anWait({{ - PseudoInst::anWait(xc->tcBase(), R16, R17); + 0x58: m5reserved4({{ + warn("M5 reserved opcode ignored"); + }}, IsNonSpeculative); + 0x59: m5reserved5({{ + warn("M5 reserved opcode ignored"); }}, IsNonSpeculative); } } -#endif } diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa index 773e7d10c..ed04d2a50 100644 --- a/src/arch/alpha/isa/fp.isa +++ b/src/arch/alpha/isa/fp.isa @@ -46,7 +46,7 @@ output exec {{ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) { Fault fault = NoFault; // dummy... this ipr access should not fault - if (!EV5::ICSR_FPE(xc->readMiscReg(AlphaISA::IPR_ICSR))) { + if (!ICSR_FPE(xc->readMiscReg(IPR_ICSR))) { fault = new FloatEnableFault; } return fault; @@ -229,7 +229,7 @@ def template FloatingPointExecute {{ %(code)s; } else { m5_fesetround(getC99RoundingMode( - xc->readMiscRegNoEffect(AlphaISA::MISCREG_FPCR))); + xc->readMiscRegNoEffect(MISCREG_FPCR))); %(code)s; m5_fesetround(M5_FE_TONEAREST); } diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa index d72dfe34a..aea44976c 100644 --- a/src/arch/alpha/isa/main.isa +++ b/src/arch/alpha/isa/main.isa @@ -68,9 +68,8 @@ using namespace AlphaISA; output exec {{ #include <math.h> -#if FULL_SYSTEM +#include "base/cp_annotate.hh" #include "sim/pseudo_inst.hh" -#endif #include "arch/alpha/ipr.hh" #include "base/fenv.hh" #include "config/ss_compatible_fp.hh" @@ -173,11 +172,11 @@ def operands {{ # Int regs default to unsigned, but code should not count on this. # For clarity, descriptions that depend on unsigned behavior should # explicitly specify '.uq'. - 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA', + 'Ra': ('IntReg', 'uq', 'PALMODE ? reg_redir[RA] : RA', 'IsInteger', 1), - 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB', + 'Rb': ('IntReg', 'uq', 'PALMODE ? reg_redir[RB] : RB', 'IsInteger', 2), - 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC', + 'Rc': ('IntReg', 'uq', 'PALMODE ? reg_redir[RC] : RC', 'IsInteger', 3), 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa index fe0daf772..cd5e117ec 100644 --- a/src/arch/alpha/isa/mem.isa +++ b/src/arch/alpha/isa/mem.isa @@ -43,7 +43,7 @@ output header {{ protected: /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; + Request::Flags memAccessFlags; /// Pointer to EAComp object. const StaticInstPtr eaCompPtr; /// Pointer to MemAcc object. @@ -54,7 +54,7 @@ output header {{ StaticInstPtr _eaCompPtr = nullStaticInstPtr, StaticInstPtr _memAccPtr = nullStaticInstPtr) : AlphaStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) + eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) { } @@ -677,6 +677,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, inst_flags) if mem_flags: + mem_flags = [ 'Request::%s' % flag for flag in mem_flags ] s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' iop.constructor += s memacc_iop.constructor += s diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa index 294b92e2f..3d3b81600 100644 --- a/src/arch/alpha/isa/pal.isa +++ b/src/arch/alpha/isa/pal.isa @@ -174,11 +174,11 @@ output decoder {{ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), disp(HW_LDST_DISP) { - memAccessFlags = 0; - if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; - if (HW_LDST_ALT) memAccessFlags |= ALTMODE; - if (HW_LDST_VPTE) memAccessFlags |= VPTE; - if (HW_LDST_LOCK) memAccessFlags |= LOCKED; + memAccessFlags.clear(); + if (HW_LDST_PHYS) memAccessFlags.set(Request::PHYSICAL); + if (HW_LDST_ALT) memAccessFlags.set(Request::ALTMODE); + if (HW_LDST_VPTE) memAccessFlags.set(Request::VPTE); + if (HW_LDST_LOCK) memAccessFlags.set(Request::LOCKED); } std::string diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh index be1d1b8bb..d37a769ea 100644 --- a/src/arch/alpha/isa_traits.hh +++ b/src/arch/alpha/isa_traits.hh @@ -42,142 +42,134 @@ namespace LittleEndianGuest {} class StaticInstPtr; -namespace AlphaISA +namespace AlphaISA { + +using namespace LittleEndianGuest; +using AlphaISAInst::MaxInstSrcRegs; +using AlphaISAInst::MaxInstDestRegs; + +// These enumerate all the registers for dependence tracking. +enum DependenceTags { + // 0..31 are the integer regs 0..31 + // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) + FP_Base_DepTag = 40, + Ctrl_Base_DepTag = 72 +}; + +StaticInstPtr decodeInst(ExtMachInst); + +// Alpha Does NOT have a delay slot +#define ISA_HAS_DELAY_SLOT 0 + +const Addr PageShift = 13; +const Addr PageBytes = ULL(1) << PageShift; +const Addr PageMask = ~(PageBytes - 1); +const Addr PageOffset = PageBytes - 1; + +//////////////////////////////////////////////////////////////////////// +// +// Translation stuff +// + +const Addr PteShift = 3; +const Addr NPtePageShift = PageShift - PteShift; +const Addr NPtePage = ULL(1) << NPtePageShift; +const Addr PteMask = NPtePage - 1; + +// User Virtual +const Addr USegBase = ULL(0x0); +const Addr USegEnd = ULL(0x000003ffffffffff); + +// Kernel Direct Mapped +const Addr K0SegBase = ULL(0xfffffc0000000000); +const Addr K0SegEnd = ULL(0xfffffdffffffffff); + +// Kernel Virtual +const Addr K1SegBase = ULL(0xfffffe0000000000); +const Addr K1SegEnd = ULL(0xffffffffffffffff); + +// For loading... XXX This maybe could be USegEnd?? --ali +const Addr LoadAddrMask = ULL(0xffffffffff); + +//////////////////////////////////////////////////////////////////////// +// +// Interrupt levels +// +enum InterruptLevels { - using namespace LittleEndianGuest; - using AlphaISAInst::MaxInstSrcRegs; - using AlphaISAInst::MaxInstDestRegs; - - // These enumerate all the registers for dependence tracking. - enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = 40, - Ctrl_Base_DepTag = 72 - }; - - StaticInstPtr decodeInst(ExtMachInst); - - // Alpha Does NOT have a delay slot - #define ISA_HAS_DELAY_SLOT 0 - - const Addr PageShift = 13; - const Addr PageBytes = ULL(1) << PageShift; - const Addr PageMask = ~(PageBytes - 1); - const Addr PageOffset = PageBytes - 1; - - - //////////////////////////////////////////////////////////////////////// - // - // Translation stuff - // - - const Addr PteShift = 3; - const Addr NPtePageShift = PageShift - PteShift; - const Addr NPtePage = ULL(1) << NPtePageShift; - const Addr PteMask = NPtePage - 1; - - // User Virtual - const Addr USegBase = ULL(0x0); - const Addr USegEnd = ULL(0x000003ffffffffff); - - // Kernel Direct Mapped - const Addr K0SegBase = ULL(0xfffffc0000000000); - const Addr K0SegEnd = ULL(0xfffffdffffffffff); - - // Kernel Virtual - const Addr K1SegBase = ULL(0xfffffe0000000000); - const Addr K1SegEnd = ULL(0xffffffffffffffff); - - // For loading... XXX This maybe could be USegEnd?? --ali - const Addr LoadAddrMask = ULL(0xffffffffff); - -#if FULL_SYSTEM - - //////////////////////////////////////////////////////////////////////// - // - // Interrupt levels - // - enum InterruptLevels - { - INTLEVEL_SOFTWARE_MIN = 4, - INTLEVEL_SOFTWARE_MAX = 19, - - INTLEVEL_EXTERNAL_MIN = 20, - INTLEVEL_EXTERNAL_MAX = 34, - - INTLEVEL_IRQ0 = 20, - INTLEVEL_IRQ1 = 21, - INTINDEX_ETHERNET = 0, - INTINDEX_SCSI = 1, - INTLEVEL_IRQ2 = 22, - INTLEVEL_IRQ3 = 23, - - INTLEVEL_SERIAL = 33, - - NumInterruptLevels = INTLEVEL_EXTERNAL_MAX - }; - -#endif - - // EV5 modes - enum mode_type - { - mode_kernel = 0, // kernel - mode_executive = 1, // executive (unused by unix) - mode_supervisor = 2, // supervisor (unused by unix) - mode_user = 3, // user mode - mode_number // number of modes - }; - - // Constants Related to the number of registers - - const int NumIntArchRegs = 32; - const int NumPALShadowRegs = 8; - const int NumFloatArchRegs = 32; - // @todo: Figure out what this number really should be. - const int NumMiscArchRegs = 77; - - const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs; - const int NumFloatRegs = NumFloatArchRegs; - const int NumMiscRegs = NumMiscArchRegs; - - const int TotalNumRegs = NumIntRegs + NumFloatRegs + - NumMiscRegs + NumInternalProcRegs; - - const int TotalDataRegs = NumIntRegs + NumFloatRegs; - - // semantically meaningful register indices - const int ZeroReg = 31; // architecturally meaningful - // the rest of these depend on the ABI - const int StackPointerReg = 30; - const int GlobalPointerReg = 29; - const int ProcedureValueReg = 27; - const int ReturnAddressReg = 26; - const int ReturnValueReg = 0; - const int FramePointerReg = 15; + INTLEVEL_SOFTWARE_MIN = 4, + INTLEVEL_SOFTWARE_MAX = 19, + + INTLEVEL_EXTERNAL_MIN = 20, + INTLEVEL_EXTERNAL_MAX = 34, - const int ArgumentReg[] = {16, 17, 18, 19, 20, 21}; - const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); + INTLEVEL_IRQ0 = 20, + INTLEVEL_IRQ1 = 21, + INTINDEX_ETHERNET = 0, + INTINDEX_SCSI = 1, + INTLEVEL_IRQ2 = 22, + INTLEVEL_IRQ3 = 23, - const int SyscallNumReg = ReturnValueReg; - const int SyscallPseudoReturnReg = ArgumentReg[4]; - const int SyscallSuccessReg = 19; + INTLEVEL_SERIAL = 33, - const int LogVMPageSize = 13; // 8K bytes - const int VMPageSize = (1 << LogVMPageSize); - - const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned - - const int MachineBytes = 8; - const int WordBytes = 4; - const int HalfwordBytes = 2; - const int ByteBytes = 1; - - // return a no-op instruction... used for instruction fetch faults - // Alpha UNOP (ldq_u r31,0(r0)) - const ExtMachInst NoopMachInst = 0x2ffe0000; + NumInterruptLevels = INTLEVEL_EXTERNAL_MAX +}; +// EV5 modes +enum mode_type +{ + mode_kernel = 0, // kernel + mode_executive = 1, // executive (unused by unix) + mode_supervisor = 2, // supervisor (unused by unix) + mode_user = 3, // user mode + mode_number // number of modes }; +// Constants Related to the number of registers + +const int NumIntArchRegs = 32; +const int NumPALShadowRegs = 8; +const int NumFloatArchRegs = 32; +// @todo: Figure out what this number really should be. +const int NumMiscArchRegs = 77; + +const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs; +const int NumFloatRegs = NumFloatArchRegs; +const int NumMiscRegs = NumMiscArchRegs; + +const int TotalNumRegs = + NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs; + +const int TotalDataRegs = NumIntRegs + NumFloatRegs; + +// semantically meaningful register indices +const int ZeroReg = 31; // architecturally meaningful +// the rest of these depend on the ABI +const int StackPointerReg = 30; +const int GlobalPointerReg = 29; +const int ProcedureValueReg = 27; +const int ReturnAddressReg = 26; +const int ReturnValueReg = 0; +const int FramePointerReg = 15; + +const int SyscallNumReg = 0; +const int FirstArgumentReg = 16; +const int SyscallPseudoReturnReg = 20; + +const int LogVMPageSize = 13; // 8K bytes +const int VMPageSize = (1 << LogVMPageSize); + +const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned + +const int MachineBytes = 8; +const int WordBytes = 4; +const int HalfwordBytes = 2; +const int ByteBytes = 1; + +// return a no-op instruction... used for instruction fetch faults +// Alpha UNOP (ldq_u r31,0(r0)) +const ExtMachInst NoopMachInst = 0x2ffe0000; + +} // namespace AlphaISA + #endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/src/arch/alpha/kernel_stats.cc b/src/arch/alpha/kernel_stats.cc index a004d5f25..6e9dc1611 100644 --- a/src/arch/alpha/kernel_stats.cc +++ b/src/arch/alpha/kernel_stats.cc @@ -152,7 +152,7 @@ Statistics::changeMode(cpu_mode newmode, ThreadContext *tc) void Statistics::mode(cpu_mode newmode, ThreadContext *tc) { - Addr pcbb = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23); + Addr pcbb = tc->readMiscRegNoEffect(IPR_PALtemp23); if (newmode == kernel && pcbb == idleProcess) newmode = idle; @@ -213,5 +213,5 @@ Statistics::unserialize(Checkpoint *cp, const string §ion) themode = (cpu_mode)exemode; } -} /* end namespace AlphaISA::Kernel */ -} /* end namespace AlphaISA */ +} // namespace Kernel +} // namespace AlphaISA diff --git a/src/arch/alpha/kernel_stats.hh b/src/arch/alpha/kernel_stats.hh index 7b8640ad7..837269309 100644 --- a/src/arch/alpha/kernel_stats.hh +++ b/src/arch/alpha/kernel_stats.hh @@ -62,15 +62,15 @@ class Statistics : public ::Kernel::Statistics void changeMode(cpu_mode newmode, ThreadContext *tc); private: - Stats::Vector<> _callpal; -// Stats::Vector<> _faults; + Stats::Vector _callpal; +// Stats::Vector _faults; - Stats::Vector<> _mode; - Stats::Vector<> _modeGood; + Stats::Vector _mode; + Stats::Vector _modeGood; Stats::Formula _modeFraction; - Stats::Vector<> _modeTicks; + Stats::Vector _modeTicks; - Stats::Scalar<> _swap_context; + Stats::Scalar _swap_context; public: Statistics(System *system); @@ -90,7 +90,7 @@ class Statistics : public ::Kernel::Statistics void unserialize(Checkpoint *cp, const std::string §ion); }; -} /* end namespace AlphaISA::Kernel */ -} /* end namespace AlphaISA */ +} // namespace Kernel +} // namespace AlphaISA #endif // __ARCH_ALPHA_KERNEL_STATS_HH__ diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc index e6908a572..ad8388096 100644 --- a/src/arch/alpha/linux/linux.cc +++ b/src/arch/alpha/linux/linux.cc @@ -28,47 +28,44 @@ * Authors: Korey Sewell */ -#include "arch/alpha/linux/linux.hh" - #include <fcntl.h> +#include "arch/alpha/linux/linux.hh" + // open(2) flags translation table OpenFlagTransTable AlphaLinux::openFlagTable[] = { #ifdef _MSC_VER - { AlphaLinux::TGT_O_RDONLY, _O_RDONLY }, - { AlphaLinux::TGT_O_WRONLY, _O_WRONLY }, - { AlphaLinux::TGT_O_RDWR, _O_RDWR }, - { AlphaLinux::TGT_O_APPEND, _O_APPEND }, - { AlphaLinux::TGT_O_CREAT, _O_CREAT }, - { AlphaLinux::TGT_O_TRUNC, _O_TRUNC }, - { AlphaLinux::TGT_O_EXCL, _O_EXCL }, + { AlphaLinux::TGT_O_RDONLY, _O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, _O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, _O_RDWR }, + { AlphaLinux::TGT_O_APPEND, _O_APPEND }, + { AlphaLinux::TGT_O_CREAT, _O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, _O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, + { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY }, + { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { AlphaLinux::TGT_O_SYNC, _O_SYNC }, + { AlphaLinux::TGT_O_SYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { AlphaLinux::TGT_O_RDONLY, O_RDONLY }, - { AlphaLinux::TGT_O_WRONLY, O_WRONLY }, - { AlphaLinux::TGT_O_RDWR, O_RDWR }, - { AlphaLinux::TGT_O_APPEND, O_APPEND }, - { AlphaLinux::TGT_O_CREAT, O_CREAT }, - { AlphaLinux::TGT_O_TRUNC, O_TRUNC }, - { AlphaLinux::TGT_O_EXCL, O_EXCL }, - { AlphaLinux::TGT_O_NONBLOCK, O_NONBLOCK }, - { AlphaLinux::TGT_O_NOCTTY, O_NOCTTY }, + { AlphaLinux::TGT_O_RDONLY, O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, O_RDWR }, + { AlphaLinux::TGT_O_APPEND, O_APPEND }, + { AlphaLinux::TGT_O_CREAT, O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, O_EXCL }, + { AlphaLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaLinux::TGT_O_NOCTTY, O_NOCTTY }, #ifdef O_SYNC - { AlphaLinux::TGT_O_SYNC, O_SYNC }, + { AlphaLinux::TGT_O_SYNC, O_SYNC }, #endif #endif /* _MSC_VER */ }; const int AlphaLinux::NUM_OPEN_FLAGS = - (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0])); - - - + (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0])); diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh index 84c04ebc3..c622c5ef1 100644 --- a/src/arch/alpha/linux/linux.hh +++ b/src/arch/alpha/linux/linux.hh @@ -28,8 +28,8 @@ * Authors: Korey Sewell */ -#ifndef __ALPHA_ALPHA_LINUX_HH -#define __ALPHA_ALPHA_LINUX_HH +#ifndef __ALPHA_ALPHA_LINUX_LINUX_HH__ +#define __ALPHA_ALPHA_LINUX_LINUX_HH__ #include "kern/linux/linux.hh" @@ -50,21 +50,21 @@ class AlphaLinux : public Linux //@{ /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00000010; //!< O_APPEND - static const int TGT_O_CREAT = 00001000; //!< O_CREAT - static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC - static const int TGT_O_EXCL = 00004000; //!< O_EXCL - static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY - static const int TGT_O_SYNC = 00040000; //!< O_SYNC - static const int TGT_O_DRD = 00100000; //!< O_DRD - static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO - static const int TGT_O_CACHE = 00400000; //!< O_CACHE - static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC - static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC //@} /// For mmap(). @@ -72,13 +72,13 @@ class AlphaLinux : public Linux //@{ /// For getsysinfo(). - static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type - static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # CPUs on machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz static const unsigned GSI_IEEE_FP_CONTROL = 45; //@} @@ -127,4 +127,4 @@ class AlphaLinux : public Linux }; }; -#endif +#endif // __ALPHA_ALPHA_LINUX_LINUX_HH__ diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc index ec47992bd..aeff9fbed 100644 --- a/src/arch/alpha/linux/process.cc +++ b/src/arch/alpha/linux/process.cc @@ -43,18 +43,16 @@ using namespace std; using namespace AlphaISA; - - /// Target uname() handler. static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); + strcpy(name->release, "2.6.26"); strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); strcpy(name->machine, "alpha"); @@ -69,13 +67,13 @@ static SyscallReturn osf_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); - // unsigned nbytes = tc->getSyscallArg(2); + unsigned op = process->getSyscallArg(tc, 0); + // unsigned nbytes = process->getSyscallArg(tc, 2); switch (op) { case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1)); // I don't think this exactly matches the HW FPCR *fpcr = 0; fpcr.copyOut(tc->getMemPort()); @@ -96,13 +94,13 @@ static SyscallReturn osf_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); - // unsigned nbytes = tc->getSyscallArg(2); + unsigned op = process->getSyscallArg(tc, 0); + // unsigned nbytes = process->getSyscallArg(tc, 2); switch (op) { case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1)); // I don't think this exactly matches the HW FPCR fpcr.copyIn(tc->getMemPort()); DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " @@ -138,7 +136,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", chmodFunc<AlphaLinux>), /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), + /* 17 */ SyscallDesc("brk", brkFunc), /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc), @@ -179,9 +177,9 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", readlinkFunc), /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 60 */ SyscallDesc("umask", umaskFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), @@ -250,14 +248,14 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 126 */ SyscallDesc("setreuid", unimplementedFunc), /* 127 */ SyscallDesc("setregid", unimplementedFunc), /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", unimplementedFunc), - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 129 */ SyscallDesc("truncate", truncateFunc), + /* 130 */ SyscallDesc("ftruncate", ftruncateFunc), /* 131 */ SyscallDesc("flock", unimplementedFunc), /* 132 */ SyscallDesc("setgid", unimplementedFunc), /* 133 */ SyscallDesc("sendto", unimplementedFunc), /* 134 */ SyscallDesc("shutdown", unimplementedFunc), /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", mkdirFunc), /* 137 */ SyscallDesc("rmdir", unimplementedFunc), /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), @@ -465,7 +463,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), /* 339 */ SyscallDesc("uname", unameFunc), /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 341 */ SyscallDesc("mremap", unimplementedFunc), + /* 341 */ SyscallDesc("mremap", mremapFunc<AlphaLinux>), /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), /* 343 */ SyscallDesc("setresuid", unimplementedFunc), /* 344 */ SyscallDesc("getresuid", unimplementedFunc), @@ -491,7 +489,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 364 */ SyscallDesc("getrusage", getrusageFunc<AlphaLinux>), /* 365 */ SyscallDesc("wait4", unimplementedFunc), /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), - /* 367 */ SyscallDesc("getcwd", unimplementedFunc), + /* 367 */ SyscallDesc("getcwd", getcwdFunc), /* 368 */ SyscallDesc("capget", unimplementedFunc), /* 369 */ SyscallDesc("capset", unimplementedFunc), /* 370 */ SyscallDesc("sendfile", unimplementedFunc), @@ -581,7 +579,7 @@ AlphaLinuxProcess::AlphaLinuxProcess(LiveProcessParams * params, SyscallDesc* AlphaLinuxProcess::getDesc(int callnum) { - if (callnum < 0 || callnum > Num_Syscall_Descs) + if (callnum < 0 || callnum >= Num_Syscall_Descs) return NULL; return &syscallDescs[callnum]; } diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh index 8d7c24e37..9ab7b0501 100644 --- a/src/arch/alpha/linux/process.hh +++ b/src/arch/alpha/linux/process.hh @@ -51,4 +51,5 @@ class AlphaLinuxProcess : public AlphaLiveProcess }; } // namespace AlphaISA + #endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc index 102598716..1d9332a58 100644 --- a/src/arch/alpha/linux/system.cc +++ b/src/arch/alpha/linux/system.cc @@ -157,7 +157,6 @@ LinuxAlphaSystem::~LinuxAlphaSystem() delete printThreadEvent; } - void LinuxAlphaSystem::setDelayLoop(ThreadContext *tc) { @@ -169,11 +168,9 @@ LinuxAlphaSystem::setDelayLoop(ThreadContext *tc) vp = tc->getVirtPort(); vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988)); - tc->delVirtPort(vp); } } - void LinuxAlphaSystem::SkipDelayLoopEvent::process(ThreadContext *tc) { diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh index 00cde826a..3e4de7b2a 100644 --- a/src/arch/alpha/linux/system.hh +++ b/src/arch/alpha/linux/system.hh @@ -43,9 +43,6 @@ class IdleStartEvent; #include "kern/linux/events.hh" #include "params/LinuxAlphaSystem.hh" -using namespace AlphaISA; -using namespace Linux; - /** * This class contains linux specific system code (Loading, Events). * It points to objects that are the system binaries to load and patches them @@ -54,23 +51,20 @@ using namespace Linux; class LinuxAlphaSystem : public AlphaSystem { private: - class SkipDelayLoopEvent : public SkipFuncEvent + struct SkipDelayLoopEvent : public SkipFuncEvent { - public: SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) : SkipFuncEvent(q, desc, addr) {} virtual void process(ThreadContext *tc); }; - class PrintThreadInfo : public PCEvent + struct PrintThreadInfo : public PCEvent { - public: PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) : PCEvent(q, desc, addr) {} virtual void process(ThreadContext *tc); }; - /** * Addresses defining where the kernel bootloader places various * elements. Details found in include/asm-alpha/system.h @@ -112,7 +106,7 @@ class LinuxAlphaSystem : public AlphaSystem * PC based event to skip the dprink() call and emulate its * functionality */ - DebugPrintkEvent *debugPrintkEvent; + Linux::DebugPrintkEvent *debugPrintkEvent; /** * Skip calculate_delay_loop() rather than waiting for this to be diff --git a/src/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh index b0c8284be..db723bed3 100644 --- a/src/arch/alpha/linux/threadinfo.hh +++ b/src/arch/alpha/linux/threadinfo.hh @@ -55,7 +55,7 @@ class ThreadInfo CopyOut(tc, &data, addr, sizeof(T)); - data = TheISA::gtoh(data); + data = AlphaISA::gtoh(data); return true; } @@ -76,7 +76,7 @@ class ThreadInfo Addr sp; if (!addr) - addr = tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23); + addr = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23); FunctionalPort *p = tc->getPhysPort(); p->readBlob(addr, (uint8_t *)&sp, sizeof(Addr)); @@ -147,6 +147,6 @@ class ThreadInfo } }; -/* namespace Linux */ } +} // namespace Linux #endif // __ARCH_ALPHA_LINUX_LINUX_THREADINFO_HH__ diff --git a/src/arch/alpha/locked_mem.hh b/src/arch/alpha/locked_mem.hh index df66b92bc..e8928ba08 100644 --- a/src/arch/alpha/locked_mem.hh +++ b/src/arch/alpha/locked_mem.hh @@ -49,9 +49,8 @@ #include "base/misc.hh" #include "mem/request.hh" +namespace AlphaISA { -namespace AlphaISA -{ template <class XC> inline void handleLockedRead(XC *xc, Request *req) @@ -86,9 +85,9 @@ handleLockedWrite(XC *xc, Request *req) stCondFailures++; xc->setStCondFailures(stCondFailures); if (stCondFailures % 100000 == 0) { - warn("cpu %d: %d consecutive " + warn("context %d: %d consecutive " "store conditional failures\n", - xc->readCpuId(), stCondFailures); + xc->contextId(), stCondFailures); } // store conditional failed already, so don't issue it to mem @@ -99,7 +98,6 @@ handleLockedWrite(XC *xc, Request *req) return true; } - } // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_LOCKED_MEM_HH__ diff --git a/src/arch/alpha/microcode_rom.hh b/src/arch/alpha/microcode_rom.hh new file mode 100644 index 000000000..ef0602580 --- /dev/null +++ b/src/arch/alpha/microcode_rom.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_ALPHA_MICROCODE_ROM_HH__ +#define __ARCH_ALPHA_MICROCODE_ROM_HH__ + +#include "sim/microcode_rom.hh" + +namespace AlphaISA +{ + using ::MicrocodeRom; +} + +#endif // __ARCH_ALPHA_MICROCODE_ROM_HH__ diff --git a/src/arch/alpha/miscregfile.cc b/src/arch/alpha/miscregfile.cc index cb5875349..61a86f1fb 100644 --- a/src/arch/alpha/miscregfile.cc +++ b/src/arch/alpha/miscregfile.cc @@ -30,121 +30,121 @@ * Kevin Lim */ +#include <cassert> + #include "arch/alpha/miscregfile.hh" #include "base/misc.hh" -namespace AlphaISA -{ +namespace AlphaISA { - void - MiscRegFile::serialize(std::ostream &os) - { - SERIALIZE_SCALAR(fpcr); - SERIALIZE_SCALAR(uniq); - SERIALIZE_SCALAR(lock_flag); - SERIALIZE_SCALAR(lock_addr); - SERIALIZE_ARRAY(ipr, NumInternalProcRegs); - } +void +MiscRegFile::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(fpcr); + SERIALIZE_SCALAR(uniq); + SERIALIZE_SCALAR(lock_flag); + SERIALIZE_SCALAR(lock_addr); + SERIALIZE_ARRAY(ipr, NumInternalProcRegs); +} - void - MiscRegFile::unserialize(Checkpoint *cp, const std::string §ion) - { - UNSERIALIZE_SCALAR(fpcr); - UNSERIALIZE_SCALAR(uniq); - UNSERIALIZE_SCALAR(lock_flag); - UNSERIALIZE_SCALAR(lock_addr); - UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); - } +void +MiscRegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(fpcr); + UNSERIALIZE_SCALAR(uniq); + UNSERIALIZE_SCALAR(lock_flag); + UNSERIALIZE_SCALAR(lock_addr); + UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); +} - MiscReg - MiscRegFile::readRegNoEffect(int misc_reg) - { - switch(misc_reg) { - case MISCREG_FPCR: - return fpcr; - case MISCREG_UNIQ: - return uniq; - case MISCREG_LOCKFLAG: - return lock_flag; - case MISCREG_LOCKADDR: - return lock_addr; - case MISCREG_INTR: - return intr_flag; - default: - assert(misc_reg < NumInternalProcRegs); - return ipr[misc_reg]; - } +MiscReg +MiscRegFile::readRegNoEffect(int misc_reg) +{ + switch (misc_reg) { + case MISCREG_FPCR: + return fpcr; + case MISCREG_UNIQ: + return uniq; + case MISCREG_LOCKFLAG: + return lock_flag; + case MISCREG_LOCKADDR: + return lock_addr; + case MISCREG_INTR: + return intr_flag; + default: + assert(misc_reg < NumInternalProcRegs); + return ipr[misc_reg]; } +} - MiscReg - MiscRegFile::readReg(int misc_reg, ThreadContext *tc) - { - switch(misc_reg) { - case MISCREG_FPCR: - return fpcr; - case MISCREG_UNIQ: - return uniq; - case MISCREG_LOCKFLAG: - return lock_flag; - case MISCREG_LOCKADDR: - return lock_addr; - case MISCREG_INTR: - return intr_flag; - default: - return readIpr(misc_reg, tc); - } +MiscReg +MiscRegFile::readReg(int misc_reg, ThreadContext *tc) +{ + switch (misc_reg) { + case MISCREG_FPCR: + return fpcr; + case MISCREG_UNIQ: + return uniq; + case MISCREG_LOCKFLAG: + return lock_flag; + case MISCREG_LOCKADDR: + return lock_addr; + case MISCREG_INTR: + return intr_flag; + default: + return readIpr(misc_reg, tc); } +} - void - MiscRegFile::setRegNoEffect(int misc_reg, const MiscReg &val) - { - switch(misc_reg) { - case MISCREG_FPCR: - fpcr = val; - return; - case MISCREG_UNIQ: - uniq = val; - return; - case MISCREG_LOCKFLAG: - lock_flag = val; - return; - case MISCREG_LOCKADDR: - lock_addr = val; - return; - case MISCREG_INTR: - intr_flag = val; - return; - default: - assert(misc_reg < NumInternalProcRegs); - ipr[misc_reg] = val; - return; - } +void +MiscRegFile::setRegNoEffect(int misc_reg, const MiscReg &val) +{ + switch (misc_reg) { + case MISCREG_FPCR: + fpcr = val; + return; + case MISCREG_UNIQ: + uniq = val; + return; + case MISCREG_LOCKFLAG: + lock_flag = val; + return; + case MISCREG_LOCKADDR: + lock_addr = val; + return; + case MISCREG_INTR: + intr_flag = val; + return; + default: + assert(misc_reg < NumInternalProcRegs); + ipr[misc_reg] = val; + return; } +} - void - MiscRegFile::setReg(int misc_reg, const MiscReg &val, - ThreadContext *tc) - { - switch(misc_reg) { - case MISCREG_FPCR: - fpcr = val; - return; - case MISCREG_UNIQ: - uniq = val; - return; - case MISCREG_LOCKFLAG: - lock_flag = val; - return; - case MISCREG_LOCKADDR: - lock_addr = val; - return; - case MISCREG_INTR: - intr_flag = val; - return; - default: - setIpr(misc_reg, val, tc); - return; - } +void +MiscRegFile::setReg(int misc_reg, const MiscReg &val, ThreadContext *tc) +{ + switch (misc_reg) { + case MISCREG_FPCR: + fpcr = val; + return; + case MISCREG_UNIQ: + uniq = val; + return; + case MISCREG_LOCKFLAG: + lock_flag = val; + return; + case MISCREG_LOCKADDR: + lock_addr = val; + return; + case MISCREG_INTR: + intr_flag = val; + return; + default: + setIpr(misc_reg, val, tc); + return; } - } + +} // namespace AlphaISA diff --git a/src/arch/alpha/miscregfile.hh b/src/arch/alpha/miscregfile.hh index 022b6404a..6105ce683 100644 --- a/src/arch/alpha/miscregfile.hh +++ b/src/arch/alpha/miscregfile.hh @@ -32,85 +32,79 @@ #ifndef __ARCH_ALPHA_MISCREGFILE_HH__ #define __ARCH_ALPHA_MISCREGFILE_HH__ +#include <iosfwd> + #include "arch/alpha/ipr.hh" #include "arch/alpha/types.hh" #include "sim/host.hh" #include "sim/serialize.hh" -#include <iostream> - class Checkpoint; class ThreadContext; -namespace AlphaISA -{ - enum MiscRegIndex - { - MISCREG_FPCR = NumInternalProcRegs, - MISCREG_UNIQ, - MISCREG_LOCKFLAG, - MISCREG_LOCKADDR, - MISCREG_INTR - }; - - static inline std::string getMiscRegName(RegIndex) - { - return ""; - } - - class MiscRegFile { - protected: - uint64_t fpcr; // floating point condition codes - uint64_t uniq; // process-unique register - bool lock_flag; // lock flag for LL/SC - Addr lock_addr; // lock address for LL/SC - int intr_flag; - - public: - MiscRegFile() - { - initializeIprTable(); - } +namespace AlphaISA { - MiscReg readRegNoEffect(int misc_reg); - - MiscReg readReg(int misc_reg, ThreadContext *tc); +enum MiscRegIndex +{ + MISCREG_FPCR = NumInternalProcRegs, + MISCREG_UNIQ, + MISCREG_LOCKFLAG, + MISCREG_LOCKADDR, + MISCREG_INTR +}; + +class MiscRegFile +{ + public: + friend class RegFile; + typedef uint64_t InternalProcReg; - //These functions should be removed once the simplescalar cpu model - //has been replaced. - int getInstAsid(); - int getDataAsid(); + protected: + uint64_t fpcr; // floating point condition codes + uint64_t uniq; // process-unique register + bool lock_flag; // lock flag for LL/SC + Addr lock_addr; // lock address for LL/SC + int intr_flag; - void setRegNoEffect(int misc_reg, const MiscReg &val); + InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs - void setReg(int misc_reg, const MiscReg &val, - ThreadContext *tc); + protected: + InternalProcReg readIpr(int idx, ThreadContext *tc); + void setIpr(int idx, InternalProcReg val, ThreadContext *tc); - void clear() - { - fpcr = uniq = 0; - lock_flag = 0; - lock_addr = 0; - intr_flag = 0; - } + public: + MiscRegFile() + { + initializeIprTable(); + } - void serialize(std::ostream &os); + // These functions should be removed once the simplescalar cpu + // model has been replaced. + int getInstAsid(); + int getDataAsid(); - void unserialize(Checkpoint *cp, const std::string §ion); - protected: - typedef uint64_t InternalProcReg; + MiscReg readRegNoEffect(int misc_reg); + MiscReg readReg(int misc_reg, ThreadContext *tc); - InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs + void setRegNoEffect(int misc_reg, const MiscReg &val); + void setReg(int misc_reg, const MiscReg &val, ThreadContext *tc); - private: - InternalProcReg readIpr(int idx, ThreadContext *tc); + void + clear() + { + fpcr = 0; + uniq = 0; + lock_flag = 0; + lock_addr = 0; + intr_flag = 0; + } - void setIpr(int idx, InternalProcReg val, ThreadContext *tc); - friend class RegFile; - }; + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); +}; - void copyIprs(ThreadContext *src, ThreadContext *dest); +void copyIprs(ThreadContext *src, ThreadContext *dest); -} +} // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_MISCREGFILE_HH__ diff --git a/src/arch/alpha/mmaped_ipr.hh b/src/arch/alpha/mmaped_ipr.hh index 2b4ba8745..af2469ca7 100644 --- a/src/arch/alpha/mmaped_ipr.hh +++ b/src/arch/alpha/mmaped_ipr.hh @@ -39,9 +39,8 @@ #include "mem/packet.hh" +namespace AlphaISA { -namespace AlphaISA -{ inline Tick handleIprRead(ThreadContext *xc, Packet *pkt) { @@ -58,4 +57,4 @@ handleIprWrite(ThreadContext *xc, Packet *pkt) } // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_MMAPED_IPR_HH__ diff --git a/src/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc index ed1d255a6..58a3d31eb 100644 --- a/src/arch/alpha/osfpal.cc +++ b/src/arch/alpha/osfpal.cc @@ -30,275 +30,273 @@ #include "arch/alpha/osfpal.hh" -namespace { - const char *strings[PAL::NumCodes] = { +const char * +PAL::name(int index) +{ + static const char *strings[PAL::NumCodes] = { // Priviledged PAL instructions - "halt", // 0x00 - "cflush", // 0x01 - "draina", // 0x02 - 0, // 0x03 - 0, // 0x04 - 0, // 0x05 - 0, // 0x06 - 0, // 0x07 - 0, // 0x08 - "cserve", // 0x09 - "swppal", // 0x0a - 0, // 0x0b - 0, // 0x0c - "wripir", // 0x0d - 0, // 0x0e - 0, // 0x0f - "rdmces", // 0x10 - "wrmces", // 0x11 - 0, // 0x12 - 0, // 0x13 - 0, // 0x14 - 0, // 0x15 - 0, // 0x16 - 0, // 0x17 - 0, // 0x18 - 0, // 0x19 - 0, // 0x1a - 0, // 0x1b - 0, // 0x1c - 0, // 0x1d - 0, // 0x1e - 0, // 0x1f - 0, // 0x20 - 0, // 0x21 - 0, // 0x22 - 0, // 0x23 - 0, // 0x24 - 0, // 0x25 - 0, // 0x26 - 0, // 0x27 - 0, // 0x28 - 0, // 0x29 - 0, // 0x2a - "wrfen", // 0x2b - 0, // 0x2c - "wrvptptr", // 0x2d - 0, // 0x2e - 0, // 0x2f - "swpctx", // 0x30 - "wrval", // 0x31 - "rdval", // 0x32 - "tbi", // 0x33 - "wrent", // 0x34 - "swpipl", // 0x35 - "rdps", // 0x36 - "wrkgp", // 0x37 - "wrusp", // 0x38 - "wrperfmon", // 0x39 - "rdusp", // 0x3a - 0, // 0x3b - "whami", // 0x3c - "retsys", // 0x3d - "wtint", // 0x3e - "rti", // 0x3f - 0, // 0x40 - 0, // 0x41 - 0, // 0x42 - 0, // 0x43 - 0, // 0x44 - 0, // 0x45 - 0, // 0x46 - 0, // 0x47 - 0, // 0x48 - 0, // 0x49 - 0, // 0x4a - 0, // 0x4b - 0, // 0x4c - 0, // 0x4d - 0, // 0x4e - 0, // 0x4f - 0, // 0x50 - 0, // 0x51 - 0, // 0x52 - 0, // 0x53 - 0, // 0x54 - 0, // 0x55 - 0, // 0x56 - 0, // 0x57 - 0, // 0x58 - 0, // 0x59 - 0, // 0x5a - 0, // 0x5b - 0, // 0x5c - 0, // 0x5d - 0, // 0x5e - 0, // 0x5f - 0, // 0x60 - 0, // 0x61 - 0, // 0x62 - 0, // 0x63 - 0, // 0x64 - 0, // 0x65 - 0, // 0x66 - 0, // 0x67 - 0, // 0x68 - 0, // 0x69 - 0, // 0x6a - 0, // 0x6b - 0, // 0x6c - 0, // 0x6d - 0, // 0x6e - 0, // 0x6f - 0, // 0x70 - 0, // 0x71 - 0, // 0x72 - 0, // 0x73 - 0, // 0x74 - 0, // 0x75 - 0, // 0x76 - 0, // 0x77 - 0, // 0x78 - 0, // 0x79 - 0, // 0x7a - 0, // 0x7b - 0, // 0x7c - 0, // 0x7d - 0, // 0x7e - 0, // 0x7f + "halt", // 0x00 + "cflush", // 0x01 + "draina", // 0x02 + 0, // 0x03 + 0, // 0x04 + 0, // 0x05 + 0, // 0x06 + 0, // 0x07 + 0, // 0x08 + "cserve", // 0x09 + "swppal", // 0x0a + 0, // 0x0b + 0, // 0x0c + "wripir", // 0x0d + 0, // 0x0e + 0, // 0x0f + "rdmces", // 0x10 + "wrmces", // 0x11 + 0, // 0x12 + 0, // 0x13 + 0, // 0x14 + 0, // 0x15 + 0, // 0x16 + 0, // 0x17 + 0, // 0x18 + 0, // 0x19 + 0, // 0x1a + 0, // 0x1b + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + 0, // 0x20 + 0, // 0x21 + 0, // 0x22 + 0, // 0x23 + 0, // 0x24 + 0, // 0x25 + 0, // 0x26 + 0, // 0x27 + 0, // 0x28 + 0, // 0x29 + 0, // 0x2a + "wrfen", // 0x2b + 0, // 0x2c + "wrvptptr", // 0x2d + 0, // 0x2e + 0, // 0x2f + "swpctx", // 0x30 + "wrval", // 0x31 + "rdval", // 0x32 + "tbi", // 0x33 + "wrent", // 0x34 + "swpipl", // 0x35 + "rdps", // 0x36 + "wrkgp", // 0x37 + "wrusp", // 0x38 + "wrperfmon", // 0x39 + "rdusp", // 0x3a + 0, // 0x3b + "whami", // 0x3c + "retsys", // 0x3d + "wtint", // 0x3e + "rti", // 0x3f + 0, // 0x40 + 0, // 0x41 + 0, // 0x42 + 0, // 0x43 + 0, // 0x44 + 0, // 0x45 + 0, // 0x46 + 0, // 0x47 + 0, // 0x48 + 0, // 0x49 + 0, // 0x4a + 0, // 0x4b + 0, // 0x4c + 0, // 0x4d + 0, // 0x4e + 0, // 0x4f + 0, // 0x50 + 0, // 0x51 + 0, // 0x52 + 0, // 0x53 + 0, // 0x54 + 0, // 0x55 + 0, // 0x56 + 0, // 0x57 + 0, // 0x58 + 0, // 0x59 + 0, // 0x5a + 0, // 0x5b + 0, // 0x5c + 0, // 0x5d + 0, // 0x5e + 0, // 0x5f + 0, // 0x60 + 0, // 0x61 + 0, // 0x62 + 0, // 0x63 + 0, // 0x64 + 0, // 0x65 + 0, // 0x66 + 0, // 0x67 + 0, // 0x68 + 0, // 0x69 + 0, // 0x6a + 0, // 0x6b + 0, // 0x6c + 0, // 0x6d + 0, // 0x6e + 0, // 0x6f + 0, // 0x70 + 0, // 0x71 + 0, // 0x72 + 0, // 0x73 + 0, // 0x74 + 0, // 0x75 + 0, // 0x76 + 0, // 0x77 + 0, // 0x78 + 0, // 0x79 + 0, // 0x7a + 0, // 0x7b + 0, // 0x7c + 0, // 0x7d + 0, // 0x7e + 0, // 0x7f // Unpriviledged PAL instructions - "bpt", // 0x80 - "bugchk", // 0x81 - 0, // 0x82 - "callsys", // 0x83 - 0, // 0x84 - 0, // 0x85 - "imb", // 0x86 - 0, // 0x87 - 0, // 0x88 - 0, // 0x89 - 0, // 0x8a - 0, // 0x8b - 0, // 0x8c - 0, // 0x8d - 0, // 0x8e - 0, // 0x8f - 0, // 0x90 - 0, // 0x91 - "urti", // 0x92 - 0, // 0x93 - 0, // 0x94 - 0, // 0x95 - 0, // 0x96 - 0, // 0x97 - 0, // 0x98 - 0, // 0x99 - 0, // 0x9a - 0, // 0x9b - 0, // 0x9c - 0, // 0x9d - "rdunique", // 0x9e - "wrunique", // 0x9f - 0, // 0xa0 - 0, // 0xa1 - 0, // 0xa2 - 0, // 0xa3 - 0, // 0xa4 - 0, // 0xa5 - 0, // 0xa6 - 0, // 0xa7 - 0, // 0xa8 - 0, // 0xa9 - "gentrap", // 0xaa - 0, // 0xab - 0, // 0xac - 0, // 0xad - "clrfen", // 0xae - 0, // 0xaf - 0, // 0xb0 - 0, // 0xb1 - 0, // 0xb2 - 0, // 0xb3 - 0, // 0xb4 - 0, // 0xb5 - 0, // 0xb6 - 0, // 0xb7 - 0, // 0xb8 - 0, // 0xb9 - 0, // 0xba - 0, // 0xbb - 0, // 0xbc - 0, // 0xbd - "nphalt", // 0xbe - "copypal", // 0xbf + "bpt", // 0x80 + "bugchk", // 0x81 + 0, // 0x82 + "callsys", // 0x83 + 0, // 0x84 + 0, // 0x85 + "imb", // 0x86 + 0, // 0x87 + 0, // 0x88 + 0, // 0x89 + 0, // 0x8a + 0, // 0x8b + 0, // 0x8c + 0, // 0x8d + 0, // 0x8e + 0, // 0x8f + 0, // 0x90 + 0, // 0x91 + "urti", // 0x92 + 0, // 0x93 + 0, // 0x94 + 0, // 0x95 + 0, // 0x96 + 0, // 0x97 + 0, // 0x98 + 0, // 0x99 + 0, // 0x9a + 0, // 0x9b + 0, // 0x9c + 0, // 0x9d + "rdunique", // 0x9e + "wrunique", // 0x9f + 0, // 0xa0 + 0, // 0xa1 + 0, // 0xa2 + 0, // 0xa3 + 0, // 0xa4 + 0, // 0xa5 + 0, // 0xa6 + 0, // 0xa7 + 0, // 0xa8 + 0, // 0xa9 + "gentrap", // 0xaa + 0, // 0xab + 0, // 0xac + 0, // 0xad + "clrfen", // 0xae + 0, // 0xaf + 0, // 0xb0 + 0, // 0xb1 + 0, // 0xb2 + 0, // 0xb3 + 0, // 0xb4 + 0, // 0xb5 + 0, // 0xb6 + 0, // 0xb7 + 0, // 0xb8 + 0, // 0xb9 + 0, // 0xba + 0, // 0xbb + 0, // 0xbc + 0, // 0xbd + "nphalt", // 0xbe + "copypal", // 0xbf #if 0 - 0, // 0xc0 - 0, // 0xc1 - 0, // 0xc2 - 0, // 0xc3 - 0, // 0xc4 - 0, // 0xc5 - 0, // 0xc6 - 0, // 0xc7 - 0, // 0xc8 - 0, // 0xc9 - 0, // 0xca - 0, // 0xcb - 0, // 0xcc - 0, // 0xcd - 0, // 0xce - 0, // 0xcf - 0, // 0xd0 - 0, // 0xd1 - 0, // 0xd2 - 0, // 0xd3 - 0, // 0xd4 - 0, // 0xd5 - 0, // 0xd6 - 0, // 0xd7 - 0, // 0xd8 - 0, // 0xd9 - 0, // 0xda - 0, // 0xdb - 0, // 0xdc - 0, // 0xdd - 0, // 0xde - 0, // 0xdf - 0, // 0xe0 - 0, // 0xe1 - 0, // 0xe2 - 0, // 0xe3 - 0, // 0xe4 - 0, // 0xe5 - 0, // 0xe6 - 0, // 0xe7 - 0, // 0xe8 - 0, // 0xe9 - 0, // 0xea - 0, // 0xeb - 0, // 0xec - 0, // 0xed - 0, // 0xee - 0, // 0xef - 0, // 0xf0 - 0, // 0xf1 - 0, // 0xf2 - 0, // 0xf3 - 0, // 0xf4 - 0, // 0xf5 - 0, // 0xf6 - 0, // 0xf7 - 0, // 0xf8 - 0, // 0xf9 - 0, // 0xfa - 0, // 0xfb - 0, // 0xfc - 0, // 0xfd - 0, // 0xfe - 0 // 0xff + 0, // 0xc0 + 0, // 0xc1 + 0, // 0xc2 + 0, // 0xc3 + 0, // 0xc4 + 0, // 0xc5 + 0, // 0xc6 + 0, // 0xc7 + 0, // 0xc8 + 0, // 0xc9 + 0, // 0xca + 0, // 0xcb + 0, // 0xcc + 0, // 0xcd + 0, // 0xce + 0, // 0xcf + 0, // 0xd0 + 0, // 0xd1 + 0, // 0xd2 + 0, // 0xd3 + 0, // 0xd4 + 0, // 0xd5 + 0, // 0xd6 + 0, // 0xd7 + 0, // 0xd8 + 0, // 0xd9 + 0, // 0xda + 0, // 0xdb + 0, // 0xdc + 0, // 0xdd + 0, // 0xde + 0, // 0xdf + 0, // 0xe0 + 0, // 0xe1 + 0, // 0xe2 + 0, // 0xe3 + 0, // 0xe4 + 0, // 0xe5 + 0, // 0xe6 + 0, // 0xe7 + 0, // 0xe8 + 0, // 0xe9 + 0, // 0xea + 0, // 0xeb + 0, // 0xec + 0, // 0xed + 0, // 0xee + 0, // 0xef + 0, // 0xf0 + 0, // 0xf1 + 0, // 0xf2 + 0, // 0xf3 + 0, // 0xf4 + 0, // 0xf5 + 0, // 0xf6 + 0, // 0xf7 + 0, // 0xf8 + 0, // 0xf9 + 0, // 0xfa + 0, // 0xfb + 0, // 0xfc + 0, // 0xfd + 0, // 0xfe + 0 // 0xff #endif }; -} -const char * -PAL::name(int index) -{ if (index > NumCodes || index < 0) return 0; diff --git a/src/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh index cf3940b85..2618e9dbd 100644 --- a/src/arch/alpha/osfpal.hh +++ b/src/arch/alpha/osfpal.hh @@ -28,8 +28,8 @@ * Authors: Nathan Binkert */ -#ifndef __OSFPAL_HH__ -#define __OSFPAL_HH__ +#ifndef __ARCH_ALPHA_OSFPAL_HH__ +#define __ARCH_ALPHA_OSFPAL_HH__ struct PAL { @@ -79,4 +79,4 @@ struct PAL static const char *name(int index); }; -#endif // __OSFPAL_HH__ +#endif // __ARCH_ALPHA_OSFPAL_HH__ diff --git a/src/arch/alpha/pagetable.cc b/src/arch/alpha/pagetable.cc index 3f9537834..6640e72e2 100644 --- a/src/arch/alpha/pagetable.cc +++ b/src/arch/alpha/pagetable.cc @@ -31,33 +31,34 @@ #include "arch/alpha/pagetable.hh" #include "sim/serialize.hh" -namespace AlphaISA +namespace AlphaISA { + +void +TlbEntry::serialize(std::ostream &os) { - void - TlbEntry::serialize(std::ostream &os) - { - SERIALIZE_SCALAR(tag); - SERIALIZE_SCALAR(ppn); - SERIALIZE_SCALAR(xre); - SERIALIZE_SCALAR(xwe); - SERIALIZE_SCALAR(asn); - SERIALIZE_SCALAR(asma); - SERIALIZE_SCALAR(fonr); - SERIALIZE_SCALAR(fonw); - SERIALIZE_SCALAR(valid); - } + SERIALIZE_SCALAR(tag); + SERIALIZE_SCALAR(ppn); + SERIALIZE_SCALAR(xre); + SERIALIZE_SCALAR(xwe); + SERIALIZE_SCALAR(asn); + SERIALIZE_SCALAR(asma); + SERIALIZE_SCALAR(fonr); + SERIALIZE_SCALAR(fonw); + SERIALIZE_SCALAR(valid); +} - void - TlbEntry::unserialize(Checkpoint *cp, const std::string §ion) - { - UNSERIALIZE_SCALAR(tag); - UNSERIALIZE_SCALAR(ppn); - UNSERIALIZE_SCALAR(xre); - UNSERIALIZE_SCALAR(xwe); - UNSERIALIZE_SCALAR(asn); - UNSERIALIZE_SCALAR(asma); - UNSERIALIZE_SCALAR(fonr); - UNSERIALIZE_SCALAR(fonw); - UNSERIALIZE_SCALAR(valid); - } +void +TlbEntry::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(tag); + UNSERIALIZE_SCALAR(ppn); + UNSERIALIZE_SCALAR(xre); + UNSERIALIZE_SCALAR(xwe); + UNSERIALIZE_SCALAR(asn); + UNSERIALIZE_SCALAR(asma); + UNSERIALIZE_SCALAR(fonr); + UNSERIALIZE_SCALAR(fonw); + UNSERIALIZE_SCALAR(valid); } + +} //namespace AlphaISA diff --git a/src/arch/alpha/pagetable.hh b/src/arch/alpha/pagetable.hh index 8ce5b4e5d..59df93bef 100644 --- a/src/arch/alpha/pagetable.hh +++ b/src/arch/alpha/pagetable.hh @@ -38,97 +38,109 @@ namespace AlphaISA { - struct VAddr +struct VAddr +{ + static const int ImplBits = 43; + static const Addr ImplMask = (ULL(1) << ImplBits) - 1; + static const Addr UnImplMask = ~ImplMask; + + Addr addr; + + VAddr(Addr a) : addr(a) {} + operator Addr() const { return addr; } + const VAddr &operator=(Addr a) { addr = a; return *this; } + + Addr vpn() const { return (addr & ImplMask) >> PageShift; } + Addr page() const { return addr & PageMask; } + Addr offset() const { return addr & PageOffset; } + + Addr level3() const + { return PteAddr(addr >> PageShift); } + Addr level2() const + { return PteAddr(addr >> (NPtePageShift + PageShift)); } + Addr level1() const + { return PteAddr(addr >> (2 * NPtePageShift + PageShift)); } +}; + +struct PageTableEntry +{ + PageTableEntry(uint64_t e) : entry(e) {} + uint64_t entry; + operator uint64_t() const { return entry; } + const PageTableEntry &operator=(uint64_t e) { entry = e; return *this; } + const PageTableEntry &operator=(const PageTableEntry &e) + { entry = e.entry; return *this; } + + Addr _pfn() const { return (entry >> 32) & 0xffffffff; } + Addr _sw() const { return (entry >> 16) & 0xffff; } + int _rsv0() const { return (entry >> 14) & 0x3; } + bool _uwe() const { return (entry >> 13) & 0x1; } + bool _kwe() const { return (entry >> 12) & 0x1; } + int _rsv1() const { return (entry >> 10) & 0x3; } + bool _ure() const { return (entry >> 9) & 0x1; } + bool _kre() const { return (entry >> 8) & 0x1; } + bool _nomb() const { return (entry >> 7) & 0x1; } + int _gh() const { return (entry >> 5) & 0x3; } + bool _asm_() const { return (entry >> 4) & 0x1; } + bool _foe() const { return (entry >> 3) & 0x1; } + bool _fow() const { return (entry >> 2) & 0x1; } + bool _for() const { return (entry >> 1) & 0x1; } + bool valid() const { return (entry >> 0) & 0x1; } + + Addr paddr() const { return _pfn() << PageShift; } +}; + +// ITB/DTB table entry +struct TlbEntry +{ + Addr tag; // virtual page number tag + Addr ppn; // physical page number + uint8_t xre; // read permissions - VMEM_PERM_* mask + uint8_t xwe; // write permissions - VMEM_PERM_* mask + uint8_t asn; // address space number + bool asma; // address space match + bool fonr; // fault on read + bool fonw; // fault on write + bool valid; // valid page table entry + + + //Construct an entry that maps to physical address addr. + TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr) { - static const int ImplBits = 43; - static const Addr ImplMask = (ULL(1) << ImplBits) - 1; - static const Addr UnImplMask = ~ImplMask; - - VAddr(Addr a) : addr(a) {} - Addr addr; - operator Addr() const { return addr; } - const VAddr &operator=(Addr a) { addr = a; return *this; } - - Addr vpn() const { return (addr & ImplMask) >> PageShift; } - Addr page() const { return addr & PageMask; } - Addr offset() const { return addr & PageOffset; } - - Addr level3() const - { return AlphaISA::PteAddr(addr >> PageShift); } - Addr level2() const - { return AlphaISA::PteAddr(addr >> NPtePageShift + PageShift); } - Addr level1() const - { return AlphaISA::PteAddr(addr >> 2 * NPtePageShift + PageShift); } - }; - - struct PageTableEntry + VAddr vaddr(_vaddr); + VAddr paddr(_paddr); + tag = vaddr.vpn(); + ppn = paddr.vpn(); + xre = 15; + xwe = 15; + asn = _asn; + asma = false; + fonr = false; + fonw = false; + valid = true; + } + + TlbEntry() + {} + + void + updateVaddr(Addr new_vaddr) { - PageTableEntry(uint64_t e) : entry(e) {} - uint64_t entry; - operator uint64_t() const { return entry; } - const PageTableEntry &operator=(uint64_t e) { entry = e; return *this; } - const PageTableEntry &operator=(const PageTableEntry &e) - { entry = e.entry; return *this; } - - Addr _pfn() const { return (entry >> 32) & 0xffffffff; } - Addr _sw() const { return (entry >> 16) & 0xffff; } - int _rsv0() const { return (entry >> 14) & 0x3; } - bool _uwe() const { return (entry >> 13) & 0x1; } - bool _kwe() const { return (entry >> 12) & 0x1; } - int _rsv1() const { return (entry >> 10) & 0x3; } - bool _ure() const { return (entry >> 9) & 0x1; } - bool _kre() const { return (entry >> 8) & 0x1; } - bool _nomb() const { return (entry >> 7) & 0x1; } - int _gh() const { return (entry >> 5) & 0x3; } - bool _asm_() const { return (entry >> 4) & 0x1; } - bool _foe() const { return (entry >> 3) & 0x1; } - bool _fow() const { return (entry >> 2) & 0x1; } - bool _for() const { return (entry >> 1) & 0x1; } - bool valid() const { return (entry >> 0) & 0x1; } - - Addr paddr() const { return _pfn() << PageShift; } - }; - - // ITB/DTB table entry - struct TlbEntry + VAddr vaddr(new_vaddr); + tag = vaddr.vpn(); + } + + Addr + pageStart() { - //Construct an entry that maps to physical address addr. - TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr) - { - VAddr vaddr(_vaddr); - VAddr paddr(_paddr); - tag = vaddr.vpn(); - ppn = paddr.vpn(); - xre = 15; - xwe = 15; - asn = _asn; - asma = false; - fonr = false; - fonw = false; - valid = true; - } - TlbEntry() - {} - - Addr tag; // virtual page number tag - Addr ppn; // physical page number - uint8_t xre; // read permissions - VMEM_PERM_* mask - uint8_t xwe; // write permissions - VMEM_PERM_* mask - uint8_t asn; // address space number - bool asma; // address space match - bool fonr; // fault on read - bool fonw; // fault on write - bool valid; // valid page table entry - - Addr pageStart() - { - return ppn << PageShift; - } - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; + return ppn << PageShift; + } + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); }; + +} // namespace AlphaISA + #endif // __ARCH_ALPHA_PAGETABLE_H__ diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh index 725b35b9d..5502342e1 100644 --- a/src/arch/alpha/predecoder.hh +++ b/src/arch/alpha/predecoder.hh @@ -38,62 +38,72 @@ class ThreadContext; -namespace AlphaISA +namespace AlphaISA { + +class Predecoder { - class Predecoder + protected: + ThreadContext *tc; + + // The extended machine instruction being generated + ExtMachInst ext_inst; + + public: + Predecoder(ThreadContext * _tc) + : tc(_tc) + {} + + ThreadContext * + getTC() { - protected: - ThreadContext * tc; - //The extended machine instruction being generated - ExtMachInst ext_inst; - - public: - Predecoder(ThreadContext * _tc) : tc(_tc) - {} - - ThreadContext * getTC() - { - return tc; - } - - void setTC(ThreadContext * _tc) - { - tc = _tc; - } - - void process() - { - } - - void reset() - {} - - //Use this to give data to the predecoder. This should be used - //when there is control flow. - void moreBytes(Addr pc, Addr fetchPC, MachInst inst) - { - ext_inst = inst; + return tc; + } + + void + setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void + process() + { } + + void + reset() + { } + + // Use this to give data to the predecoder. This should be used + // when there is control flow. + void + moreBytes(Addr pc, Addr fetchPC, MachInst inst) + { + ext_inst = inst; #if FULL_SYSTEM - ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); + ext_inst |= (static_cast<ExtMachInst>(pc & 0x1) << 32); #endif - } - - bool needMoreBytes() - { - return true; - } - - bool extMachInstReady() - { - return true; - } - - //This returns a constant reference to the ExtMachInst to avoid a copy - const ExtMachInst & getExtMachInst() - { - return ext_inst; - } - }; + } + + bool + needMoreBytes() + { + return true; + } + + bool + extMachInstReady() + { + return true; + } + + // This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & + getExtMachInst() + { + return ext_inst; + } }; +} // namespace AlphaISA + #endif // __ARCH_ALPHA_PREDECODER_HH__ diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc index c2d23ecdd..9c6e62815 100644 --- a/src/arch/alpha/process.cc +++ b/src/arch/alpha/process.cc @@ -32,16 +32,20 @@ #include "arch/alpha/isa_traits.hh" #include "arch/alpha/process.hh" #include "base/loader/object_file.hh" +#include "base/loader/elf_object.hh" #include "base/misc.hh" #include "cpu/thread_context.hh" +#include "mem/page_table.hh" +#include "sim/process_impl.hh" #include "sim/system.hh" - using namespace AlphaISA; using namespace std; -AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams * params, - ObjectFile *objFile) +static const int SyscallSuccessReg = 19; + +AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams *params, + ObjectFile *objFile) : LiveProcess(params, objFile) { brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); @@ -61,20 +65,165 @@ AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams * params, } void +AlphaLiveProcess::argsInit(int intSize, int pageSize) +{ + objFile->loadSections(initVirtMem); + + typedef AuxVector<uint64_t> auxv_t; + std::vector<auxv_t> auxv; + + ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile); + if(elfObject) + { + // modern glibc uses a bunch of auxiliary vectors to set up + // TLS as well as do a bunch of other stuff + // these vectors go on the bottom of the stack, below argc/argv/envp + // pointers but above actual arg strings + // I don't have all the ones glibc looks at here, but so far it doesn't + // seem to be a problem. + // check out _dl_aux_init() in glibc/elf/dl-support.c for details + // --Lisa + auxv.push_back(auxv_t(M5_AT_PAGESZ, AlphaISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); + DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable()); + auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); + + } + + // Calculate how much space we need for arg & env & auxv arrays. + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + int auxv_array_size = intSize * 2 * (auxv.size() + 1); + + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + + int space_needed = + argv_array_size + + envp_array_size + + auxv_array_size + + arg_data_size + + env_data_size; + + if (space_needed < 32*1024) + space_needed = 32*1024; + + // set bottom of stack + stack_min = stack_base - space_needed; + // align it + stack_min = roundDown(stack_min, pageSize); + stack_size = stack_base - stack_min; + // map memory + pTable->allocate(stack_min, roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr argv_array_base = stack_min + intSize; // room for argc + Addr envp_array_base = argv_array_base + argv_array_size; + Addr auxv_array_base = envp_array_base + envp_array_size; + Addr arg_data_base = auxv_array_base + auxv_array_size; + Addr env_data_base = arg_data_base + arg_data_size; + + // write contents to stack + uint64_t argc = argv.size(); + if (intSize == 8) + argc = htog((uint64_t)argc); + else if (intSize == 4) + argc = htog((uint32_t)argc); + else + panic("Unknown int size"); + + initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); + + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + + //Copy the aux stuff + for(int x = 0; x < auxv.size(); x++) + { + initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize, + (uint8_t*)&(auxv[x].a_type), intSize); + initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, + (uint8_t*)&(auxv[x].a_val), intSize); + } + + ThreadContext *tc = system->getThreadContext(contextIds[0]); + + setSyscallArg(tc, 0, argc); + setSyscallArg(tc, 1, argv_array_base); + tc->setIntReg(StackPointerReg, stack_min); + + Addr prog_entry = objFile->entryPoint(); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); + +#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc + tc->setNextNPC(prog_entry + (2 * sizeof(MachInst))); +#endif + + +} + +void AlphaLiveProcess::startup() { if (checkpointRestored) return; + Process::startup(); + argsInit(MachineBytes, VMPageSize); - threadContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer()); - //Opperate in user mode - threadContexts[0]->setMiscRegNoEffect(IPR_ICM, 0x18); + ThreadContext *tc = system->getThreadContext(contextIds[0]); + tc->setIntReg(GlobalPointerReg, objFile->globalPointer()); + //Operate in user mode + tc->setMiscRegNoEffect(IPR_ICM, 0x18); //No super page mapping - threadContexts[0]->setMiscRegNoEffect(IPR_MCSR, 0); + tc->setMiscRegNoEffect(IPR_MCSR, 0); //Set this to 0 for now, but it should be unique for each process - threadContexts[0]->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57); + tc->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57); } +AlphaISA::IntReg +AlphaLiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < 6); + return tc->readIntReg(FirstArgumentReg + i); +} + +void +AlphaLiveProcess::setSyscallArg(ThreadContext *tc, + int i, AlphaISA::IntReg val) +{ + assert(i < 6); + tc->setIntReg(FirstArgumentReg + i, val); +} +void +AlphaLiveProcess::setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) +{ + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + tc->setIntReg(SyscallSuccessReg, 0); + tc->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, return details + tc->setIntReg(SyscallSuccessReg, (IntReg)-1); + tc->setIntReg(ReturnValueReg, -return_value.value()); + } +} diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh index c66b97d23..6d083c5ac 100644 --- a/src/arch/alpha/process.hh +++ b/src/arch/alpha/process.hh @@ -29,24 +29,24 @@ * Ali Saidi */ -#ifndef __ALPHA_PROCESS_HH__ -#define __ALPHA_PROCESS_HH__ +#ifndef __ARCH_ALPHA_PROCESS_HH__ +#define __ARCH_ALPHA_PROCESS_HH__ -#include <string> -#include <vector> #include "sim/process.hh" -class ObjectFile; -class System; - - class AlphaLiveProcess : public LiveProcess { protected: - AlphaLiveProcess(LiveProcessParams * params, ObjectFile *objFile); + AlphaLiveProcess(LiveProcessParams *params, ObjectFile *objFile); void startup(); -}; + void argsInit(int intSize, int pageSize); + + public: + AlphaISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val); + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); +}; -#endif // __ALPHA_PROCESS_HH__ +#endif // __ARCH_ALPHA_PROCESS_HH__ diff --git a/src/arch/alpha/regfile.cc b/src/arch/alpha/regfile.cc index 2653310d7..b3aa55b19 100644 --- a/src/arch/alpha/regfile.cc +++ b/src/arch/alpha/regfile.cc @@ -33,67 +33,68 @@ #include "arch/alpha/regfile.hh" #include "cpu/thread_context.hh" -namespace AlphaISA +using namespace std; + +namespace AlphaISA { + +void +RegFile::serialize(EventManager *em, ostream &os) { - void - RegFile::serialize(std::ostream &os) - { - intRegFile.serialize(os); - floatRegFile.serialize(os); - miscRegFile.serialize(os); - SERIALIZE_SCALAR(pc); - SERIALIZE_SCALAR(npc); + intRegFile.serialize(os); + floatRegFile.serialize(os); + miscRegFile.serialize(os); + SERIALIZE_SCALAR(pc); + SERIALIZE_SCALAR(npc); #if FULL_SYSTEM - SERIALIZE_SCALAR(intrflag); + SERIALIZE_SCALAR(intrflag); #endif - } +} - void - RegFile::unserialize(Checkpoint *cp, const std::string §ion) - { - intRegFile.unserialize(cp, section); - floatRegFile.unserialize(cp, section); - miscRegFile.unserialize(cp, section); - UNSERIALIZE_SCALAR(pc); - UNSERIALIZE_SCALAR(npc); +void +RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) +{ + intRegFile.unserialize(cp, section); + floatRegFile.unserialize(cp, section); + miscRegFile.unserialize(cp, section); + UNSERIALIZE_SCALAR(pc); + UNSERIALIZE_SCALAR(npc); #if FULL_SYSTEM - UNSERIALIZE_SCALAR(intrflag); + UNSERIALIZE_SCALAR(intrflag); #endif - } +} - void - copyRegs(ThreadContext *src, ThreadContext *dest) - { - // First loop through the integer registers. - for (int i = 0; i < NumIntRegs; ++i) { - dest->setIntReg(i, src->readIntReg(i)); - } +void +copyRegs(ThreadContext *src, ThreadContext *dest) +{ + // First loop through the integer registers. + for (int i = 0; i < NumIntRegs; ++i) + dest->setIntReg(i, src->readIntReg(i)); - // Then loop through the floating point registers. - for (int i = 0; i < TheISA::NumFloatRegs; ++i) { - dest->setFloatRegBits(i, src->readFloatRegBits(i)); - } + // Then loop through the floating point registers. + for (int i = 0; i < NumFloatRegs; ++i) + dest->setFloatRegBits(i, src->readFloatRegBits(i)); - // Copy misc. registers - copyMiscRegs(src, dest); + // Copy misc. registers + copyMiscRegs(src, dest); - // Lastly copy PC/NPC - dest->setPC(src->readPC()); - dest->setNextPC(src->readNextPC()); - } + // Lastly copy PC/NPC + dest->setPC(src->readPC()); + dest->setNextPC(src->readNextPC()); +} - void - copyMiscRegs(ThreadContext *src, ThreadContext *dest) - { - dest->setMiscRegNoEffect(AlphaISA::MISCREG_FPCR, - src->readMiscRegNoEffect(AlphaISA::MISCREG_FPCR)); - dest->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ, - src->readMiscRegNoEffect(AlphaISA::MISCREG_UNIQ)); - dest->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, - src->readMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG)); - dest->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKADDR, - src->readMiscRegNoEffect(AlphaISA::MISCREG_LOCKADDR)); +void +copyMiscRegs(ThreadContext *src, ThreadContext *dest) +{ + dest->setMiscRegNoEffect(MISCREG_FPCR, + src->readMiscRegNoEffect(MISCREG_FPCR)); + dest->setMiscRegNoEffect(MISCREG_UNIQ, + src->readMiscRegNoEffect(MISCREG_UNIQ)); + dest->setMiscRegNoEffect(MISCREG_LOCKFLAG, + src->readMiscRegNoEffect(MISCREG_LOCKFLAG)); + dest->setMiscRegNoEffect(MISCREG_LOCKADDR, + src->readMiscRegNoEffect(MISCREG_LOCKADDR)); - copyIprs(src, dest); - } + copyIprs(src, dest); } + +} // namespace AlphaISA diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh index 792a518fb..e431e7570 100644 --- a/src/arch/alpha/regfile.hh +++ b/src/arch/alpha/regfile.hh @@ -43,163 +43,187 @@ //XXX These should be implemented by someone who knows the alpha stuff better class Checkpoint; +class EventManager; class ThreadContext; -namespace AlphaISA -{ - - class RegFile { +namespace AlphaISA { - protected: - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; +class RegFile { + protected: + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; // next next-cycle program counter - public: - Addr readPC() - { - return pc; - } - - void setPC(Addr val) - { - pc = val; - } + public: + Addr + readPC() + { + return pc; + } - Addr readNextPC() - { - return npc; - } + void + setPC(Addr val) + { + pc = val; + } - void setNextPC(Addr val) - { - npc = val; - } + Addr + readNextPC() + { + return npc; + } - Addr readNextNPC() - { - return npc + sizeof(MachInst); - } + void + setNextPC(Addr val) + { + npc = val; + } - void setNextNPC(Addr val) - { } + Addr + readNextNPC() + { + return npc + sizeof(MachInst); + } - protected: - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegFile; // control register file + void + setNextNPC(Addr val) + { } - public: + protected: + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + public: #if FULL_SYSTEM - int intrflag; // interrupt flag - inline int instAsid() - { return miscRegFile.getInstAsid(); } - inline int dataAsid() - { return miscRegFile.getDataAsid(); } -#endif // FULL_SYSTEM + int intrflag; // interrupt flag - void clear() - { - intRegFile.clear(); - floatRegFile.clear(); - miscRegFile.clear(); - } - - MiscReg readMiscRegNoEffect(int miscReg) - { - return miscRegFile.readRegNoEffect(miscReg); - } - - MiscReg readMiscReg(int miscReg, ThreadContext *tc) - { - return miscRegFile.readReg(miscReg, tc); - } + int + instAsid() + { + return miscRegFile.getInstAsid(); + } - void setMiscRegNoEffect(int miscReg, const MiscReg &val) - { - miscRegFile.setRegNoEffect(miscReg, val); - } + int + dataAsid() + { + return miscRegFile.getDataAsid(); + } +#endif // FULL_SYSTEM - void setMiscReg(int miscReg, const MiscReg &val, - ThreadContext * tc) - { - miscRegFile.setReg(miscReg, val, tc); - } + void + clear() + { + intRegFile.clear(); + floatRegFile.clear(); + miscRegFile.clear(); + } - FloatReg readFloatReg(int floatReg) - { - return floatRegFile.d[floatReg]; - } + MiscReg + readMiscRegNoEffect(int miscReg) + { + return miscRegFile.readRegNoEffect(miscReg); + } - FloatReg readFloatReg(int floatReg, int width) - { - return readFloatReg(floatReg); - } + MiscReg + readMiscReg(int miscReg, ThreadContext *tc) + { + return miscRegFile.readReg(miscReg, tc); + } - FloatRegBits readFloatRegBits(int floatReg) - { - return floatRegFile.q[floatReg]; - } + void + setMiscRegNoEffect(int miscReg, const MiscReg &val) + { + miscRegFile.setRegNoEffect(miscReg, val); + } - FloatRegBits readFloatRegBits(int floatReg, int width) - { - return readFloatRegBits(floatReg); - } + void + setMiscReg(int miscReg, const MiscReg &val, ThreadContext *tc) + { + miscRegFile.setReg(miscReg, val, tc); + } - void setFloatReg(int floatReg, const FloatReg &val) - { - floatRegFile.d[floatReg] = val; - } + FloatReg + readFloatReg(int floatReg) + { + return floatRegFile.d[floatReg]; + } - void setFloatReg(int floatReg, const FloatReg &val, int width) - { - setFloatReg(floatReg, val); - } + FloatReg + readFloatReg(int floatReg, int width) + { + return readFloatReg(floatReg); + } - void setFloatRegBits(int floatReg, const FloatRegBits &val) - { - floatRegFile.q[floatReg] = val; - } + FloatRegBits + readFloatRegBits(int floatReg) + { + return floatRegFile.q[floatReg]; + } - void setFloatRegBits(int floatReg, const FloatRegBits &val, int width) - { - setFloatRegBits(floatReg, val); - } + FloatRegBits + readFloatRegBits(int floatReg, int width) + { + return readFloatRegBits(floatReg); + } - IntReg readIntReg(int intReg) - { - return intRegFile.readReg(intReg); - } + void + setFloatReg(int floatReg, const FloatReg &val) + { + floatRegFile.d[floatReg] = val; + } - void setIntReg(int intReg, const IntReg &val) - { - intRegFile.setReg(intReg, val); - } + void + setFloatReg(int floatReg, const FloatReg &val, int width) + { + setFloatReg(floatReg, val); + } - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void + setFloatRegBits(int floatReg, const FloatRegBits &val) + { + floatRegFile.q[floatReg] = val; + } - void changeContext(RegContextParam param, RegContextVal val) - { - //This would be an alternative place to call/implement - //the swapPALShadow function - } - }; + void + setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + setFloatRegBits(floatReg, val); + } - static inline int flattenIntIndex(ThreadContext * tc, int reg) + IntReg + readIntReg(int intReg) { - return reg; + return intRegFile.readReg(intReg); } - static inline int flattenFloatIndex(ThreadContext * tc, int reg) + void + setIntReg(int intReg, const IntReg &val) { - return reg; + intRegFile.setReg(intReg, val); } - void copyRegs(ThreadContext *src, ThreadContext *dest); + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); +}; + +static inline int +flattenIntIndex(ThreadContext * tc, int reg) +{ + return reg; +} + +static inline int +flattenFloatIndex(ThreadContext * tc, int reg) +{ + return reg; +} + +void copyRegs(ThreadContext *src, ThreadContext *dest); + +void copyMiscRegs(ThreadContext *src, ThreadContext *dest); - void copyMiscRegs(ThreadContext *src, ThreadContext *dest); } // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_REGFILE_HH__ diff --git a/src/arch/alpha/remote_gdb.cc b/src/arch/alpha/remote_gdb.cc index ea5db36f4..c47293b98 100644 --- a/src/arch/alpha/remote_gdb.cc +++ b/src/arch/alpha/remote_gdb.cc @@ -30,7 +30,7 @@ /* * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and @@ -38,8 +38,8 @@ * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,8 +51,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -69,7 +69,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 */ /*- @@ -89,8 +89,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -117,9 +117,9 @@ */ #include <sys/signal.h> +#include <unistd.h> #include <string> -#include <unistd.h> #include "config/full_system.hh" #if FULL_SYSTEM @@ -140,19 +140,17 @@ #include "sim/system.hh" using namespace std; -using namespace TheISA; +using namespace AlphaISA; -RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) - : BaseRemoteGDB(_system, c, KGDB_NUMREGS) +RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc) + : BaseRemoteGDB(_system, tc, KGDB_NUMREGS) { memset(gdbregs.regs, 0, gdbregs.bytes()); } -/////////////////////////////////////////////////////////// -// RemoteGDB::acc -// -// Determine if the mapping at va..(va+len) is valid. -// +/* + * Determine if the mapping at va..(va+len) is valid. + */ bool RemoteGDB::acc(Addr va, size_t len) { @@ -161,12 +159,12 @@ RemoteGDB::acc(Addr va, size_t len) #else Addr last_va; - va = TheISA::TruncPage(va); - last_va = TheISA::RoundPage(va + len); + va = TruncPage(va); + last_va = RoundPage(va + len); do { - if (TheISA::IsK0Seg(va)) { - if (va < (TheISA::K0SegBase + pmem->size())) { + if (IsK0Seg(va)) { + if (va < (K0SegBase + pmem->size())) { DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " "%#x < K0SEG + size\n", va); return true; @@ -177,23 +175,25 @@ RemoteGDB::acc(Addr va, size_t len) } } - /** - * This code says that all accesses to palcode (instruction and data) - * are valid since there isn't a va->pa mapping because palcode is - * accessed physically. At some point this should probably be cleaned up - * but there is no easy way to do it. - */ + /** + * This code says that all accesses to palcode (instruction + * and data) are valid since there isn't a va->pa mapping + * because palcode is accessed physically. At some point this + * should probably be cleaned up but there is no easy way to + * do it. + */ - if (AlphaISA::PcPAL(va) || va < 0x10000) + if (PcPAL(va) || va < 0x10000) return true; - Addr ptbr = context->readMiscRegNoEffect(AlphaISA::IPR_PALtemp20); - TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va); + Addr ptbr = context->readMiscRegNoEffect(IPR_PALtemp20); + PageTableEntry pte = + kernel_pte_lookup(context->getPhysPort(), ptbr, va); if (!pte.valid()) { DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); return false; } - va += TheISA::PageBytes; + va += PageBytes; } while (va < last_va); DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); @@ -201,11 +201,10 @@ RemoteGDB::acc(Addr va, size_t len) #endif } -/////////////////////////////////////////////////////////// -// RemoteGDB::getregs -// -// Translate the kernel debugger register format into -// the GDB register format. +/* + * Translate the kernel debugger register format into the GDB register + * format. + */ void RemoteGDB::getregs() { @@ -214,45 +213,43 @@ RemoteGDB::getregs() gdbregs.regs[KGDB_REG_PC] = context->readPC(); // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - gdbregs.regs[i] = context->readIntReg(AlphaISA::reg_redir[i]); + if (PcPAL(gdbregs.regs[KGDB_REG_PC])) { + for (int i = 0; i < NumIntArchRegs; ++i) { + gdbregs.regs[i] = context->readIntReg(reg_redir[i]); } } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + for (int i = 0; i < NumIntArchRegs; ++i) { gdbregs.regs[i] = context->readIntReg(i); } } #ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + for (int i = 0; i < NumFloatArchRegs; ++i) { gdbregs.regs[i + KGDB_REG_F0] = context->readFloatRegBits(i); } #endif } -/////////////////////////////////////////////////////////// -// RemoteGDB::setregs -// -// Translate the GDB register format into the kernel -// debugger register format. -// +/* + * Translate the GDB register format into the kernel debugger register + * format. + */ void RemoteGDB::setregs() { // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - context->setIntReg(AlphaISA::reg_redir[i], gdbregs.regs[i]); + if (PcPAL(gdbregs.regs[KGDB_REG_PC])) { + for (int i = 0; i < NumIntArchRegs; ++i) { + context->setIntReg(reg_redir[i], gdbregs.regs[i]); } } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + for (int i = 0; i < NumIntArchRegs; ++i) { context->setIntReg(i, gdbregs.regs[i]); } } #ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + for (int i = 0; i < NumFloatArchRegs; ++i) { context->setFloatRegBits(i, gdbregs.regs[i + KGDB_REG_F0]); } #endif diff --git a/src/arch/alpha/remote_gdb.hh b/src/arch/alpha/remote_gdb.hh index 7bef183c3..43d0580d8 100644 --- a/src/arch/alpha/remote_gdb.hh +++ b/src/arch/alpha/remote_gdb.hh @@ -44,31 +44,29 @@ class System; class ThreadContext; class PhysicalMemory; -namespace AlphaISA -{ - class RemoteGDB : public BaseRemoteGDB - { - protected: - // Machine memory - bool write(Addr addr, size_t size, const char *data); +namespace AlphaISA { - public: - RemoteGDB(System *system, ThreadContext *context); +class RemoteGDB : public BaseRemoteGDB +{ + protected: + Addr notTakenBkpt; + Addr takenBkpt; - bool acc(Addr addr, size_t len); + protected: + void getregs(); + void setregs(); - protected: - void getregs(); - void setregs(); + void clearSingleStep(); + void setSingleStep(); - void clearSingleStep(); - void setSingleStep(); + // Machine memory + bool acc(Addr addr, size_t len); + bool write(Addr addr, size_t size, const char *data); - protected: + public: + RemoteGDB(System *system, ThreadContext *context); +}; - Addr notTakenBkpt; - Addr takenBkpt; - }; -} +} // namespace AlphaISA -#endif /* __ARCH_ALPHA_REMOTE_GDB_H__ */ +#endif // __ARCH_ALPHA_REMOTE_GDB_HH__ diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc index c16498e72..1b5a9be34 100644 --- a/src/arch/alpha/stacktrace.cc +++ b/src/arch/alpha/stacktrace.cc @@ -41,330 +41,326 @@ using namespace std; -namespace AlphaISA +namespace AlphaISA { + +ProcessInfo::ProcessInfo(ThreadContext *_tc) + : tc(_tc) { - ProcessInfo::ProcessInfo(ThreadContext *_tc) - : tc(_tc) - { - Addr addr = 0; + Addr addr = 0; + VirtualPort *vp = tc->getVirtPort(); + SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; - VirtualPort *vp; + if (!symtab->findAddress("thread_info_size", addr)) + panic("thread info not compiled into kernel\n"); + thread_info_size = vp->readGtoH<int32_t>(addr); - vp = tc->getVirtPort(); + if (!symtab->findAddress("task_struct_size", addr)) + panic("thread info not compiled into kernel\n"); + task_struct_size = vp->readGtoH<int32_t>(addr); - if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) - panic("thread info not compiled into kernel\n"); - thread_info_size = vp->readGtoH<int32_t>(addr); + if (!symtab->findAddress("thread_info_task", addr)) + panic("thread info not compiled into kernel\n"); + task_off = vp->readGtoH<int32_t>(addr); - if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) - panic("thread info not compiled into kernel\n"); - task_struct_size = vp->readGtoH<int32_t>(addr); + if (!symtab->findAddress("task_struct_pid", addr)) + panic("thread info not compiled into kernel\n"); + pid_off = vp->readGtoH<int32_t>(addr); - if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) - panic("thread info not compiled into kernel\n"); - task_off = vp->readGtoH<int32_t>(addr); + if (!symtab->findAddress("task_struct_comm", addr)) + panic("thread info not compiled into kernel\n"); + name_off = vp->readGtoH<int32_t>(addr); +} - if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) - panic("thread info not compiled into kernel\n"); - pid_off = vp->readGtoH<int32_t>(addr); +Addr +ProcessInfo::task(Addr ksp) const +{ + Addr base = ksp & ~0x3fff; + if (base == ULL(0xfffffc0000000000)) + return 0; - if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) - panic("thread info not compiled into kernel\n"); - name_off = vp->readGtoH<int32_t>(addr); + Addr tsk; - tc->delVirtPort(vp); - } + VirtualPort *vp; - Addr - ProcessInfo::task(Addr ksp) const - { - Addr base = ksp & ~0x3fff; - if (base == ULL(0xfffffc0000000000)) - return 0; + vp = tc->getVirtPort(); + tsk = vp->readGtoH<Addr>(base + task_off); - Addr tsk; + return tsk; +} - VirtualPort *vp; +int +ProcessInfo::pid(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return -1; - vp = tc->getVirtPort(); - tsk = vp->readGtoH<Addr>(base + task_off); - tc->delVirtPort(vp); + uint16_t pd; - return tsk; - } + VirtualPort *vp; - int - ProcessInfo::pid(Addr ksp) const - { - Addr task = this->task(ksp); - if (!task) - return -1; + vp = tc->getVirtPort(); + pd = vp->readGtoH<uint16_t>(task + pid_off); - uint16_t pd; + return pd; +} - VirtualPort *vp; +string +ProcessInfo::name(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return "console"; - vp = tc->getVirtPort(); - pd = vp->readGtoH<uint16_t>(task + pid_off); - tc->delVirtPort(vp); + char comm[256]; + CopyStringOut(tc, comm, task + name_off, sizeof(comm)); + if (!comm[0]) + return "startup"; - return pd; - } + return comm; +} - string - ProcessInfo::name(Addr ksp) const - { - Addr task = this->task(ksp); - if (!task) - return "console"; +StackTrace::StackTrace() + : tc(0), stack(64) +{ +} - char comm[256]; - CopyStringOut(tc, comm, task + name_off, sizeof(comm)); - if (!comm[0]) - return "startup"; +StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst) + : tc(0), stack(64) +{ + trace(_tc, inst); +} - return comm; - } +StackTrace::~StackTrace() +{ +} - StackTrace::StackTrace() - : tc(0), stack(64) - { - } +void +StackTrace::trace(ThreadContext *_tc, bool is_call) +{ + tc = _tc; - StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst) - : tc(0), stack(64) - { - trace(_tc, inst); - } + System *sys = tc->getSystemPtr(); - StackTrace::~StackTrace() - { - } + bool usermode = + (tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0; - void - StackTrace::trace(ThreadContext *_tc, bool is_call) - { - tc = _tc; + Addr pc = tc->readNextPC(); + bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd; - bool usermode = (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + if (usermode) { + stack.push_back(user); + return; + } - Addr pc = tc->readNextPC(); - bool kernel = tc->getSystemPtr()->kernelStart <= pc && - pc <= tc->getSystemPtr()->kernelEnd; + if (!kernel) { + stack.push_back(console); + return; + } - if (usermode) { - stack.push_back(user); - return; - } + SymbolTable *symtab = sys->kernelSymtab; + Addr ksp = tc->readIntReg(StackPointerReg); + Addr bottom = ksp & ~0x3fff; - if (!kernel) { - stack.push_back(console); - return; - } + if (is_call) { + Addr addr; + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find address %#x", pc); + + stack.push_back(addr); + pc = tc->readPC(); + } - SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; - Addr ksp = tc->readIntReg(TheISA::StackPointerReg); - Addr bottom = ksp & ~0x3fff; + while (ksp > bottom) { Addr addr; + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find symbol for pc=%#x", pc); + assert(pc >= addr && "symbol botch: callpc < func"); - if (is_call) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find address %#x", pc); + stack.push_back(addr); - stack.push_back(addr); - pc = tc->readPC(); - } + if (isEntry(addr)) + return; Addr ra; int size; - - while (ksp > bottom) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find symbol for pc=%#x", pc); - assert(pc >= addr && "symbol botch: callpc < func"); - - stack.push_back(addr); - - if (isEntry(addr)) + if (decodePrologue(ksp, pc, addr, size, ra)) { + if (!ra) return; - if (decodePrologue(ksp, pc, addr, size, ra)) { - if (!ra) - return; - - if (size <= 0) { - stack.push_back(unknown); - return; - } - - pc = ra; - ksp += size; - } else { + if (size <= 0) { stack.push_back(unknown); return; } - bool kernel = tc->getSystemPtr()->kernelStart <= pc && - pc <= tc->getSystemPtr()->kernelEnd; - if (!kernel) - return; - - if (stack.size() >= 1000) - panic("unwinding too far"); + pc = ra; + ksp += size; + } else { + stack.push_back(unknown); + return; } - panic("unwinding too far"); + bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd; + if (!kernel) + return; + + if (stack.size() >= 1000) + panic("unwinding too far"); } - bool - StackTrace::isEntry(Addr addr) - { - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp12)) - return true; + panic("unwinding too far"); +} - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp7)) - return true; +bool +StackTrace::isEntry(Addr addr) +{ + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp12)) + return true; - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp11)) - return true; + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp7)) + return true; - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp21)) - return true; + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp11)) + return true; - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp9)) - return true; + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp21)) + return true; - if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp2)) - return true; + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp9)) + return true; - return false; - } + if (addr == tc->readMiscRegNoEffect(IPR_PALtemp2)) + return true; - bool - StackTrace::decodeStack(MachInst inst, int &disp) - { - // lda $sp, -disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == 30 - // RB<20:16> == 30 - // Disp<15:0> - const MachInst mem_mask = 0xffff0000; - const MachInst lda_pattern = 0x23de0000; - const MachInst lda_disp_mask = 0x0000ffff; - - // subq $sp, disp, $sp - // addq $sp, disp, $sp - // - // Opcode<31:26> == 0x10 - // RA<25:21> == 30 - // Lit<20:13> - // One<12> = 1 - // Func<11:5> == 0x20 (addq) - // Func<11:5> == 0x29 (subq) - // RC<4:0> == 30 - const MachInst intop_mask = 0xffe01fff; - const MachInst addq_pattern = 0x43c0141e; - const MachInst subq_pattern = 0x43c0153e; - const MachInst intop_disp_mask = 0x001fe000; - const int intop_disp_shift = 13; - - if ((inst & mem_mask) == lda_pattern) - disp = -sext<16>(inst & lda_disp_mask); - else if ((inst & intop_mask) == addq_pattern) - disp = -int((inst & intop_disp_mask) >> intop_disp_shift); - else if ((inst & intop_mask) == subq_pattern) - disp = int((inst & intop_disp_mask) >> intop_disp_shift); - else - return false; + return false; +} - return true; - } +bool +StackTrace::decodeStack(MachInst inst, int &disp) +{ + // lda $sp, -disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == 30 + // RB<20:16> == 30 + // Disp<15:0> + const MachInst mem_mask = 0xffff0000; + const MachInst lda_pattern = 0x23de0000; + const MachInst lda_disp_mask = 0x0000ffff; + + // subq $sp, disp, $sp + // addq $sp, disp, $sp + // + // Opcode<31:26> == 0x10 + // RA<25:21> == 30 + // Lit<20:13> + // One<12> = 1 + // Func<11:5> == 0x20 (addq) + // Func<11:5> == 0x29 (subq) + // RC<4:0> == 30 + const MachInst intop_mask = 0xffe01fff; + const MachInst addq_pattern = 0x43c0141e; + const MachInst subq_pattern = 0x43c0153e; + const MachInst intop_disp_mask = 0x001fe000; + const int intop_disp_shift = 13; + + if ((inst & mem_mask) == lda_pattern) + disp = -sext<16>(inst & lda_disp_mask); + else if ((inst & intop_mask) == addq_pattern) + disp = -int((inst & intop_disp_mask) >> intop_disp_shift); + else if ((inst & intop_mask) == subq_pattern) + disp = int((inst & intop_disp_mask) >> intop_disp_shift); + else + return false; - bool - StackTrace::decodeSave(MachInst inst, int ®, int &disp) - { - // lda $stq, disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == ? - // RB<20:16> == 30 - // Disp<15:0> - const MachInst stq_mask = 0xfc1f0000; - const MachInst stq_pattern = 0xb41e0000; - const MachInst stq_disp_mask = 0x0000ffff; - const MachInst reg_mask = 0x03e00000; - const int reg_shift = 21; - - if ((inst & stq_mask) == stq_pattern) { - reg = (inst & reg_mask) >> reg_shift; - disp = sext<16>(inst & stq_disp_mask); - } else { - return false; - } + return true; +} - return true; +bool +StackTrace::decodeSave(MachInst inst, int ®, int &disp) +{ + // lda $stq, disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == ? + // RB<20:16> == 30 + // Disp<15:0> + const MachInst stq_mask = 0xfc1f0000; + const MachInst stq_pattern = 0xb41e0000; + const MachInst stq_disp_mask = 0x0000ffff; + const MachInst reg_mask = 0x03e00000; + const int reg_shift = 21; + + if ((inst & stq_mask) == stq_pattern) { + reg = (inst & reg_mask) >> reg_shift; + disp = sext<16>(inst & stq_disp_mask); + } else { + return false; } - /* - * Decode the function prologue for the function we're in, and note - * which registers are stored where, and how large the stack frame is. - */ - bool - StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, - int &size, Addr &ra) - { - size = 0; - ra = 0; - - for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { - MachInst inst; - CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst)); - - int reg, disp; - if (decodeStack(inst, disp)) { - if (size) { - // panic("decoding frame size again"); - return true; - } - size += disp; - } else if (decodeSave(inst, reg, disp)) { - if (!ra && reg == ReturnAddressReg) { - CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); - if (!ra) { - // panic("no return address value pc=%#x\n", pc); - return false; - } + return true; +} + +/* + * Decode the function prologue for the function we're in, and note + * which registers are stored where, and how large the stack frame is. + */ +bool +StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, int &size, + Addr &ra) +{ + size = 0; + ra = 0; + + for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { + MachInst inst; + CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst)); + + int reg, disp; + if (decodeStack(inst, disp)) { + if (size) { + // panic("decoding frame size again"); + return true; + } + size += disp; + } else if (decodeSave(inst, reg, disp)) { + if (!ra && reg == ReturnAddressReg) { + CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); + if (!ra) { + // panic("no return address value pc=%#x\n", pc); + return false; } } } - - return true; } + return true; +} + #if TRACING_ON - void - StackTrace::dump() - { - StringWrap name(tc->getCpuPtr()->name()); - SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; - - DPRINTFN("------ Stack ------\n"); - - string symbol; - for (int i = 0, size = stack.size(); i < size; ++i) { - Addr addr = stack[size - i - 1]; - if (addr == user) - symbol = "user"; - else if (addr == console) - symbol = "console"; - else if (addr == unknown) - symbol = "unknown"; - else - symtab->findSymbol(addr, symbol); - - DPRINTFN("%#x: %s\n", addr, symbol); - } +void +StackTrace::dump() +{ + StringWrap name(tc->getCpuPtr()->name()); + SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; + + DPRINTFN("------ Stack ------\n"); + + string symbol; + for (int i = 0, size = stack.size(); i < size; ++i) { + Addr addr = stack[size - i - 1]; + if (addr == user) + symbol = "user"; + else if (addr == console) + symbol = "console"; + else if (addr == unknown) + symbol = "unknown"; + else + symtab->findSymbol(addr, symbol); + + DPRINTFN("%#x: %s\n", addr, symbol); } -#endif } +#endif + +} // namespace AlphaISA diff --git a/src/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh index 834abbc2f..db42c4399 100644 --- a/src/arch/alpha/stacktrace.hh +++ b/src/arch/alpha/stacktrace.hh @@ -36,90 +36,90 @@ class ThreadContext; -namespace AlphaISA -{ - class StackTrace; +namespace AlphaISA { - class ProcessInfo - { - private: - ThreadContext *tc; +class StackTrace; + +class ProcessInfo +{ + private: + ThreadContext *tc; - int thread_info_size; - int task_struct_size; - int task_off; - int pid_off; - int name_off; + int thread_info_size; + int task_struct_size; + int task_off; + int pid_off; + int name_off; - public: - ProcessInfo(ThreadContext *_tc); + public: + ProcessInfo(ThreadContext *_tc); - Addr task(Addr ksp) const; - int pid(Addr ksp) const; - std::string name(Addr ksp) const; - }; + Addr task(Addr ksp) const; + int pid(Addr ksp) const; + std::string name(Addr ksp) const; +}; - class StackTrace - { - protected: - typedef TheISA::MachInst MachInst; - private: - ThreadContext *tc; - std::vector<Addr> stack; +class StackTrace +{ + private: + ThreadContext *tc; + std::vector<Addr> stack; - private: - bool isEntry(Addr addr); - bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); - bool decodeSave(MachInst inst, int ®, int &disp); - bool decodeStack(MachInst inst, int &disp); + private: + bool isEntry(Addr addr); + bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); + bool decodeSave(MachInst inst, int ®, int &disp); + bool decodeStack(MachInst inst, int &disp); - void trace(ThreadContext *tc, bool is_call); + void trace(ThreadContext *tc, bool is_call); - public: - StackTrace(); - StackTrace(ThreadContext *tc, StaticInstPtr inst); - ~StackTrace(); + public: + StackTrace(); + StackTrace(ThreadContext *tc, StaticInstPtr inst); + ~StackTrace(); - void clear() - { - tc = 0; - stack.clear(); - } + void + clear() + { + tc = 0; + stack.clear(); + } - bool valid() const { return tc != NULL; } - bool trace(ThreadContext *tc, StaticInstPtr inst); + bool valid() const { return tc != NULL; } + bool trace(ThreadContext *tc, StaticInstPtr inst); - public: - const std::vector<Addr> &getstack() const { return stack; } + public: + const std::vector<Addr> &getstack() const { return stack; } - static const int user = 1; - static const int console = 2; - static const int unknown = 3; + static const int user = 1; + static const int console = 2; + static const int unknown = 3; #if TRACING_ON - private: - void dump(); + private: + void dump(); - public: - void dprintf() { if (DTRACE(Stack)) dump(); } + public: + void dprintf() { if (DTRACE(Stack)) dump(); } #else - public: - void dprintf() {} + public: + void dprintf() {} #endif - }; +}; - inline bool - StackTrace::trace(ThreadContext *tc, StaticInstPtr inst) - { - if (!inst->isCall() && !inst->isReturn()) - return false; +inline bool +StackTrace::trace(ThreadContext *tc, StaticInstPtr inst) +{ + if (!inst->isCall() && !inst->isReturn()) + return false; - if (valid()) - clear(); + if (valid()) + clear(); - trace(tc, !inst->isReturn()); - return true; - } + trace(tc, !inst->isReturn()); + return true; } +} // namespace AlphaISA + #endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc index 2af62ceea..72d918870 100644 --- a/src/arch/alpha/system.cc +++ b/src/arch/alpha/system.cc @@ -42,8 +42,7 @@ #include "params/AlphaSystem.hh" #include "sim/byteswap.hh" - -using namespace LittleEndianGuest; +using namespace AlphaISA; AlphaSystem::AlphaSystem(Params *p) : System(p) @@ -67,8 +66,8 @@ AlphaSystem::AlphaSystem(Params *p) // Load program sections into memory - pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask); - console->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + pal->loadSections(&functionalPort, LoadAddrMask); + console->loadSections(&functionalPort, LoadAddrMask); // load symbols if (!console->loadGlobalSymbols(consoleSymtab)) @@ -117,7 +116,6 @@ AlphaSystem::AlphaSystem(Params *p) virtPort.write(addr+0x58, data); } else panic("could not find hwrpb\n"); - } AlphaSystem::~AlphaSystem() @@ -142,9 +140,9 @@ AlphaSystem::~AlphaSystem() * in the procedure value register (pv aka t12 == r27). This sequence * looks like the following: * - * opcode Ra Rb offset - * ldah gp,X(pv) 09 29 27 X - * lda gp,Y(gp) 08 29 29 Y + * opcode Ra Rb offset + * ldah gp,X(pv) 09 29 27 X + * lda gp,Y(gp) 08 29 29 Y * * for some constant offsets X and Y. The catch is that the linker * (or maybe even the compiler, I'm not sure) may recognize that the @@ -172,11 +170,11 @@ AlphaSystem::fixFuncEventAddr(Addr addr) const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); uint32_t i1 = virtPort.read<uint32_t>(addr); - uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(AlphaISA::MachInst)); + uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(MachInst)); if ((i1 & inst_mask) == gp_ldah_pattern && (i2 & inst_mask) == gp_lda_pattern) { - Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst); + Addr new_addr = addr + 2 * sizeof(MachInst); DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); return new_addr; } else { @@ -184,15 +182,15 @@ AlphaSystem::fixFuncEventAddr(Addr addr) } } - void AlphaSystem::setAlphaAccess(Addr access) { Addr addr = 0; if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { - virtPort.write(addr, htog(EV5::Phys2K0Seg(access))); - } else + virtPort.write(addr, htog(Phys2K0Seg(access))); + } else { panic("could not find m5AlphaAccess\n"); + } } void @@ -203,7 +201,6 @@ AlphaSystem::serialize(std::ostream &os) palSymtab->serialize("pal_symtab", os); } - void AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) { diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh index a934550b7..da42ab263 100644 --- a/src/arch/alpha/system.hh +++ b/src/arch/alpha/system.hh @@ -49,10 +49,10 @@ class AlphaSystem : public System AlphaSystem(Params *p); ~AlphaSystem(); -/** - * Serialization stuff - */ public: + /** + * Serialization stuff + */ virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); @@ -77,26 +77,28 @@ class AlphaSystem : public System /** Event to halt the simulator if the console calls panic() */ BreakPCEvent *consolePanicEvent; #endif + protected: const Params *params() const { return (const Params *)_params; } /** Add a function-based event to PALcode. */ template <class T> - T *addPalFuncEvent(const char *lbl) + T * + addPalFuncEvent(const char *lbl) { return addFuncEvent<T>(palSymtab, lbl); } /** Add a function-based event to the console code. */ template <class T> - T *addConsoleFuncEvent(const char *lbl) + T * + addConsoleFuncEvent(const char *lbl) { return addFuncEvent<T>(consoleSymtab, lbl); } virtual Addr fixFuncEventAddr(Addr addr); - }; -#endif +#endif // __ARCH_ALPHA_SYSTEM_HH__ diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc index 77bf5e285..2b0afacfe 100644 --- a/src/arch/alpha/tlb.cc +++ b/src/arch/alpha/tlb.cc @@ -43,19 +43,20 @@ #include "cpu/thread_context.hh" using namespace std; -using namespace EV5; namespace AlphaISA { + /////////////////////////////////////////////////////////////////////// // // Alpha TLB // + #ifdef DEBUG bool uncacheBit39 = false; bool uncacheBit40 = false; #endif -#define MODE2MASK(X) (1 << (X)) +#define MODE2MASK(X) (1 << (X)) TLB::TLB(const Params *p) : BaseTLB(p), size(p->size), nlu(0) @@ -114,20 +115,20 @@ TLB::lookup(Addr vpn, uint8_t asn) return retval; } - Fault -TLB::checkCacheability(RequestPtr &req) +TLB::checkCacheability(RequestPtr &req, bool itb) { -// in Alpha, cacheability is controlled by upper-level bits of the -// physical address - -/* - * We support having the uncacheable bit in either bit 39 or bit 40. - * The Turbolaser platform (and EV5) support having the bit in 39, but - * Tsunami (which Linux assumes uses an EV6) generates accesses with - * the bit in 40. So we must check for both, but we have debug flags - * to catch a weird case where both are used, which shouldn't happen. - */ + // in Alpha, cacheability is controlled by upper-level bits of the + // physical address + + /* + * We support having the uncacheable bit in either bit 39 or bit + * 40. The Turbolaser platform (and EV5) support having the bit + * in 39, but Tsunami (which Linux assumes uses an EV6) generates + * accesses with the bit in 40. So we must check for both, but we + * have debug flags to catch a weird case where both are used, + * which shouldn't happen. + */ #if ALPHA_TLASER @@ -141,13 +142,20 @@ TLB::checkCacheability(RequestPtr &req) return new UnimpFault("IPR memory space not implemented!"); } else { // mark request as uncacheable - req->setFlags(req->getFlags() | UNCACHEABLE); + req->setFlags(Request::UNCACHEABLE); #if !ALPHA_TLASER - // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) + // Clear bits 42:35 of the physical address (10-2 in + // Tsunami manual) req->setPaddr(req->getPaddr() & PAddrUncachedMask); #endif } + // We shouldn't be able to read from an uncachable address in Alpha as + // we don't have a ROM and we don't want to try to fetch from a device + // register as we destroy any data that is clear-on-read. + if (req->isUncacheable() && itb) + return new UnimpFault("CPU trying to fetch from uncached I/O"); + } return NoFault; } @@ -216,7 +224,8 @@ TLB::flushProcesses() ++i; if (!entry->asma) { - DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, entry->tag, entry->ppn); + DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, + entry->tag, entry->ppn); entry->valid = false; lookupTable.erase(cur); } @@ -279,7 +288,6 @@ TLB::unserialize(Checkpoint *cp, const string §ion) } } - /////////////////////////////////////////////////////////////////////// // // Alpha ITB @@ -308,13 +316,12 @@ ITB::regStats() accesses = hits + misses; } - Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { //If this is a pal pc, then set PHYSICAL - if(FULL_SYSTEM && PcPAL(req->getPC())) - req->setFlags(req->getFlags() | PHYSICAL); + if (FULL_SYSTEM && PcPAL(req->getPC())) + req->setFlags(Request::PHYSICAL); if (PcPAL(req->getPC())) { // strip off PAL PC marker (lsb is 1) @@ -323,7 +330,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) return NoFault; } - if (req->getFlags() & PHYSICAL) { + if (req->getFlags() & Request::PHYSICAL) { req->setPaddr(req->getVaddr()); } else { // verify that this is a good virtual address @@ -390,15 +397,23 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) if (req->getPaddr() & ~PAddrImplMask) return genMachineCheckFault(); - return checkCacheability(req); + return checkCacheability(req, true); } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + /////////////////////////////////////////////////////////////////////// // // Alpha DTB // - DTB::DTB(const Params *p) +DTB::DTB(const Params *p) : TLB(p) {} @@ -472,14 +487,13 @@ DTB::regStats() } Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { Addr pc = tc->readPC(); mode_type mode = (mode_type)DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM)); - /** * Check for alignment faults */ @@ -491,13 +505,13 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) } if (PcPAL(pc)) { - mode = (req->getFlags() & ALTMODE) ? + mode = (req->getFlags() & Request::ALTMODE) ? (mode_type)ALT_MODE_AM( tc->readMiscRegNoEffect(IPR_ALT_MODE)) : mode_kernel; } - if (req->getFlags() & PHYSICAL) { + if (req->getFlags() & Request::PHYSICAL) { req->setPaddr(req->getVaddr()); } else { // verify that this is a good virtual address @@ -517,14 +531,15 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) #endif { - // only valid in kernel mode if (DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM)) != mode_kernel) { if (write) { write_acv++; } else { read_acv++; } uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK); - return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + + return new DtbAcvFault(req->getVaddr(), req->getFlags(), + flags); } req->setPaddr(req->getVaddr() & PAddrImplMask); @@ -553,7 +568,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if (write) { write_misses++; } else { read_misses++; } uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK; - return (req->getFlags() & VPTE) ? + return (req->getFlags() & Request::VPTE) ? (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(), flags)) : (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(), @@ -570,25 +585,28 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) uint64_t flags = MM_STAT_WR_MASK | MM_STAT_ACV_MASK | (entry->fonw ? MM_STAT_FONW_MASK : 0); - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + return new DtbPageFault(req->getVaddr(), req->getFlags(), + flags); } if (entry->fonw) { write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_FONW_MASK; - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + uint64_t flags = MM_STAT_WR_MASK | MM_STAT_FONW_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), + flags); } } else { if (!(entry->xre & MODE2MASK(mode))) { read_acv++; uint64_t flags = MM_STAT_ACV_MASK | (entry->fonr ? MM_STAT_FONR_MASK : 0); - return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), + flags); } if (entry->fonr) { read_acv++; uint64_t flags = MM_STAT_FONR_MASK; - return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + return new DtbPageFault(req->getVaddr(), req->getFlags(), + flags); } } } @@ -606,6 +624,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) return checkCacheability(req); } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + TlbEntry & TLB::index(bool advance) { diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh index e61ae5c6d..643889534 100644 --- a/src/arch/alpha/tlb.hh +++ b/src/arch/alpha/tlb.hh @@ -29,8 +29,8 @@ * Steve Reinhardt */ -#ifndef __ALPHA_MEMORY_HH__ -#define __ALPHA_MEMORY_HH__ +#ifndef __ARCH_ALPHA_TLB_HH__ +#define __ARCH_ALPHA_TLB_HH__ #include <map> @@ -48,110 +48,120 @@ class ThreadContext; -namespace AlphaISA +namespace AlphaISA { + +class TlbEntry; + +class TLB : public BaseTLB { - class TlbEntry; + protected: + typedef std::multimap<Addr, int> PageTable; + PageTable lookupTable; // Quick lookup into page table + + TlbEntry *table; // the Page Table + int size; // TLB Size + int nlu; // not last used entry (for replacement) + + void nextnlu() { if (++nlu >= size) nlu = 0; } + TlbEntry *lookup(Addr vpn, uint8_t asn); + + public: + typedef AlphaTLBParams Params; + TLB(const Params *p); + virtual ~TLB(); + + int getsize() const { return size; } - class TLB : public BaseTLB + TlbEntry &index(bool advance = true); + void insert(Addr vaddr, TlbEntry &entry); + + void flushAll(); + void flushProcesses(); + void flushAddr(Addr addr, uint8_t asn); + + void + demapPage(Addr vaddr, uint64_t asn) { - protected: - typedef std::multimap<Addr, int> PageTable; - PageTable lookupTable; // Quick lookup into page table - - TlbEntry *table; // the Page Table - int size; // TLB Size - int nlu; // not last used entry (for replacement) - - void nextnlu() { if (++nlu >= size) nlu = 0; } - TlbEntry *lookup(Addr vpn, uint8_t asn); - - public: - typedef AlphaTLBParams Params; - TLB(const Params *p); - virtual ~TLB(); - - int getsize() const { return size; } - - TlbEntry &index(bool advance = true); - void insert(Addr vaddr, TlbEntry &entry); - - void flushAll(); - void flushProcesses(); - void flushAddr(Addr addr, uint8_t asn); - - void demapPage(Addr vaddr, uint64_t asn) - { - assert(asn < (1 << 8)); - flushAddr(vaddr, asn); - } - - // static helper functions... really EV5 VM traits - static bool validVirtualAddress(Addr vaddr) { - // unimplemented bits must be all 0 or all 1 - Addr unimplBits = vaddr & EV5::VAddrUnImplMask; - return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); - } - - static Fault checkCacheability(RequestPtr &req); - - // Checkpointing - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - // Most recently used page table entries - TlbEntry *EntryCache[3]; - inline void flushCache() - { - memset(EntryCache, 0, 3 * sizeof(TlbEntry*)); - } - - inline TlbEntry* updateCache(TlbEntry *entry) { - EntryCache[2] = EntryCache[1]; - EntryCache[1] = EntryCache[0]; - EntryCache[0] = entry; - return entry; - } - }; - - class ITB : public TLB + assert(asn < (1 << 8)); + flushAddr(vaddr, asn); + } + + // static helper functions... really EV5 VM traits + static bool + validVirtualAddress(Addr vaddr) { - protected: - mutable Stats::Scalar<> hits; - mutable Stats::Scalar<> misses; - mutable Stats::Scalar<> acv; - mutable Stats::Formula accesses; + // unimplemented bits must be all 0 or all 1 + Addr unimplBits = vaddr & VAddrUnImplMask; + return unimplBits == 0 || unimplBits == VAddrUnImplMask; + } - public: - typedef AlphaITBParams Params; - ITB(const Params *p); - virtual void regStats(); + static Fault checkCacheability(RequestPtr &req, bool itb = false); - Fault translate(RequestPtr &req, ThreadContext *tc); - }; + // Checkpointing + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); - class DTB : public TLB + // Most recently used page table entries + TlbEntry *EntryCache[3]; + inline void + flushCache() { - protected: - mutable Stats::Scalar<> read_hits; - mutable Stats::Scalar<> read_misses; - mutable Stats::Scalar<> read_acv; - mutable Stats::Scalar<> read_accesses; - mutable Stats::Scalar<> write_hits; - mutable Stats::Scalar<> write_misses; - mutable Stats::Scalar<> write_acv; - mutable Stats::Scalar<> write_accesses; - Stats::Formula hits; - Stats::Formula misses; - Stats::Formula acv; - Stats::Formula accesses; - - public: - typedef AlphaDTBParams Params; - DTB(const Params *p); - virtual void regStats(); - - Fault translate(RequestPtr &req, ThreadContext *tc, bool write); - }; -} - -#endif // __ALPHA_MEMORY_HH__ + memset(EntryCache, 0, 3 * sizeof(TlbEntry*)); + } + + inline TlbEntry * + updateCache(TlbEntry *entry) { + EntryCache[2] = EntryCache[1]; + EntryCache[1] = EntryCache[0]; + EntryCache[0] = entry; + return entry; + } +}; + +class ITB : public TLB +{ + protected: + mutable Stats::Scalar hits; + mutable Stats::Scalar misses; + mutable Stats::Scalar acv; + mutable Stats::Formula accesses; + + public: + typedef AlphaITBParams Params; + ITB(const Params *p); + virtual void regStats(); + + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); +}; + +class DTB : public TLB +{ + protected: + mutable Stats::Scalar read_hits; + mutable Stats::Scalar read_misses; + mutable Stats::Scalar read_acv; + mutable Stats::Scalar read_accesses; + mutable Stats::Scalar write_hits; + mutable Stats::Scalar write_misses; + mutable Stats::Scalar write_acv; + mutable Stats::Scalar write_accesses; + Stats::Formula hits; + Stats::Formula misses; + Stats::Formula acv; + Stats::Formula accesses; + + public: + typedef AlphaDTBParams Params; + DTB(const Params *p); + virtual void regStats(); + + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); +}; + +} // namespace AlphaISA + +#endif // __ARCH_ALPHA_TLB_HH__ diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc index 6823d820a..8fa3cdeda 100644 --- a/src/arch/alpha/tru64/process.cc +++ b/src/arch/alpha/tru64/process.cc @@ -32,10 +32,8 @@ #include "arch/alpha/tru64/tru64.hh" #include "arch/alpha/isa_traits.hh" #include "arch/alpha/tru64/process.hh" - #include "cpu/thread_context.hh" #include "kern/tru64/tru64.hh" - #include "sim/process.hh" #include "sim/syscall_emul.hh" @@ -47,7 +45,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<AlphaTru64::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<AlphaTru64::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "OSF1"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -64,34 +62,35 @@ static SyscallReturn getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); - unsigned nbytes = tc->getSyscallArg(2); + unsigned op = process->getSyscallArg(tc, 0); + unsigned nbytes = process->getSyscallArg(tc, 2); switch (op) { case AlphaTru64::GSI_MAX_CPU: { - TypedBufferArg<uint32_t> max_cpu(tc->getSyscallArg(1)); + TypedBufferArg<uint32_t> max_cpu(process->getSyscallArg(tc, 1)); *max_cpu = htog((uint32_t)process->numCpus()); max_cpu.copyOut(tc->getMemPort()); return 1; } case AlphaTru64::GSI_CPUS_IN_BOX: { - TypedBufferArg<uint32_t> cpus_in_box(tc->getSyscallArg(1)); + TypedBufferArg<uint32_t> cpus_in_box(process->getSyscallArg(tc, 1)); *cpus_in_box = htog((uint32_t)process->numCpus()); cpus_in_box.copyOut(tc->getMemPort()); return 1; } case AlphaTru64::GSI_PHYSMEM: { - TypedBufferArg<uint64_t> physmem(tc->getSyscallArg(1)); - *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB + TypedBufferArg<uint64_t> physmem(process->getSyscallArg(tc, 1)); + *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB physmem.copyOut(tc->getMemPort()); return 1; } case AlphaTru64::GSI_CPU_INFO: { - TypedBufferArg<AlphaTru64::cpu_info> infop(tc->getSyscallArg(1)); + TypedBufferArg<AlphaTru64::cpu_info> + infop(process->getSyscallArg(tc, 1)); infop->current_cpu = htog(0); infop->cpus_in_box = htog(process->numCpus()); @@ -108,14 +107,14 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, } case AlphaTru64::GSI_PROC_TYPE: { - TypedBufferArg<uint64_t> proc_type(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> proc_type(process->getSyscallArg(tc, 1)); *proc_type = htog((uint64_t)11); proc_type.copyOut(tc->getMemPort()); return 1; } case AlphaTru64::GSI_PLATFORM_NAME: { - BufferArg bufArg(tc->getSyscallArg(1), nbytes); + BufferArg bufArg(process->getSyscallArg(tc, 1), nbytes); strncpy((char *)bufArg.bufferPtr(), "COMPAQ Professional Workstation XP1000", nbytes); @@ -124,7 +123,7 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, } case AlphaTru64::GSI_CLK_TCK: { - TypedBufferArg<uint64_t> clk_hz(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> clk_hz(process->getSyscallArg(tc, 1)); *clk_hz = htog((uint64_t)1024); clk_hz.copyOut(tc->getMemPort()); return 1; @@ -143,12 +142,12 @@ static SyscallReturn setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); + unsigned op = process->getSyscallArg(tc, 0); switch (op) { case AlphaTru64::SSI_IEEE_FP_CONTROL: warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n", - tc->getSyscallArg(1)); + process->getSyscallArg(tc, 1)); break; default: @@ -159,26 +158,24 @@ setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return 0; } - /// Target table() handler. -static -SyscallReturn tableFunc(SyscallDesc *desc, int callnum, LiveProcess *process, - ThreadContext *tc) +static SyscallReturn +tableFunc(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) { using namespace std; - using namespace TheISA; - int id = tc->getSyscallArg(0); // table ID - int index = tc->getSyscallArg(1); // index into table + int id = process->getSyscallArg(tc, 0); // table ID + int index = process->getSyscallArg(tc, 1); // index into table // arg 2 is buffer pointer; type depends on table ID - int nel = tc->getSyscallArg(3); // number of elements - int lel = tc->getSyscallArg(4); // expected element size + int nel = process->getSyscallArg(tc, 3); // number of elements + int lel = process->getSyscallArg(tc, 4); // expected element size switch (id) { case AlphaTru64::TBL_SYSINFO: { if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) return -EINVAL; - TypedBufferArg<Tru64::tbl_sysinfo> elp(tc->getSyscallArg(2)); + TypedBufferArg<Tru64::tbl_sysinfo> elp(process->getSyscallArg(tc, 2)); const int clk_hz = one_million; elp->si_user = htog(curTick / (Clock::Frequency / clk_hz)); @@ -219,7 +216,7 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", unimplementedFunc), /* 16 */ SyscallDesc("chown", unimplementedFunc), - /* 17 */ SyscallDesc("obreak", obreakFunc), + /* 17 */ SyscallDesc("obreak", brkFunc), /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc), /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getpid", getpidPseudoFunc), @@ -260,9 +257,9 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = { /* 55 */ SyscallDesc("reboot", unimplementedFunc), /* 56 */ SyscallDesc("revoke", unimplementedFunc), /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", readlinkFunc), /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 60 */ SyscallDesc("umask", umaskFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("old_fstat", unimplementedFunc), /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), @@ -339,7 +336,7 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = { /* 133 */ SyscallDesc("sendto", unimplementedFunc), /* 134 */ SyscallDesc("shutdown", unimplementedFunc), /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", mkdirFunc), /* 137 */ SyscallDesc("rmdir", unimplementedFunc), /* 138 */ SyscallDesc("utimes", unimplementedFunc), /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc), @@ -472,15 +469,14 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = { /* 266 */ SyscallDesc("sendfile", unimplementedFunc), }; - - SyscallDesc AlphaTru64Process::machSyscallDescs[] = { /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc), /* 1 */ SyscallDesc("m5_mutex_lock", AlphaTru64::m5_mutex_lockFunc), /* 2 */ SyscallDesc("m5_mutex_trylock", AlphaTru64::m5_mutex_trylockFunc), /* 3 */ SyscallDesc("m5_mutex_unlock", AlphaTru64::m5_mutex_unlockFunc), /* 4 */ SyscallDesc("m5_cond_signal", AlphaTru64::m5_cond_signalFunc), - /* 5 */ SyscallDesc("m5_cond_broadcast", AlphaTru64::m5_cond_broadcastFunc), + /* 5 */ SyscallDesc("m5_cond_broadcast", + AlphaTru64::m5_cond_broadcastFunc), /* 6 */ SyscallDesc("m5_cond_wait", AlphaTru64::m5_cond_waitFunc), /* 7 */ SyscallDesc("m5_thread_exit", AlphaTru64::m5_thread_exitFunc), /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc), @@ -507,7 +503,8 @@ SyscallDesc AlphaTru64Process::machSyscallDescs[] = { /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc), /* 30 */ SyscallDesc("lw_wire", unimplementedFunc), /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc), - /* 32 */ SyscallDesc("nxm_thread_create", AlphaTru64::nxm_thread_createFunc), + /* 32 */ SyscallDesc("nxm_thread_create", + AlphaTru64::nxm_thread_createFunc), /* 33 */ SyscallDesc("nxm_task_init", AlphaTru64::nxm_task_initFunc), /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc), /* 35 */ SyscallDesc("nxm_idle", AlphaTru64::nxm_idleFunc), @@ -572,9 +569,8 @@ AlphaTru64Process::getDesc(int callnum) return &syscallDescs[callnum]; } - -AlphaTru64Process::AlphaTru64Process(LiveProcessParams * params, - ObjectFile *objFile) +AlphaTru64Process::AlphaTru64Process(LiveProcessParams *params, + ObjectFile *objFile) : AlphaLiveProcess(params, objFile), Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc)) diff --git a/src/arch/alpha/tru64/process.hh b/src/arch/alpha/tru64/process.hh index 16bc499c6..6d7a76555 100644 --- a/src/arch/alpha/tru64/process.hh +++ b/src/arch/alpha/tru64/process.hh @@ -28,12 +28,13 @@ * Authors: Steve Reinhardt */ -#ifndef __ALPHA_TRU64_PROCESS_HH__ -#define __ALPHA_TRU64_PROCESS_HH__ +#ifndef __ARCH_ALPHA_TRU64_PROCESS_HH__ +#define __ARCH_ALPHA_TRU64_PROCESS_HH__ #include "arch/alpha/process.hh" namespace AlphaISA { + /// A process with emulated Alpha Tru64 syscalls. class AlphaTru64Process : public AlphaLiveProcess { @@ -51,9 +52,9 @@ class AlphaTru64Process : public AlphaLiveProcess const int Num_Syscall_Descs; const int Num_Mach_Syscall_Descs; - virtual SyscallDesc* getDesc(int callnum); + virtual SyscallDesc *getDesc(int callnum); }; } // namespace AlphaISA -#endif // __ALPHA_TRU64_PROCESS_HH__ +#endif // __ARCH_ALPHA_TRU64_PROCESS_HH__ diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc index 56b04846f..c72e975f0 100644 --- a/src/arch/alpha/tru64/tru64.cc +++ b/src/arch/alpha/tru64/tru64.cc @@ -33,34 +33,34 @@ // open(2) flags translation table OpenFlagTransTable AlphaTru64::openFlagTable[] = { #ifdef _MSC_VER - { AlphaTru64::TGT_O_RDONLY, _O_RDONLY }, - { AlphaTru64::TGT_O_WRONLY, _O_WRONLY }, - { AlphaTru64::TGT_O_RDWR, _O_RDWR }, - { AlphaTru64::TGT_O_APPEND, _O_APPEND }, - { AlphaTru64::TGT_O_CREAT, _O_CREAT }, - { AlphaTru64::TGT_O_TRUNC, _O_TRUNC }, - { AlphaTru64::TGT_O_EXCL, _O_EXCL }, + { AlphaTru64::TGT_O_RDONLY, _O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, _O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, _O_RDWR }, + { AlphaTru64::TGT_O_APPEND, _O_APPEND }, + { AlphaTru64::TGT_O_CREAT, _O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, _O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK }, + { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY }, + { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { AlphaTru64::TGT_O_SYNC, _O_SYNC }, + { AlphaTru64::TGT_O_SYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { AlphaTru64::TGT_O_RDONLY, O_RDONLY }, - { AlphaTru64::TGT_O_WRONLY, O_WRONLY }, - { AlphaTru64::TGT_O_RDWR, O_RDWR }, - { AlphaTru64::TGT_O_APPEND, O_APPEND }, - { AlphaTru64::TGT_O_CREAT, O_CREAT }, - { AlphaTru64::TGT_O_TRUNC, O_TRUNC }, - { AlphaTru64::TGT_O_EXCL, O_EXCL }, - { AlphaTru64::TGT_O_NONBLOCK, O_NONBLOCK }, - { AlphaTru64::TGT_O_NOCTTY, O_NOCTTY }, + { AlphaTru64::TGT_O_RDONLY, O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, O_RDWR }, + { AlphaTru64::TGT_O_APPEND, O_APPEND }, + { AlphaTru64::TGT_O_CREAT, O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, O_EXCL }, + { AlphaTru64::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaTru64::TGT_O_NOCTTY, O_NOCTTY }, #ifdef O_SYNC - { AlphaTru64::TGT_O_SYNC, O_SYNC }, + { AlphaTru64::TGT_O_SYNC, O_SYNC }, #endif #endif /* _MSC_VER */ }; diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh index 90e5f12dc..4ba35fc50 100644 --- a/src/arch/alpha/tru64/tru64.hh +++ b/src/arch/alpha/tru64/tru64.hh @@ -28,14 +28,13 @@ * Authors: Korey Sewell */ -#ifndef __ALPHA_ALPHA_TRU64_HH -#define __ALPHA_ALPHA_TRU64_HH +#ifndef __ALPHA_ALPHA_TRU64_TRU64_HH__ +#define __ALPHA_ALPHA_TRU64_TRU64_HH__ #include "kern/tru64/tru64.hh" class AlphaTru64 : public Tru64 { - public: /// This table maps the target open() flags to the corresponding /// host open() flags. @@ -46,21 +45,21 @@ class AlphaTru64 : public Tru64 //@{ /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00000010; //!< O_APPEND - static const int TGT_O_CREAT = 00001000; //!< O_CREAT - static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC - static const int TGT_O_EXCL = 00004000; //!< O_EXCL - static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY - static const int TGT_O_SYNC = 00040000; //!< O_SYNC - static const int TGT_O_DRD = 00100000; //!< O_DRD - static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO - static const int TGT_O_CACHE = 00400000; //!< O_CACHE - static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC - static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC //@} /// For mmap(). @@ -68,13 +67,13 @@ class AlphaTru64 : public Tru64 //@{ /// For getsysinfo(). - static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type - static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # CPUs on machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz //@} //@{ @@ -124,6 +123,4 @@ class AlphaTru64 : public Tru64 }; }; - - -#endif +#endif // __ALPHA_ALPHA_TRU64_TRU64_HH__ diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh index f6648b776..7905114b8 100644 --- a/src/arch/alpha/types.hh +++ b/src/arch/alpha/types.hh @@ -32,47 +32,43 @@ #ifndef __ARCH_ALPHA_TYPES_HH__ #define __ARCH_ALPHA_TYPES_HH__ -#include <inttypes.h> +#include "sim/host.hh" -namespace AlphaISA -{ - - typedef uint32_t MachInst; - typedef uint64_t ExtMachInst; - typedef uint8_t RegIndex; +namespace AlphaISA { - typedef uint64_t IntReg; - typedef uint64_t LargestRead; +typedef uint32_t MachInst; +typedef uint64_t ExtMachInst; +typedef uint8_t RegIndex; - // floating point register file entry type - typedef double FloatReg; - typedef uint64_t FloatRegBits; +typedef uint64_t IntReg; +typedef uint64_t LargestRead; - // control register file contents - typedef uint64_t MiscReg; +// floating point register file entry type +typedef double FloatReg; +typedef uint64_t FloatRegBits; - typedef union { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; +// control register file contents +typedef uint64_t MiscReg; - enum RegContextParam - { - CONTEXT_PALMODE - }; +union AnyReg +{ + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; +}; - typedef bool RegContextVal; +enum annotes +{ + ANNOTE_NONE = 0, + // An impossible number for instruction annotations + ITOUCH_ANNOTE = 0xffffffff, +}; - enum annotes { - ANNOTE_NONE = 0, - // An impossible number for instruction annotations - ITOUCH_ANNOTE = 0xffffffff, - }; +struct CoreSpecific +{ + int core_type; +}; - struct CoreSpecific { - int core_type; - }; } // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_TYPES_HH__ diff --git a/src/arch/alpha/utility.cc b/src/arch/alpha/utility.cc index f1864203b..763da0d4f 100644 --- a/src/arch/alpha/utility.cc +++ b/src/arch/alpha/utility.cc @@ -36,28 +36,28 @@ #include "mem/vport.hh" #endif -namespace AlphaISA -{ +namespace AlphaISA { -uint64_t getArgument(ThreadContext *tc, int number, bool fp) +uint64_t +getArgument(ThreadContext *tc, int number, bool fp) { #if FULL_SYSTEM + const int NumArgumentRegs = 6; if (number < NumArgumentRegs) { if (fp) - return tc->readFloatRegBits(ArgumentReg[number]); + return tc->readFloatRegBits(16 + number); else - return tc->readIntReg(ArgumentReg[number]); + return tc->readIntReg(16 + number); } else { Addr sp = tc->readIntReg(StackPointerReg); - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); uint64_t arg = vp->read<uint64_t>(sp + (number-NumArgumentRegs) * sizeof(uint64_t)); - tc->delVirtPort(vp); return arg; } #else panic("getArgument() is Full system only\n"); - M5_DUMMY_RETURN + M5_DUMMY_RETURN; #endif } diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh index 11357bc44..76c6c5726 100644 --- a/src/arch/alpha/utility.hh +++ b/src/arch/alpha/utility.hh @@ -32,127 +32,137 @@ #ifndef __ARCH_ALPHA_UTILITY_HH__ #define __ARCH_ALPHA_UTILITY_HH__ -#include "config/full_system.hh" #include "arch/alpha/types.hh" #include "arch/alpha/isa_traits.hh" #include "arch/alpha/regfile.hh" #include "base/misc.hh" +#include "config/full_system.hh" #include "cpu/thread_context.hh" -namespace AlphaISA +namespace AlphaISA { + +uint64_t getArgument(ThreadContext *tc, int number, bool fp); + +inline bool +inUserMode(ThreadContext *tc) +{ + return (tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0; +} + +inline bool +isCallerSaveIntegerRegister(unsigned int reg) +{ + panic("register classification not implemented"); + return (reg >= 1 && reg <= 8) || (reg >= 22 && reg <= 25) || reg == 27; +} + +inline bool +isCalleeSaveIntegerRegister(unsigned int reg) +{ + panic("register classification not implemented"); + return reg >= 9 && reg <= 15; +} + +inline bool +isCallerSaveFloatRegister(unsigned int reg) +{ + panic("register classification not implemented"); + return false; +} + +inline bool +isCalleeSaveFloatRegister(unsigned int reg) +{ + panic("register classification not implemented"); + return false; +} + +inline Addr +alignAddress(const Addr &addr, unsigned int nbytes) +{ + return (addr & ~(nbytes - 1)); +} + +// Instruction address compression hooks +inline Addr +realPCToFetchPC(const Addr &addr) +{ + return addr; +} + +inline Addr +fetchPCToRealPC(const Addr &addr) { + return addr; +} - uint64_t getArgument(ThreadContext *tc, int number, bool fp); - - static inline bool - inUserMode(ThreadContext *tc) - { - return (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - } - - inline bool isCallerSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); - } - - inline bool isCalleeSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 9 && reg <= 15); - } - - inline bool isCallerSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - inline bool isCalleeSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - inline Addr alignAddress(const Addr &addr, - unsigned int nbytes) { - return (addr & ~(nbytes - 1)); - } - - // Instruction address compression hooks - inline Addr realPCToFetchPC(const Addr &addr) { - return addr; - } - - inline Addr fetchPCToRealPC(const Addr &addr) { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - inline size_t fetchInstSize() { - return sizeof(MachInst); - } - - inline MachInst makeRegisterCopy(int dest, int src) { - panic("makeRegisterCopy not implemented"); - return 0; - } - - // Machine operations - - void saveMachineReg(AnyReg &savereg, const RegFile ®_file, - int regnum); - - void restoreMachineReg(RegFile ®s, const AnyReg ®, - int regnum); - - /** - * Function to insure ISA semantics about 0 registers. - * @param tc The thread context. - */ - template <class TC> - void zeroRegisters(TC *tc); - - // Alpha IPR register accessors - inline bool PcPAL(Addr addr) { return addr & 0x3; } - inline void startupCPU(ThreadContext *tc, int cpuId) { - tc->activate(0); - } - - //////////////////////////////////////////////////////////////////////// - // - // Translation stuff - // - - inline Addr PteAddr(Addr a) { return (a & PteMask) << PteShift; } - - // User Virtual - inline bool IsUSeg(Addr a) { return USegBase <= a && a <= USegEnd; } - - // Kernel Direct Mapped - inline bool IsK0Seg(Addr a) { return K0SegBase <= a && a <= K0SegEnd; } - inline Addr K0Seg2Phys(Addr addr) { return addr & ~K0SegBase; } - - // Kernel Virtual - inline bool IsK1Seg(Addr a) { return K1SegBase <= a && a <= K1SegEnd; } - - inline Addr - TruncPage(Addr addr) - { return addr & ~(PageBytes - 1); } - - inline Addr - RoundPage(Addr addr) - { return (addr + PageBytes - 1) & ~(PageBytes - 1); } - - void initIPRs(ThreadContext *tc, int cpuId); +// the size of "fetched" instructions (not necessarily the size +// of real instructions for PISA) +inline size_t +fetchInstSize() +{ + return sizeof(MachInst); +} + +inline MachInst +makeRegisterCopy(int dest, int src) +{ + panic("makeRegisterCopy not implemented"); + return 0; +} + +// Machine operations +void saveMachineReg(AnyReg &savereg, const RegFile ®_file, int regnum); +void restoreMachineReg(RegFile ®s, const AnyReg ®, int regnum); + +/** + * Function to insure ISA semantics about 0 registers. + * @param tc The thread context. + */ +template <class TC> +void zeroRegisters(TC *tc); + +// Alpha IPR register accessors +inline bool PcPAL(Addr addr) { return addr & 0x3; } +inline void startupCPU(ThreadContext *tc, int cpuId) { tc->activate(0); } + +//////////////////////////////////////////////////////////////////////// +// +// Translation stuff +// + +inline Addr PteAddr(Addr a) { return (a & PteMask) << PteShift; } + +// User Virtual +inline bool IsUSeg(Addr a) { return USegBase <= a && a <= USegEnd; } + +// Kernel Direct Mapped +inline bool IsK0Seg(Addr a) { return K0SegBase <= a && a <= K0SegEnd; } +inline Addr K0Seg2Phys(Addr addr) { return addr & ~K0SegBase; } + +// Kernel Virtual +inline bool IsK1Seg(Addr a) { return K1SegBase <= a && a <= K1SegEnd; } + +inline Addr +TruncPage(Addr addr) +{ return addr & ~(PageBytes - 1); } + +inline Addr +RoundPage(Addr addr) +{ return (addr + PageBytes - 1) & ~(PageBytes - 1); } + +void initIPRs(ThreadContext *tc, int cpuId); #if FULL_SYSTEM - void initCPU(ThreadContext *tc, int cpuId); - - /** - * Function to check for and process any interrupts. - * @param tc The thread context. - */ - template <class TC> - void processInterrupts(TC *tc); +void initCPU(ThreadContext *tc, int cpuId); + +/** + * Function to check for and process any interrupts. + * @param tc The thread context. + */ +template <class TC> +void processInterrupts(TC *tc); #endif } // namespace AlphaISA -#endif +#endif // __ARCH_ALPHA_UTILITY_HH__ diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc index 6ffbea181..4a043d8d1 100644 --- a/src/arch/alpha/vtophys.cc +++ b/src/arch/alpha/vtophys.cc @@ -40,27 +40,28 @@ #include "mem/vport.hh" using namespace std; -using namespace AlphaISA; -AlphaISA::PageTableEntry -AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr) +namespace AlphaISA { + +PageTableEntry +kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, VAddr vaddr) { Addr level1_pte = ptbr + vaddr.level1(); - AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte); + PageTableEntry level1 = mem->read<uint64_t>(level1_pte); if (!level1.valid()) { DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); return 0; } Addr level2_pte = level1.paddr() + vaddr.level2(); - AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte); + PageTableEntry level2 = mem->read<uint64_t>(level2_pte); if (!level2.valid()) { DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); return 0; } Addr level3_pte = level2.paddr() + vaddr.level3(); - AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte); + PageTableEntry level3 = mem->read<uint64_t>(level3_pte); if (!level3.valid()) { DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); return 0; @@ -69,13 +70,13 @@ AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vadd } Addr -AlphaISA::vtophys(Addr vaddr) +vtophys(Addr vaddr) { Addr paddr = 0; - if (AlphaISA::IsUSeg(vaddr)) + if (IsUSeg(vaddr)) DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); - else if (AlphaISA::IsK0Seg(vaddr)) - paddr = AlphaISA::K0Seg2Phys(vaddr); + else if (IsK0Seg(vaddr)) + paddr = K0Seg2Phys(vaddr); else panic("vtophys: ptbr is not set on virtual lookup"); @@ -85,22 +86,22 @@ AlphaISA::vtophys(Addr vaddr) } Addr -AlphaISA::vtophys(ThreadContext *tc, Addr addr) +vtophys(ThreadContext *tc, Addr addr) { - AlphaISA::VAddr vaddr = addr; - Addr ptbr = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp20); + VAddr vaddr = addr; + Addr ptbr = tc->readMiscRegNoEffect(IPR_PALtemp20); Addr paddr = 0; //@todo Andrew couldn't remember why he commented some of this code //so I put it back in. Perhaps something to do with gdb debugging? - if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { + if (PcPAL(vaddr) && (vaddr < PalMax)) { paddr = vaddr & ~ULL(1); } else { - if (AlphaISA::IsK0Seg(vaddr)) { - paddr = AlphaISA::K0Seg2Phys(vaddr); + if (IsK0Seg(vaddr)) { + paddr = K0Seg2Phys(vaddr); } else if (!ptbr) { paddr = vaddr; } else { - AlphaISA::PageTableEntry pte = + PageTableEntry pte = kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr); if (pte.valid()) paddr = pte.paddr() | vaddr.offset(); @@ -113,3 +114,4 @@ AlphaISA::vtophys(ThreadContext *tc, Addr addr) return paddr; } +} // namespace AlphaISA diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh index bd2ee8468..b13afd090 100644 --- a/src/arch/alpha/vtophys.hh +++ b/src/arch/alpha/vtophys.hh @@ -41,12 +41,13 @@ class FunctionalPort; namespace AlphaISA { - PageTableEntry - kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr); +PageTableEntry kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, + VAddr vaddr); - Addr vtophys(Addr vaddr); - Addr vtophys(ThreadContext *tc, Addr vaddr); +Addr vtophys(Addr vaddr); +Addr vtophys(ThreadContext *tc, Addr vaddr); + +} // namespace AlphaISA -}; #endif // __ARCH_ALPHA_VTOPHYS_H__ diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py index 21253edef..fa9faaddf 100644 --- a/src/arch/arm/ArmTLB.py +++ b/src/arch/arm/ArmTLB.py @@ -34,25 +34,21 @@ from m5.params import * class ArmTLB(SimObject): abstract = True type = 'ArmTLB' - cxx_namespace = 'ArmISA' - cxx_class = 'TLB' + cxx_class = 'ArmISA::TLB' size = Param.Int("TLB size") class ArmDTB(ArmTLB): type = 'ArmDTB' - cxx_namespace = 'ArmISA' - cxx_class = 'DTB' + cxx_class = 'ArmISA::DTB' size = 64 class ArmITB(ArmTLB): type = 'ArmITB' - cxx_namespace = 'ArmISA' - cxx_class = 'ITB' + cxx_class = 'ArmISA::ITB' size = 64 class ArmUTB(ArmTLB): type = 'ArmUTB' - cxx_namespace = 'ArmISA' - cxx_class = 'UTB' + cxx_class = 'ArmISA::UTB' size = 64 diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh index 253114ad1..cf07699ce 100644 --- a/src/arch/arm/isa_traits.hh +++ b/src/arch/arm/isa_traits.hh @@ -131,9 +131,6 @@ namespace ArmISA const int ZeroReg = NumIntArchRegs; const int AddrReg = ZeroReg + 1; // Used to generate address for uops - const int ArgumentReg[] = {0, 1, 2, 3}; - const int NumArgumentRegs = sizeof(ArgumentReg)/ sizeof(const int); - const int SyscallNumReg = ReturnValueReg; const int SyscallPseudoReturnReg = ReturnValueReg; const int SyscallSuccessReg = ReturnValueReg; diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc index 6d3153063..46b2f9bee 100644 --- a/src/arch/arm/linux/process.cc +++ b/src/arch/arm/linux/process.cc @@ -49,7 +49,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -79,7 +79,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", chmodFunc<ArmLinux>), /* 16 */ SyscallDesc("lchown", chownFunc), - /* 17 */ SyscallDesc("break", obreakFunc), //??? + /* 17 */ SyscallDesc("break", brkFunc), //??? /* 18 */ SyscallDesc("unused#18", unimplementedFunc), //??? /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getpid", getpidFunc), @@ -107,7 +107,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 42 */ SyscallDesc("pipe", unimplementedFunc), /* 43 */ SyscallDesc("times", unimplementedFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), - /* 45 */ SyscallDesc("brk", obreakFunc), + /* 45 */ SyscallDesc("brk", brkFunc), /* 46 */ SyscallDesc("setgid", unimplementedFunc), /* 47 */ SyscallDesc("getgid", getgidFunc), /* 48 */ SyscallDesc("signal", ignoreFunc), diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc index 00ba414ba..365d5b22c 100644 --- a/src/arch/arm/process.cc +++ b/src/arch/arm/process.cc @@ -43,8 +43,7 @@ using namespace std; using namespace ArmISA; -ArmLiveProcess::ArmLiveProcess(LiveProcessParams * params, - ObjectFile *objFile) +ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile) : LiveProcess(params, objFile) { stack_base = 0xc0000000L; @@ -147,12 +146,35 @@ ArmLiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(0xffff0fe0, insns, 8); */ - threadContexts[0]->setIntReg(ArgumentReg1, argc); - threadContexts[0]->setIntReg(ArgumentReg2, argv_array_base); - threadContexts[0]->setIntReg(StackPointerReg, stack_min); + ThreadContext *tc = system->getThreadContext(contextIds[0]); + + tc->setIntReg(ArgumentReg1, argc); + tc->setIntReg(ArgumentReg2, argv_array_base); + tc->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); - threadContexts[0]->setPC(prog_entry); - threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); +} + +ArmISA::IntReg +ArmLiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < 4); + return tc->readIntReg(ArgumentReg0 + i); } +void +ArmLiveProcess::setSyscallArg(ThreadContext *tc, + int i, ArmISA::IntReg val) +{ + assert(i < 4); + tc->setIntReg(ArgumentReg0 + i, val); +} + +void +ArmLiveProcess::setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) +{ + tc->setIntReg(ReturnValueReg, return_value.value()); +} diff --git a/src/arch/arm/process.hh b/src/arch/arm/process.hh index b97f4b0d2..8954d3719 100644 --- a/src/arch/arm/process.hh +++ b/src/arch/arm/process.hh @@ -53,6 +53,9 @@ class ArmLiveProcess : public LiveProcess public: void argsInit(int intSize, int pageSize); + ArmISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val); + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); }; #endif // __ARM_PROCESS_HH__ diff --git a/src/arch/arm/regfile/regfile.cc b/src/arch/arm/regfile/regfile.cc index 5de0b3076..a4d6e9a4a 100644 --- a/src/arch/arm/regfile/regfile.cc +++ b/src/arch/arm/regfile/regfile.cc @@ -55,7 +55,7 @@ MiscRegFile::copyMiscRegs(ThreadContext *tc) } void -RegFile::serialize(std::ostream &os) +RegFile::serialize(EventManager *em, ostream &os) { intRegFile.serialize(os); //SERIALIZE_ARRAY(floatRegFile, NumFloatRegs); @@ -69,7 +69,7 @@ RegFile::serialize(std::ostream &os) } void -RegFile::unserialize(Checkpoint *cp, const std::string §ion) +RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) { intRegFile.unserialize(cp, section); //UNSERIALIZE_ARRAY(floatRegFile); diff --git a/src/arch/arm/regfile/regfile.hh b/src/arch/arm/regfile/regfile.hh index 86799f18d..7f4d21353 100644 --- a/src/arch/arm/regfile/regfile.hh +++ b/src/arch/arm/regfile/regfile.hh @@ -38,11 +38,13 @@ #include "sim/faults.hh" class Checkpoint; +class EventManager; class ThreadContext; namespace ArmISA { - class RegFile { + class RegFile + { protected: IntRegFile intRegFile; // (signed) integer register file FloatRegFile floatRegFile; // floating point register file @@ -176,8 +178,9 @@ namespace ArmISA //nnpc = val; } - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); void changeContext(RegContextParam param, RegContextVal val) { diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index d0cc57a1d..78eebddfe 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -29,6 +29,7 @@ * * Authors: Nathan Binkert * Steve Reinhardt + * Jaidev Patwardhan * Stephen Hines */ @@ -149,7 +150,7 @@ TLB::checkCacheability(RequestPtr &req) // or by the TLB entry if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) { // mark request as uncacheable - req->setFlags(req->getFlags() | UNCACHEABLE); + req->setFlags(req->getFlags() | Request::UNCACHEABLE); } return NoFault; } @@ -278,7 +279,7 @@ TLB::regStats() } Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -293,8 +294,17 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) #endif } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + + Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -309,6 +319,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) #endif } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + /////////////////////////////////////////////////////////////////////// // // Arm ITB diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 59fe1a60d..fea317ef3 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -62,6 +62,12 @@ struct TlbEntry TlbEntry() {} TlbEntry(Addr asn, Addr vaddr, Addr paddr) : _pageStart(paddr) {} + void + updateVaddr(Addr new_vaddr) + { + panic("unimplemented"); + } + Addr pageStart() { return _pageStart; @@ -92,14 +98,14 @@ class TLB : public BaseTLB void nextnlu() { if (++nlu >= size) nlu = 0; } ArmISA::PTE *lookup(Addr vpn, uint8_t asn) const; - mutable Stats::Scalar<> read_hits; - mutable Stats::Scalar<> read_misses; - mutable Stats::Scalar<> read_acv; - mutable Stats::Scalar<> read_accesses; - mutable Stats::Scalar<> write_hits; - mutable Stats::Scalar<> write_misses; - mutable Stats::Scalar<> write_acv; - mutable Stats::Scalar<> write_accesses; + mutable Stats::Scalar read_hits; + mutable Stats::Scalar read_misses; + mutable Stats::Scalar read_acv; + mutable Stats::Scalar read_accesses; + mutable Stats::Scalar write_hits; + mutable Stats::Scalar write_misses; + mutable Stats::Scalar write_acv; + mutable Stats::Scalar write_accesses; Stats::Formula hits; Stats::Formula misses; Stats::Formula invalids; @@ -136,23 +142,30 @@ class TLB : public BaseTLB void regStats(); }; -class ITB : public TLB { +class ITB : public TLB +{ public: typedef ArmTLBParams Params; ITB(const Params *p); - Fault translate(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); }; -class DTB : public TLB { +class DTB : public TLB +{ public: typedef ArmTLBParams Params; DTB(const Params *p); - Fault translate(RequestPtr &req, ThreadContext *tc, bool write = false); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); }; -class UTB : public ITB, public DTB { +class UTB : public ITB, public DTB +{ public: typedef ArmTLBParams Params; UTB(const Params *p); diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index bbdd95bb0..25cf84b30 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -116,7 +116,7 @@ t_SEMI = r';' t_DOT = r'\.' t_COLON = r':' t_DBLCOLON = r'::' -t_ASTERISK = r'\*' +t_ASTERISK = r'\*' # Identifiers and reserved words reserved_map = { } @@ -480,7 +480,7 @@ def p_excess_args_param(t): # # A decode block looks like: -# decode <field1> [, <field2>]* [default <inst>] { ... } +# decode <field1> [, <field2>]* [default <inst>] { ... } # def p_decode_block(t): 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' @@ -1149,7 +1149,7 @@ def buildOperandTypeMap(userDict, lineno): ctype = 'uint%d_t' % size is_signed = 0 elif desc == 'float': - is_signed = 1 # shouldn't really matter + is_signed = 1 # shouldn't really matter if size == 32: ctype = 'float' elif size == 64: @@ -1595,9 +1595,9 @@ def buildOperandNameMap(userDict, lineno): operands = userDict.keys() operandsREString = (r''' - (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches + (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix - (?![\w\.]) # neg. lookahead assertion: prevent partial matches + (?![\w\.]) # neg. lookahead assertion: prevent partial matches ''' % string.join(operands, '|')) diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh index c10ce7350..de070bbf9 100644 --- a/src/arch/isa_specific.hh +++ b/src/arch/isa_specific.hh @@ -38,7 +38,7 @@ //To use them, do something like: // //#if THE_ISA == YOUR_FAVORITE_ISA -// conditional_code +// conditional_code //#endif // //Note that this is how this file sets up the TheISA macro. diff --git a/src/arch/micro_asm.py b/src/arch/micro_asm.py index 36c9919c0..3433a8076 100644 --- a/src/arch/micro_asm.py +++ b/src/arch/micro_asm.py @@ -141,7 +141,7 @@ def handle_statement(parser, container, statement): try: for label in statement.labels: container.labels[label.text] = microop - if label.extern: + if label.is_extern: container.externs[label.text] = microop container.add_microop(statement.mnemonic, microop) except: @@ -242,7 +242,10 @@ def t_params_PARAMS(t): def t_asm_ID(t): r'[A-Za-z_]\w*' t.type = reserved_map.get(t.value, 'ID') - t.lexer.begin('params') + # If the ID is really "extern", we shouldn't start looking for parameters + # yet. The real ID, the label itself, is coming up. + if t.type != 'EXTERN': + t.lexer.begin('params') return t # If there is a label and you're -not- in the assembler (which would be caught diff --git a/src/arch/mips/MipsInterrupts.py b/src/arch/mips/MipsInterrupts.py new file mode 100644 index 000000000..06cd54263 --- /dev/null +++ b/src/arch/mips/MipsInterrupts.py @@ -0,0 +1,33 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject + +class MipsInterrupts(SimObject): + type = 'MipsInterrupts' + cxx_class = 'MipsISA::Interrupts' diff --git a/src/arch/mips/MipsTLB.py b/src/arch/mips/MipsTLB.py index ce8847365..41d46c572 100644 --- a/src/arch/mips/MipsTLB.py +++ b/src/arch/mips/MipsTLB.py @@ -32,28 +32,25 @@ from m5.SimObject import SimObject from m5.params import * -class MipsTLB(SimObject): - abstract = True +from BaseTLB import BaseTLB + +class MipsTLB(BaseTLB): type = 'MipsTLB' - cxx_namespace = 'MipsISA' - cxx_class = 'TLB' + abstract = True size = Param.Int("TLB size") class MipsDTB(MipsTLB): type = 'MipsDTB' - cxx_namespace = 'MipsISA' - cxx_class = 'DTB' + cxx_class = 'MipsISA::DTB' size = 64 class MipsITB(MipsTLB): type = 'MipsITB' - cxx_namespace = 'MipsISA' - cxx_class = 'ITB' + cxx_class = 'MipsISA::ITB' size = 64 class MipsUTB(MipsTLB): type = 'MipsUTB' - cxx_namespace = 'MipsISA' - cxx_class = 'UTB' + cxx_class = 'MipsISA::UTB' size = 64 diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript index 8be445c99..0b470def6 100644 --- a/src/arch/mips/SConscript +++ b/src/arch/mips/SConscript @@ -48,6 +48,7 @@ if env['TARGET_ISA'] == 'mips': if env['FULL_SYSTEM']: SimObject('MipsSystem.py') + SimObject('MipsInterrupts.py') Source('idle_event.cc') Source('mips_core_specific.cc') Source('vtophys.cc') diff --git a/src/arch/mips/bare_iron/system.hh b/src/arch/mips/bare_iron/system.hh index ab4e02344..e593f832c 100755 --- a/src/arch/mips/bare_iron/system.hh +++ b/src/arch/mips/bare_iron/system.hh @@ -39,8 +39,6 @@ class IdleStartEvent; #include "arch/mips/system.hh" #include "params/BareIronMipsSystem.hh" -using namespace MipsISA; - /** * This class contains linux specific system code (Loading, Events). * It points to objects that are the system binaries to load and patches them diff --git a/src/arch/mips/dsp.cc b/src/arch/mips/dsp.cc index 8e2db3f0b..6e4f7afea 100755 --- a/src/arch/mips/dsp.cc +++ b/src/arch/mips/dsp.cc @@ -40,92 +40,84 @@ using namespace MipsISA; using namespace std; int32_t -MipsISA::bitrev( int32_t value ) +MipsISA::bitrev(int32_t value) { int32_t result = 0; - int i, shift; + int shift; - for( i=0; i<16; i++ ) - { - shift = 2*i - 15; + for (int i = 0; i < 16; i++) { + shift = 2 * i - 15; - if( shift < 0 ) - result |= (value & 1L<<i) << -shift; + if (shift < 0) + result |= (value & 1 << i) << -shift; else - result |= (value & 1L<<i) >> shift; + result |= (value & 1 << i) >> shift; } return result; } uint64_t -MipsISA::dspSaturate( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow ) +MipsISA::dspSaturate(uint64_t value, int32_t fmt, int32_t sign, + uint32_t *overflow) { - int64_t svalue; + int64_t svalue = (int64_t)value; - svalue = (int64_t)value; - - switch( sign ) - { + switch (sign) { case SIGNED: - if( svalue > (int64_t)FIXED_SMAX[fmt] ) - { + if (svalue > (int64_t)FIXED_SMAX[fmt]) { *overflow = 1; svalue = (int64_t)FIXED_SMAX[fmt]; - } - else if( svalue < (int64_t)FIXED_SMIN[fmt] ) - { + } else if (svalue < (int64_t)FIXED_SMIN[fmt]) { *overflow = 1; svalue = (int64_t)FIXED_SMIN[fmt]; } break; case UNSIGNED: - if( svalue > (int64_t)FIXED_UMAX[fmt] ) - { + if (svalue > (int64_t)FIXED_UMAX[fmt]) { *overflow = 1; svalue = FIXED_UMAX[fmt]; - } - else if( svalue < (int64_t)FIXED_UMIN[fmt] ) - { + } else if (svalue < (int64_t)FIXED_UMIN[fmt]) { *overflow = 1; svalue = FIXED_UMIN[fmt]; } break; } - return( (uint64_t)svalue ); + return (uint64_t)svalue; } uint64_t -MipsISA::checkOverflow( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow ) +MipsISA::checkOverflow(uint64_t value, int32_t fmt, int32_t sign, + uint32_t *overflow) { - int64_t svalue; - - svalue = (int64_t)value; + int64_t svalue = (int64_t)value; - switch( sign ) + switch (sign) { case SIGNED: - if( svalue > (int64_t)FIXED_SMAX[fmt] || svalue < (int64_t)FIXED_SMIN[fmt] ) + if (svalue > (int64_t)FIXED_SMAX[fmt] || + svalue < (int64_t)FIXED_SMIN[fmt]) *overflow = 1; break; case UNSIGNED: - if( svalue > (int64_t)FIXED_UMAX[fmt] || svalue < (int64_t)FIXED_UMIN[fmt] ) + if (svalue > (int64_t)FIXED_UMAX[fmt] || + svalue < (int64_t)FIXED_UMIN[fmt]) *overflow = 1; break; } - return( (uint64_t)svalue ); + return (uint64_t)svalue; } uint64_t -MipsISA::signExtend( uint64_t value, int32_t fmt ) +MipsISA::signExtend(uint64_t value, int32_t fmt) { int32_t signpos = SIMD_NBITS[fmt]; - uint64_t sign = uint64_t(1)<<(signpos-1); + uint64_t sign = uint64_t(1) << (signpos - 1); uint64_t ones = ~(0ULL); - if( value & sign ) + if (value & sign) value |= (ones << signpos); // extend with ones else value &= (ones >> (64 - signpos)); // extend with zeros @@ -134,231 +126,230 @@ MipsISA::signExtend( uint64_t value, int32_t fmt ) } uint64_t -MipsISA::addHalfLsb( uint64_t value, int32_t lsbpos ) +MipsISA::addHalfLsb(uint64_t value, int32_t lsbpos) { - return( value += ULL(1) << (lsbpos-1) ); + return value += ULL(1) << (lsbpos - 1); } int32_t -MipsISA::dspAbs( int32_t a, int32_t fmt, uint32_t *dspctl ) +MipsISA::dspAbs(int32_t a, int32_t fmt, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; int64_t svalue; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) - { + for (int i = 0; i < nvals; i++) { svalue = (int64_t)a_values[i]; - if( a_values[i] == FIXED_SMIN[fmt] ) - { + if (a_values[i] == FIXED_SMIN[fmt]) { a_values[i] = FIXED_SMAX[fmt]; ouflag = 1; - } - else if( svalue < 0 ) - { - a_values[i] = uint64_t( 0 - svalue ); + } else if (svalue < 0) { + a_values[i] = uint64_t(0 - svalue); } } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspAdd( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ) +MipsISA::dspAdd(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) + for (int i = 0; i < nvals; i++) { - if( saturate ) - a_values[i] = dspSaturate( a_values[i] + b_values[i], fmt, sign, &ouflag ); + if (saturate) + a_values[i] = dspSaturate(a_values[i] + b_values[i], fmt, sign, + &ouflag); else - a_values[i] = checkOverflow( a_values[i] + b_values[i], fmt, sign, &ouflag ); + a_values[i] = checkOverflow(a_values[i] + b_values[i], fmt, sign, + &ouflag); } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspAddh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign ) +MipsISA::dspAddh(int32_t a, int32_t b, int32_t fmt, int32_t round, + int32_t sign) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) - { - if( round ) - a_values[i] = addHalfLsb( a_values[i] + b_values[i], 1 ) >> 1; + for (int i = 0; i < nvals; i++) { + if (round) + a_values[i] = addHalfLsb(a_values[i] + b_values[i], 1) >> 1; else - a_values[i] = ( a_values[i] + b_values[i] ) >> 1; + a_values[i] = (a_values[i] + b_values[i]) >> 1; } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspSub( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ) +MipsISA::dspSub(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) - { - if( saturate ) - a_values[i] = dspSaturate( a_values[i] - b_values[i], fmt, sign, &ouflag ); + for (int i = 0; i < nvals; i++) { + if (saturate) + a_values[i] = dspSaturate(a_values[i] - b_values[i], fmt, sign, + &ouflag); else - a_values[i] = checkOverflow( a_values[i] - b_values[i], fmt, sign, &ouflag ); + a_values[i] = checkOverflow(a_values[i] - b_values[i], fmt, sign, + &ouflag); } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspSubh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign ) +MipsISA::dspSubh(int32_t a, int32_t b, int32_t fmt, int32_t round, + int32_t sign) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) + for (int i = 0; i < nvals; i++) { - if( round ) - a_values[i] = addHalfLsb( a_values[i] - b_values[i], 1 ) >> 1; + if (round) + a_values[i] = addHalfLsb(a_values[i] - b_values[i], 1) >> 1; else - a_values[i] = ( a_values[i] - b_values[i] ) >> 1; + a_values[i] = (a_values[i] - b_values[i]) >> 1; } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspShll( int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ) +MipsISA::dspShll(int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; - sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 ); - simdUnpack( a, a_values, fmt, sign ); + sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); + simdUnpack(a, a_values, fmt, sign); - for( i=0; i<nvals; i++ ) + for (int i = 0; i < nvals; i++) { - if( saturate ) - a_values[i] = dspSaturate( a_values[i] << sa, fmt, sign, &ouflag ); + if (saturate) + a_values[i] = dspSaturate(a_values[i] << sa, fmt, sign, &ouflag); else - a_values[i] = checkOverflow( a_values[i] << sa, fmt, sign, &ouflag ); + a_values[i] = checkOverflow(a_values[i] << sa, fmt, sign, &ouflag); } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<6)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 6) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspShrl( int32_t a, uint32_t sa, int32_t fmt, int32_t sign ) +MipsISA::dspShrl(int32_t a, uint32_t sa, int32_t fmt, int32_t sign) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; - sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 ); + sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); - simdUnpack( a, a_values, fmt, UNSIGNED ); + simdUnpack(a, a_values, fmt, UNSIGNED); - for( i=0; i<nvals; i++ ) + for (int i = 0; i < nvals; i++) a_values[i] = a_values[i] >> sa; - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspShra( int32_t a, uint32_t sa, int32_t fmt, int32_t round, int32_t sign, uint32_t *dspctl ) +MipsISA::dspShra(int32_t a, uint32_t sa, int32_t fmt, int32_t round, + int32_t sign, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; - sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 ); + sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); - simdUnpack( a, a_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - if( round ) - a_values[i] = addHalfLsb( a_values[i], sa ) >> sa; + for (int i = 0; i < nvals; i++) { + if (round) + a_values[i] = addHalfLsb(a_values[i], sa) >> sa; else a_values[i] = a_values[i] >> sa; } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t round, uint32_t *dspctl ) +MipsISA::dspMulq(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t round, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int sa = SIMD_NBITS[fmt]; int32_t result; @@ -367,102 +358,104 @@ MipsISA::dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t r uint64_t b_values[SIMD_MAX_VALS]; int64_t temp; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - if( round ) - temp = (int64_t)addHalfLsb( a_values[i] * b_values[i] << 1, sa ) >> sa; + for (int i = 0; i < nvals; i++) { + if (round) + temp = + (int64_t)addHalfLsb(a_values[i] * b_values[i] << 1, sa) >> sa; else temp = (int64_t)(a_values[i] * b_values[i]) >> (sa - 1); - if( a_values[i] == FIXED_SMIN[fmt] && - b_values[i] == FIXED_SMIN[fmt] ) - { + if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) { ouflag = 1; - if( saturate ) + if (saturate) temp = FIXED_SMAX[fmt]; } a_values[i] = temp; } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspMul( int32_t a, int32_t b, int32_t fmt, int32_t saturate, uint32_t *dspctl ) +MipsISA::dspMul(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) + for (int i = 0; i < nvals; i++) { - if( saturate ) - a_values[i] = dspSaturate( a_values[i] * b_values[i], fmt, SIGNED, &ouflag ); + if (saturate) + a_values[i] = dspSaturate(a_values[i] * b_values[i], fmt, SIGNED, + &ouflag); else - a_values[i] = checkOverflow( a_values[i] * b_values[i], fmt, SIGNED, &ouflag ); + a_values[i] = checkOverflow(a_values[i] * b_values[i], fmt, SIGNED, + &ouflag); } - simdPack( a_values, &result, fmt ); + simdPack(a_values, &result, fmt); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspMuleu( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl ) +MipsISA::dspMuleu(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[SIMD_FMT_PH]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, SIMD_FMT_QB, UNSIGNED ); - simdUnpack( b, b_values, SIMD_FMT_PH, UNSIGNED ); + simdUnpack(a, a_values, SIMD_FMT_QB, UNSIGNED); + simdUnpack(b, b_values, SIMD_FMT_PH, UNSIGNED); - switch( mode ) - { + switch (mode) { case MODE_L: - for( i=0; i<nvals; i++ ) - b_values[i] = dspSaturate( a_values[i+2] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag ); + for (int i = 0; i < nvals; i++) + b_values[i] = dspSaturate(a_values[i + 2] * b_values[i], + SIMD_FMT_PH, UNSIGNED, &ouflag); break; case MODE_R: - for( i=0; i<nvals; i++ ) - b_values[i] = dspSaturate( a_values[i] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag ); + for (int i = 0; i < nvals; i++) + b_values[i] = dspSaturate(a_values[i] * b_values[i], SIMD_FMT_PH, + UNSIGNED, &ouflag); break; } - simdPack( b_values, &result, SIMD_FMT_PH ); + simdPack(b_values, &result, SIMD_FMT_PH); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int32_t -MipsISA::dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl ) +MipsISA::dspMuleq(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[SIMD_FMT_W]; int32_t result; uint32_t ouflag = 0; @@ -470,36 +463,36 @@ MipsISA::dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl ) uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, SIMD_FMT_PH, SIGNED ); - simdUnpack( b, b_values, SIMD_FMT_PH, SIGNED ); + simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED); + simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED); - switch( mode ) - { + switch (mode) { case MODE_L: - for( i=0; i<nvals; i++ ) - c_values[i] = dspSaturate( a_values[i+1] * b_values[i+1] << 1, - SIMD_FMT_W, SIGNED, &ouflag ); + for (int i = 0; i < nvals; i++) + c_values[i] = dspSaturate(a_values[i + 1] * b_values[i + 1] << 1, + SIMD_FMT_W, SIGNED, &ouflag); break; case MODE_R: - for( i=0; i<nvals; i++ ) - c_values[i] = dspSaturate( a_values[i] * b_values[i] << 1, - SIMD_FMT_W, SIGNED, &ouflag ); + for (int i = 0; i < nvals; i++) + c_values[i] = dspSaturate(a_values[i] * b_values[i] << 1, + SIMD_FMT_W, SIGNED, &ouflag); break; } - simdPack( c_values, &result, SIMD_FMT_W ); + simdPack(c_values, &result, SIMD_FMT_W); - if( ouflag ) - writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG); + if (ouflag) + writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], + 1 << DSP_OUFLAG); - return( result ); + return result; } int64_t -MipsISA::dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, - int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl ) +MipsISA::dspDpaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, + uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[infmt]; int64_t result = 0; int64_t temp = 0; @@ -507,74 +500,66 @@ MipsISA::dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, infmt, SIGNED ); - simdUnpack( b, b_values, infmt, SIGNED ); + simdUnpack(a, a_values, infmt, SIGNED); + simdUnpack(b, b_values, infmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - switch( mode ) - { + for (int i = 0; i < nvals; i++) { + switch (mode) { case MODE_X: - if( a_values[nvals-1-i] == FIXED_SMIN[infmt] && - b_values[i] == FIXED_SMIN[infmt] ) - { + if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] && + b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; } else - result += a_values[nvals-1-i] * b_values[i] << 1; + result += a_values[nvals - 1 - i] * b_values[i] << 1; break; default: - if( a_values[i] == FIXED_SMIN[infmt] && - b_values[i] == FIXED_SMIN[infmt] ) - { + if (a_values[i] == FIXED_SMIN[infmt] && + b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; - } - else + } else { result += a_values[i] * b_values[i] << 1; + } break; } } - if( postsat ) - { - if( outfmt == SIMD_FMT_L ) - { - int signa = bits( dspac, 63, 63 ); - int signb = bits( result, 63, 63 ); + if (postsat) { + if (outfmt == SIMD_FMT_L) { + int signa = bits(dspac, 63, 63); + int signb = bits(result, 63, 63); temp = dspac + result; - if( ( signa == signb ) && - ( bits( temp, 63, 63 ) != signa ) ) - { + if (signa == signb && bits(temp, 63, 63) != signa) { ouflag = 1; - if( signa ) + if (signa) dspac = FIXED_SMIN[outfmt]; else dspac = FIXED_SMAX[outfmt]; - } - else + } else { dspac = temp; + } + } else { + dspac = dspSaturate(dspac + result, outfmt, SIGNED, &ouflag); } - else - dspac = dspSaturate( dspac + result, outfmt, SIGNED, &ouflag ); - } - else + } else { dspac += result; + } - if( ouflag ) - *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 ); + if (ouflag) + *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); - return( dspac ); + return dspac; } int64_t -MipsISA::dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, - int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl ) +MipsISA::dspDpsq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, + uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[infmt]; int64_t result = 0; int64_t temp = 0; @@ -582,93 +567,82 @@ MipsISA::dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, infmt, SIGNED ); - simdUnpack( b, b_values, infmt, SIGNED ); + simdUnpack(a, a_values, infmt, SIGNED); + simdUnpack(b, b_values, infmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - switch( mode ) - { + for (int i = 0; i < nvals; i++) { + switch (mode) { case MODE_X: - if( a_values[nvals-1-i] == FIXED_SMIN[infmt] && - b_values[i] == FIXED_SMIN[infmt] ) - { + if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] && + b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; + } else { + result += a_values[nvals - 1 - i] * b_values[i] << 1; } - else - result += a_values[nvals-1-i] * b_values[i] << 1; break; default: - if( a_values[i] == FIXED_SMIN[infmt] && - b_values[i] == FIXED_SMIN[infmt] ) - { + if (a_values[i] == FIXED_SMIN[infmt] && + b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; - } - else + } else { result += a_values[i] * b_values[i] << 1; + } break; } } - if( postsat ) - { - if( outfmt == SIMD_FMT_L ) - { - int signa = bits( dspac, 63, 63 ); - int signb = bits( -result, 63, 63 ); + if (postsat) { + if (outfmt == SIMD_FMT_L) { + int signa = bits(dspac, 63, 63); + int signb = bits(-result, 63, 63); temp = dspac - result; - if( ( signa == signb ) && - ( bits( temp, 63, 63 ) != signa ) ) - { + if (signa == signb && bits(temp, 63, 63) != signa) { ouflag = 1; - if( signa ) + if (signa) dspac = FIXED_SMIN[outfmt]; else dspac = FIXED_SMAX[outfmt]; - } - else + } else { dspac = temp; + } + } else { + dspac = dspSaturate(dspac - result, outfmt, SIGNED, &ouflag); } - else - dspac = dspSaturate( dspac - result, outfmt, SIGNED, &ouflag ); - } - else + } else { dspac -= result; + } - if( ouflag ) - *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 ); + if (ouflag) + *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); - return( dspac ); + return dspac; } int64_t -MipsISA::dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac, - int32_t fmt, int32_t sign, int32_t mode ) +MipsISA::dspDpa(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t fmt, int32_t sign, int32_t mode) { - int i = 0; int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<2; i++ ) - { - switch( mode ) - { + for (int i = 0; i < 2; i++) { + switch (mode) { case MODE_L: - dspac += a_values[nvals-1-i] * b_values[nvals-1-i]; + dspac += a_values[nvals - 1 - i] * b_values[nvals - 1 - i]; break; case MODE_R: - dspac += a_values[nvals-3-i] * b_values[nvals-3-i]; + dspac += a_values[nvals - 3 - i] * b_values[nvals - 3 - i]; break; case MODE_X: - dspac += a_values[nvals-1-i] * b_values[i]; + dspac += a_values[nvals - 1 - i] * b_values[i]; break; } } @@ -677,29 +651,26 @@ MipsISA::dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac, } int64_t -MipsISA::dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac, - int32_t fmt, int32_t sign, int32_t mode ) +MipsISA::dspDps(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t fmt, int32_t sign, int32_t mode) { - int i = 0; int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<2; i++ ) - { - switch( mode ) - { + for (int i = 0; i < 2; i++) { + switch (mode) { case MODE_L: - dspac -= a_values[nvals-1-i] * b_values[nvals-1-i]; + dspac -= a_values[nvals - 1 - i] * b_values[nvals - 1 - i]; break; case MODE_R: - dspac -= a_values[nvals-3-i] * b_values[nvals-3-i]; + dspac -= a_values[nvals - 3 - i] * b_values[nvals - 3 - i]; break; case MODE_X: - dspac -= a_values[nvals-1-i] * b_values[i]; + dspac -= a_values[nvals - 1 - i] * b_values[i]; break; } } @@ -708,36 +679,33 @@ MipsISA::dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac, } int64_t -MipsISA::dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, - int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl ) +MipsISA::dspMaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl) { - int i = 0; - int nvals = SIMD_NVALS[fmt-1]; + int nvals = SIMD_NVALS[fmt - 1]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; int64_t temp = 0; uint32_t ouflag = 0; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - switch( mode ) - { + for (int i = 0; i < nvals; i++) { + switch (mode) { case MODE_L: - temp = a_values[i+1] * b_values[i+1] << 1; - if( a_values[i+1] == FIXED_SMIN[fmt] && b_values[i+1] == FIXED_SMIN[fmt] ) - { - temp = (int64_t)FIXED_SMAX[fmt-1]; + temp = a_values[i + 1] * b_values[i + 1] << 1; + if (a_values[i + 1] == FIXED_SMIN[fmt] && + b_values[i + 1] == FIXED_SMIN[fmt]) { + temp = (int64_t)FIXED_SMAX[fmt - 1]; ouflag = 1; } break; case MODE_R: temp = a_values[i] * b_values[i] << 1; - if( a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt] ) - { - temp = (int64_t)FIXED_SMAX[fmt-1]; + if (a_values[i] == FIXED_SMIN[fmt] && + b_values[i] == FIXED_SMIN[fmt]) { + temp = (int64_t)FIXED_SMAX[fmt - 1]; ouflag = 1; } break; @@ -745,23 +713,23 @@ MipsISA::dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, temp += dspac; - if( saturate ) - temp = dspSaturate( temp, fmt-1, SIGNED, &ouflag ); - if( ouflag ) - *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 ); + if (saturate) + temp = dspSaturate(temp, fmt - 1, SIGNED, &ouflag); + if (ouflag) + *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); } return temp; } int64_t -MipsISA::dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt ) +MipsISA::dspMulsa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt) { uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); dspac += a_values[1] * b_values[1] - a_values[0] * b_values[0]; @@ -769,132 +737,140 @@ MipsISA::dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt } int64_t -MipsISA::dspMulsaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, uint32_t *dspctl ) +MipsISA::dspMulsaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t fmt, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; int64_t temp[2]; uint32_t ouflag = 0; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - for( i=nvals-1; i>-1; i-- ) - { + for (int i = nvals - 1; i > -1; i--) { temp[i] = a_values[i] * b_values[i] << 1; - if( a_values[i] == FIXED_SMIN[fmt] && - b_values[i] == FIXED_SMIN[fmt] ) - { - temp[i] = FIXED_SMAX[fmt-1]; + if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) { + temp[i] = FIXED_SMAX[fmt - 1]; ouflag = 1; } } dspac += temp[1] - temp[0]; - if( ouflag ) - *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 ); + if (ouflag) + *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); return dspac; } void -MipsISA::dspCmp( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl ) +MipsISA::dspCmp(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, + uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int ccond = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) - { + for (int i = 0; i < nvals; i++) { int cc = 0; - switch( op ) - { - case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break; - case CMP_LT: cc = ( a_values[i] < b_values[i] ); break; - case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break; + switch (op) { + case CMP_EQ: + cc = (a_values[i] == b_values[i]); + break; + case CMP_LT: + cc = (a_values[i] < b_values[i]); + break; + case CMP_LE: + cc = (a_values[i] <= b_values[i]); + break; } - ccond |= cc << ( DSP_CTL_POS[DSP_CCOND] + i ); + ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i); } - writeDSPControl( dspctl, ccond, 1<<DSP_CCOND ); + writeDSPControl(dspctl, ccond, 1 << DSP_CCOND); } int32_t -MipsISA::dspCmpg( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op ) +MipsISA::dspCmpg(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) - { + for (int i = 0; i < nvals; i++) { int cc = 0; - switch( op ) - { - case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break; - case CMP_LT: cc = ( a_values[i] < b_values[i] ); break; - case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break; + switch (op) { + case CMP_EQ: + cc = (a_values[i] == b_values[i]); + break; + case CMP_LT: + cc = (a_values[i] < b_values[i]); + break; + case CMP_LE: + cc = (a_values[i] <= b_values[i]); + break; } result |= cc << i; } - return( result ); + return result; } int32_t -MipsISA::dspCmpgd( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl ) +MipsISA::dspCmpgd(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, + uint32_t *dspctl) { - int i = 0;; int nvals = SIMD_NVALS[fmt]; int32_t result = 0; int ccond = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, sign ); - simdUnpack( b, b_values, fmt, sign ); + simdUnpack(a, a_values, fmt, sign); + simdUnpack(b, b_values, fmt, sign); - for( i=0; i<nvals; i++ ) - { - int cc = 0;; + for (int i = 0; i < nvals; i++) { + int cc = 0; - switch( op ) - { - case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break; - case CMP_LT: cc = ( a_values[i] < b_values[i] ); break; - case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break; + switch (op) { + case CMP_EQ: + cc = (a_values[i] == b_values[i]); + break; + case CMP_LT: + cc = (a_values[i] < b_values[i]); + break; + case CMP_LE: + cc = (a_values[i] <= b_values[i]); + break; } result |= cc << i; - ccond |= cc << ( DSP_CTL_POS[DSP_CCOND] + i ); + ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i); } - writeDSPControl( dspctl, ccond, 1<<DSP_CCOND ); + writeDSPControl(dspctl, ccond, 1 << DSP_CCOND); - return( result ); + return result; } int32_t -MipsISA::dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int32_t outsign, int32_t mode ) +MipsISA::dspPrece(int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, + int32_t outsign, int32_t mode) { - int i = 0; int sa = 0; int ninvals = SIMD_NVALS[infmt]; int noutvals = SIMD_NVALS[outfmt]; @@ -902,62 +878,68 @@ MipsISA::dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int uint64_t in_values[SIMD_MAX_VALS]; uint64_t out_values[SIMD_MAX_VALS]; - if( insign == SIGNED && outsign == SIGNED ) + if (insign == SIGNED && outsign == SIGNED) sa = SIMD_NBITS[infmt]; - else if( insign == UNSIGNED && outsign == SIGNED ) + else if (insign == UNSIGNED && outsign == SIGNED) sa = SIMD_NBITS[infmt] - 1; - else if( insign == UNSIGNED && outsign == UNSIGNED ) + else if (insign == UNSIGNED && outsign == UNSIGNED) sa = 0; - simdUnpack( a, in_values, infmt, insign ); + simdUnpack(a, in_values, infmt, insign); - for( i=0; i<noutvals; i++ ) - { - switch( mode ) - { - case MODE_L: out_values[i] = in_values[i+(ninvals>>1)] << sa; break; - case MODE_R: out_values[i] = in_values[i] << sa; break; - case MODE_LA: out_values[i] = in_values[(i<<1)+1] << sa; break; - case MODE_RA: out_values[i] = in_values[i<<1] << sa; break; + for (int i = 0; i<noutvals; i++) { + switch (mode) { + case MODE_L: + out_values[i] = in_values[i + (ninvals >> 1)] << sa; + break; + case MODE_R: + out_values[i] = in_values[i] << sa; + break; + case MODE_LA: + out_values[i] = in_values[(i << 1) + 1] << sa; + break; + case MODE_RA: + out_values[i] = in_values[i << 1] << sa; + break; } } - simdPack( out_values, &result, outfmt ); + simdPack(out_values, &result, outfmt); - return( result ); + return result; } int32_t -MipsISA::dspPrecrqu( int32_t a, int32_t b, uint32_t *dspctl ) +MipsISA::dspPrecrqu(int32_t a, int32_t b, uint32_t *dspctl) { - int i = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t r_values[SIMD_MAX_VALS]; uint32_t ouflag = 0; int32_t result = 0; - simdUnpack( a, a_values, SIMD_FMT_PH, SIGNED ); - simdUnpack( b, b_values, SIMD_FMT_PH, SIGNED ); + simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED); + simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED); - for( i=0; i<2; i++ ) - { - r_values[i] = dspSaturate( (int64_t)b_values[i] >> SIMD_NBITS[SIMD_FMT_QB] - 1, - SIMD_FMT_QB, UNSIGNED, &ouflag ); - r_values[i+2] = dspSaturate( (int64_t)a_values[i] >> SIMD_NBITS[SIMD_FMT_QB] - 1, - SIMD_FMT_QB, UNSIGNED, &ouflag ); + for (int i = 0; i<2; i++) { + r_values[i] = + dspSaturate((int64_t)b_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1), + SIMD_FMT_QB, UNSIGNED, &ouflag); + r_values[i + 2] = + dspSaturate((int64_t)a_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1), + SIMD_FMT_QB, UNSIGNED, &ouflag); } - simdPack( r_values, &result, SIMD_FMT_QB ); + simdPack(r_values, &result, SIMD_FMT_QB); - if( ouflag ) - *dspctl = insertBits( *dspctl, 22, 22, 1 ); + if (ouflag) + *dspctl = insertBits(*dspctl, 22, 22, 1); return result; } int32_t -MipsISA::dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl ) +MipsISA::dspPrecrq(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl) { uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; @@ -965,245 +947,226 @@ MipsISA::dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl ) uint32_t ouflag = 0; int32_t result; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - r_values[1] = dspSaturate( (int64_t)addHalfLsb( a_values[0], 16 ) >> 16, - fmt+1, SIGNED, &ouflag ); - r_values[0] = dspSaturate( (int64_t)addHalfLsb( b_values[0], 16 ) >> 16, - fmt+1, SIGNED, &ouflag ); + r_values[1] = dspSaturate((int64_t)addHalfLsb(a_values[0], 16) >> 16, + fmt + 1, SIGNED, &ouflag); + r_values[0] = dspSaturate((int64_t)addHalfLsb(b_values[0], 16) >> 16, + fmt + 1, SIGNED, &ouflag); - simdPack( r_values, &result, fmt+1 ); + simdPack(r_values, &result, fmt + 1); - if( ouflag ) - *dspctl = insertBits( *dspctl, 22, 22, 1 ); + if (ouflag) + *dspctl = insertBits(*dspctl, 22, 22, 1); return result; } int32_t -MipsISA::dspPrecrSra( int32_t a, int32_t b, int32_t sa, int32_t fmt, int32_t round ) +MipsISA::dspPrecrSra(int32_t a, int32_t b, int32_t sa, int32_t fmt, + int32_t round) { - int i = 0; int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; int32_t result = 0; - simdUnpack( a, a_values, fmt, SIGNED ); - simdUnpack( b, b_values, fmt, SIGNED ); + simdUnpack(a, a_values, fmt, SIGNED); + simdUnpack(b, b_values, fmt, SIGNED); - for( i=0; i<nvals; i++ ) - { - if( round ) - { - c_values[i] = addHalfLsb( b_values[i], sa ) >> sa; - c_values[i+1] = addHalfLsb( a_values[i], sa ) >> sa; - } - else - { + for (int i = 0; i < nvals; i++) { + if (round) { + c_values[i] = addHalfLsb(b_values[i], sa) >> sa; + c_values[i + 1] = addHalfLsb(a_values[i], sa) >> sa; + } else { c_values[i] = b_values[i] >> sa; - c_values[i+1] = a_values[i] >> sa; + c_values[i + 1] = a_values[i] >> sa; } } - simdPack( c_values, &result, fmt+1 ); + simdPack(c_values, &result, fmt + 1); return result; } int32_t -MipsISA::dspPick( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl ) +MipsISA::dspPick(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, UNSIGNED ); - simdUnpack( b, b_values, fmt, UNSIGNED ); + simdUnpack(a, a_values, fmt, UNSIGNED); + simdUnpack(b, b_values, fmt, UNSIGNED); - for( i=0; i<nvals; i++ ) - { + for (int i = 0; i < nvals; i++) { int condbit = DSP_CTL_POS[DSP_CCOND] + i; - if( bits( *dspctl, condbit, condbit ) == 1 ) + if (bits(*dspctl, condbit, condbit) == 1) c_values[i] = a_values[i]; else c_values[i] = b_values[i]; } - simdPack( c_values, &result, fmt ); + simdPack(c_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspPack( int32_t a, int32_t b, int32_t fmt ) +MipsISA::dspPack(int32_t a, int32_t b, int32_t fmt) { int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; - simdUnpack( a, a_values, fmt, UNSIGNED ); - simdUnpack( b, b_values, fmt, UNSIGNED ); + simdUnpack(a, a_values, fmt, UNSIGNED); + simdUnpack(b, b_values, fmt, UNSIGNED); c_values[0] = b_values[1]; c_values[1] = a_values[0]; - simdPack( c_values, &result, fmt ); + simdPack(c_values, &result, fmt); - return( result ); + return result; } int32_t -MipsISA::dspExtr( int64_t dspac, int32_t fmt, int32_t sa, int32_t round, int32_t saturate, uint32_t *dspctl ) +MipsISA::dspExtr(int64_t dspac, int32_t fmt, int32_t sa, int32_t round, + int32_t saturate, uint32_t *dspctl) { int32_t result = 0; uint32_t ouflag = 0; int64_t temp = 0; - sa = bits( sa, 4, 0 ); + sa = bits(sa, 4, 0); - if( sa > 0 ) - { - if( round ) - { - temp = (int64_t)addHalfLsb( dspac, sa ); + if (sa > 0) { + if (round) { + temp = (int64_t)addHalfLsb(dspac, sa); - if( dspac > 0 && temp < 0 ) - { + if (dspac > 0 && temp < 0) { ouflag = 1; - if( saturate ) + if (saturate) temp = FIXED_SMAX[SIMD_FMT_L]; } temp = temp >> sa; - } - else + } else { temp = dspac >> sa; - } - else + } + } else { temp = dspac; + } - dspac = checkOverflow( dspac, fmt, SIGNED, &ouflag ); + dspac = checkOverflow(dspac, fmt, SIGNED, &ouflag); - if( ouflag ) - { - *dspctl = insertBits( *dspctl, 23, 23, ouflag ); + if (ouflag) { + *dspctl = insertBits(*dspctl, 23, 23, ouflag); - if( saturate ) - result = (int32_t)dspSaturate( temp, fmt, SIGNED, &ouflag ); + if (saturate) + result = (int32_t)dspSaturate(temp, fmt, SIGNED, &ouflag); else result = (int32_t)temp; - } - else + } else { result = (int32_t)temp; + } - return( result ); + return result; } int32_t -MipsISA::dspExtp( int64_t dspac, int32_t size, uint32_t *dspctl ) +MipsISA::dspExtp(int64_t dspac, int32_t size, uint32_t *dspctl) { int32_t pos = 0; int32_t result = 0; - pos = bits( *dspctl, 5, 0 ); - size = bits( size, 4, 0 ); + pos = bits(*dspctl, 5, 0); + size = bits(size, 4, 0); - if( pos - (size+1) >= -1 ) - { - result = bits( dspac, pos, pos-size ); - *dspctl = insertBits( *dspctl, 14, 14, 0 ); - } - else - { + if (pos - (size + 1) >= -1) { + result = bits(dspac, pos, pos - size); + *dspctl = insertBits(*dspctl, 14, 14, 0); + } else { result = 0; - *dspctl = insertBits( *dspctl, 14, 14, 1 ); + *dspctl = insertBits(*dspctl, 14, 14, 1); } - return( result ); + return result; } int32_t -MipsISA::dspExtpd( int64_t dspac, int32_t size, uint32_t *dspctl ) +MipsISA::dspExtpd(int64_t dspac, int32_t size, uint32_t *dspctl) { int32_t pos = 0; int32_t result = 0; - pos = bits( *dspctl, 5, 0 ); - size = bits( size, 4, 0 ); - - if( pos - (size+1) >= -1 ) - { - result = bits( dspac, pos, pos-size ); - *dspctl = insertBits( *dspctl, 14, 14, 0 ); - if( pos - (size+1) >= 0 ) - *dspctl = insertBits( *dspctl, 5, 0, pos - (size+1) ); - else if( (pos - (size+1)) == -1 ) - *dspctl = insertBits( *dspctl, 5, 0, 63 ); - } - else - { + pos = bits(*dspctl, 5, 0); + size = bits(size, 4, 0); + + if (pos - (size + 1) >= -1) { + result = bits(dspac, pos, pos - size); + *dspctl = insertBits(*dspctl, 14, 14, 0); + if (pos - (size + 1) >= 0) + *dspctl = insertBits(*dspctl, 5, 0, pos - (size + 1)); + else if ((pos - (size + 1)) == -1) + *dspctl = insertBits(*dspctl, 5, 0, 63); + } else { result = 0; - *dspctl = insertBits( *dspctl, 14, 14, 1 ); + *dspctl = insertBits(*dspctl, 14, 14, 1); } - return( result ); + return result; } void -MipsISA::simdPack( uint64_t *values_ptr, int32_t *reg, int32_t fmt ) +MipsISA::simdPack(uint64_t *values_ptr, int32_t *reg, int32_t fmt) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int nbits = SIMD_NBITS[fmt]; *reg = 0; - for( i=0; i<nvals; i++ ) - *reg |= (int32_t)bits( values_ptr[i], nbits-1, 0 ) << nbits*i; + for (int i = 0; i < nvals; i++) + *reg |= (int32_t)bits(values_ptr[i], nbits - 1, 0) << nbits * i; } void -MipsISA::simdUnpack( int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign ) +MipsISA::simdUnpack(int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign) { - int i = 0; int nvals = SIMD_NVALS[fmt]; int nbits = SIMD_NBITS[fmt]; - switch( sign ) - { - case SIGNED: - for( i=0; i<nvals; i++ ) - { - values_ptr[i] = (uint64_t)bits( reg, nbits*(i+1)-1, nbits*i ); - values_ptr[i] = signExtend( values_ptr[i], fmt ); + switch (sign) { + case SIGNED: + for (int i = 0; i < nvals; i++) { + uint64_t tmp = (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i); + values_ptr[i] = signExtend(tmp, fmt); } break; - case UNSIGNED: - for( i=0; i<nvals; i++ ) - { - values_ptr[i] = (uint64_t)bits( reg, nbits*(i+1)-1, nbits*i ); + case UNSIGNED: + for (int i = 0; i < nvals; i++) { + values_ptr[i] = + (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i); } break; } } void -MipsISA::writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask ) +MipsISA::writeDSPControl(uint32_t *dspctl, uint32_t value, uint32_t mask) { uint32_t fmask = 0; - if( mask & 0x01 ) fmask |= DSP_CTL_MASK[DSP_POS]; - if( mask & 0x02 ) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; - if( mask & 0x04 ) fmask |= DSP_CTL_MASK[DSP_C]; - if( mask & 0x08 ) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; - if( mask & 0x10 ) fmask |= DSP_CTL_MASK[DSP_CCOND]; - if( mask & 0x20 ) fmask |= DSP_CTL_MASK[DSP_EFI]; + if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS]; + if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; + if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C]; + if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; + if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND]; + if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI]; *dspctl &= ~fmask; value &= fmask; @@ -1211,16 +1174,16 @@ MipsISA::writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask ) } uint32_t -MipsISA::readDSPControl( uint32_t *dspctl, uint32_t mask ) +MipsISA::readDSPControl(uint32_t *dspctl, uint32_t mask) { uint32_t fmask = 0; - if( mask & 0x01 ) fmask |= DSP_CTL_MASK[DSP_POS]; - if( mask & 0x02 ) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; - if( mask & 0x04 ) fmask |= DSP_CTL_MASK[DSP_C]; - if( mask & 0x08 ) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; - if( mask & 0x10 ) fmask |= DSP_CTL_MASK[DSP_CCOND]; - if( mask & 0x20 ) fmask |= DSP_CTL_MASK[DSP_EFI]; + if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS]; + if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; + if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C]; + if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; + if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND]; + if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI]; - return( *dspctl & fmask ); + return *dspctl & fmask; } diff --git a/src/arch/mips/dsp.hh b/src/arch/mips/dsp.hh index fb8d5c4f6..fde4b332a 100755 --- a/src/arch/mips/dsp.hh +++ b/src/arch/mips/dsp.hh @@ -41,131 +41,164 @@ class ThreadContext; namespace MipsISA { - // SIMD formats - enum { - SIMD_FMT_L, // long word - SIMD_FMT_W, // word - SIMD_FMT_PH, // paired halfword - SIMD_FMT_QB, // quad byte - SIMD_NUM_FMTS - }; - - // DSPControl Fields - enum { - DSP_POS, // insertion bitfield position - DSP_SCOUNT, // insertion bitfield size - DSP_C, // carry bit - DSP_OUFLAG, // overflow-underflow flag - DSP_CCOND, // condition code - DSP_EFI, // extract fail indicator bit - DSP_NUM_FIELDS - }; - - // compare instruction operations - enum { - CMP_EQ, // equal - CMP_LT, // less than - CMP_LE // less than or equal - }; - - // SIMD operation order modes - enum { - MODE_L, // left - MODE_R, // right - MODE_LA, // left-alternate - MODE_RA, // right-alternate - MODE_X // cross - }; - - // dsp operation parameters - enum { UNSIGNED, SIGNED }; - enum { NOSATURATE, SATURATE }; - enum { NOROUND, ROUND }; - - // DSPControl field positions and masks - const uint32_t DSP_CTL_POS[DSP_NUM_FIELDS] = { 0, 7, 13, 16, 24, 14 }; - const uint32_t DSP_CTL_MASK[DSP_NUM_FIELDS] = { 0x0000003f, 0x00001f80, 0x00002000, - 0x00ff0000, 0x0f000000, 0x00004000 }; - - // SIMD format constants - const uint32_t SIMD_MAX_VALS = 4; // maximum values per register - const uint32_t SIMD_NVALS[SIMD_NUM_FMTS] = { 1, 1, 2, 4 }; // number of values in fmt - const uint32_t SIMD_NBITS[SIMD_NUM_FMTS] = { 64, 32, 16, 8 }; // number of bits per value - const uint32_t SIMD_LOG2N[SIMD_NUM_FMTS] = { 6, 5, 4, 3 }; // log2( bits per value ) - - // DSP maximum values - const uint64_t FIXED_L_SMAX = ULL(0x7fffffffffffffff); - const uint64_t FIXED_W_SMAX = ULL(0x000000007fffffff); - const uint64_t FIXED_H_SMAX = ULL(0x0000000000007fff); - const uint64_t FIXED_B_SMAX = ULL(0x000000000000007f); - const uint64_t FIXED_L_UMAX = ULL(0xffffffffffffffff); - const uint64_t FIXED_W_UMAX = ULL(0x00000000ffffffff); - const uint64_t FIXED_H_UMAX = ULL(0x000000000000ffff); - const uint64_t FIXED_B_UMAX = ULL(0x00000000000000ff); - const uint64_t FIXED_SMAX[SIMD_NUM_FMTS] = { FIXED_L_SMAX, FIXED_W_SMAX, FIXED_H_SMAX, FIXED_B_SMAX }; - const uint64_t FIXED_UMAX[SIMD_NUM_FMTS] = { FIXED_L_UMAX, FIXED_W_UMAX, FIXED_H_UMAX, FIXED_B_UMAX }; - - // DSP minimum values - const uint64_t FIXED_L_SMIN = ULL(0x8000000000000000); - const uint64_t FIXED_W_SMIN = ULL(0xffffffff80000000); - const uint64_t FIXED_H_SMIN = ULL(0xffffffffffff8000); - const uint64_t FIXED_B_SMIN = ULL(0xffffffffffffff80); - const uint64_t FIXED_L_UMIN = ULL(0x0000000000000000); - const uint64_t FIXED_W_UMIN = ULL(0x0000000000000000); - const uint64_t FIXED_H_UMIN = ULL(0x0000000000000000); - const uint64_t FIXED_B_UMIN = ULL(0x0000000000000000); - const uint64_t FIXED_SMIN[SIMD_NUM_FMTS] = { FIXED_L_SMIN, FIXED_W_SMIN, FIXED_H_SMIN, FIXED_B_SMIN }; - const uint64_t FIXED_UMIN[SIMD_NUM_FMTS] = { FIXED_L_UMIN, FIXED_W_UMIN, FIXED_H_UMIN, FIXED_B_UMIN }; - - // DSP utility functions - int32_t bitrev( int32_t value ); - uint64_t dspSaturate( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow ); - uint64_t checkOverflow( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow ); - uint64_t signExtend( uint64_t value, int32_t signpos ); - uint64_t addHalfLsb( uint64_t value, int32_t lsbpos ); - int32_t dspAbs( int32_t a, int32_t fmt, uint32_t *dspctl ); - int32_t dspAdd( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ); - int32_t dspAddh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign ); - int32_t dspSub( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ); - int32_t dspSubh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign ); - int32_t dspShll( int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl ); - int32_t dspShrl( int32_t a, uint32_t sa, int32_t fmt, int32_t sign ); - int32_t dspShra( int32_t a, uint32_t sa, int32_t fmt, int32_t round, int32_t sign, uint32_t *dspctl ); - int32_t dspMul( int32_t a, int32_t b, int32_t fmt, int32_t saturate, uint32_t *dspctl ); - int32_t dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t round, uint32_t *dspctl ); - int32_t dspMuleu( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl ); - int32_t dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl ); - int64_t dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, - int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl ); - int64_t dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, - int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl ); - int64_t dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode ); - int64_t dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode ); - int64_t dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, - int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl ); - int64_t dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt ); - int64_t dspMulsaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, uint32_t *dspctl ); - void dspCmp( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl ); - int32_t dspCmpg( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op ); - int32_t dspCmpgd( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl ); - int32_t dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int32_t outsign, int32_t mode ); - int32_t dspPrecrqu( int32_t a, int32_t b, uint32_t *dspctl ); - int32_t dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl ); - int32_t dspPrecrSra( int32_t a, int32_t b, int32_t sa, int32_t fmt, int32_t round ); - int32_t dspPick( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl ); - int32_t dspPack( int32_t a, int32_t b, int32_t fmt ); - int32_t dspExtr( int64_t dspac, int32_t fmt, int32_t sa, int32_t round, - int32_t saturate, uint32_t *dspctl ); - int32_t dspExtp( int64_t dspac, int32_t size, uint32_t *dspctl ); - int32_t dspExtpd( int64_t dspac, int32_t size, uint32_t *dspctl ); - - // SIMD pack/unpack utility functions - void simdPack( uint64_t *values_ptr, int32_t *reg, int32_t fmt ); - void simdUnpack( int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign ); - - // DSPControl r/w utility functions - void writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask ); - uint32_t readDSPControl( uint32_t *dspctl, uint32_t mask ); +// SIMD formats +enum { + SIMD_FMT_L, // long word + SIMD_FMT_W, // word + SIMD_FMT_PH, // paired halfword + SIMD_FMT_QB, // quad byte + SIMD_NUM_FMTS }; -#endif +// DSPControl Fields +enum { + DSP_POS, // insertion bitfield position + DSP_SCOUNT, // insertion bitfield size + DSP_C, // carry bit + DSP_OUFLAG, // overflow-underflow flag + DSP_CCOND, // condition code + DSP_EFI, // extract fail indicator bit + DSP_NUM_FIELDS +}; + +// compare instruction operations +enum { + CMP_EQ, // equal + CMP_LT, // less than + CMP_LE // less than or equal +}; + +// SIMD operation order modes +enum { + MODE_L, // left + MODE_R, // right + MODE_LA, // left-alternate + MODE_RA, // right-alternate + MODE_X // cross +}; + +// dsp operation parameters +enum { UNSIGNED, SIGNED }; +enum { NOSATURATE, SATURATE }; +enum { NOROUND, ROUND }; + +// DSPControl field positions and masks +const uint32_t DSP_CTL_POS[DSP_NUM_FIELDS] = { 0, 7, 13, 16, 24, 14 }; +const uint32_t DSP_CTL_MASK[DSP_NUM_FIELDS] = +{ 0x0000003f, 0x00001f80, 0x00002000, + 0x00ff0000, 0x0f000000, 0x00004000 }; + +/* + * SIMD format constants + */ + +// maximum values per register +const uint32_t SIMD_MAX_VALS = 4; +// number of values in fmt +const uint32_t SIMD_NVALS[SIMD_NUM_FMTS] = { 1, 1, 2, 4 }; +// number of bits per value +const uint32_t SIMD_NBITS[SIMD_NUM_FMTS] = { 64, 32, 16, 8 }; +// log2(bits per value) +const uint32_t SIMD_LOG2N[SIMD_NUM_FMTS] = { 6, 5, 4, 3 }; + + +// DSP maximum values +const uint64_t FIXED_L_SMAX = ULL(0x7fffffffffffffff); +const uint64_t FIXED_W_SMAX = ULL(0x000000007fffffff); +const uint64_t FIXED_H_SMAX = ULL(0x0000000000007fff); +const uint64_t FIXED_B_SMAX = ULL(0x000000000000007f); +const uint64_t FIXED_L_UMAX = ULL(0xffffffffffffffff); +const uint64_t FIXED_W_UMAX = ULL(0x00000000ffffffff); +const uint64_t FIXED_H_UMAX = ULL(0x000000000000ffff); +const uint64_t FIXED_B_UMAX = ULL(0x00000000000000ff); +const uint64_t FIXED_SMAX[SIMD_NUM_FMTS] = +{ FIXED_L_SMAX, FIXED_W_SMAX, FIXED_H_SMAX, FIXED_B_SMAX }; +const uint64_t FIXED_UMAX[SIMD_NUM_FMTS] = +{ FIXED_L_UMAX, FIXED_W_UMAX, FIXED_H_UMAX, FIXED_B_UMAX }; + +// DSP minimum values +const uint64_t FIXED_L_SMIN = ULL(0x8000000000000000); +const uint64_t FIXED_W_SMIN = ULL(0xffffffff80000000); +const uint64_t FIXED_H_SMIN = ULL(0xffffffffffff8000); +const uint64_t FIXED_B_SMIN = ULL(0xffffffffffffff80); +const uint64_t FIXED_L_UMIN = ULL(0x0000000000000000); +const uint64_t FIXED_W_UMIN = ULL(0x0000000000000000); +const uint64_t FIXED_H_UMIN = ULL(0x0000000000000000); +const uint64_t FIXED_B_UMIN = ULL(0x0000000000000000); +const uint64_t FIXED_SMIN[SIMD_NUM_FMTS] = +{ FIXED_L_SMIN, FIXED_W_SMIN, FIXED_H_SMIN, FIXED_B_SMIN }; +const uint64_t FIXED_UMIN[SIMD_NUM_FMTS] = +{ FIXED_L_UMIN, FIXED_W_UMIN, FIXED_H_UMIN, FIXED_B_UMIN }; + +// DSP utility functions +int32_t bitrev(int32_t value); +uint64_t dspSaturate(uint64_t value, int32_t fmt, int32_t sign, + uint32_t *overflow); +uint64_t checkOverflow(uint64_t value, int32_t fmt, int32_t sign, + uint32_t *overflow); +uint64_t signExtend(uint64_t value, int32_t signpos); +uint64_t addHalfLsb(uint64_t value, int32_t lsbpos); +int32_t dspAbs(int32_t a, int32_t fmt, uint32_t *dspctl); +int32_t dspAdd(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl); +int32_t dspAddh(int32_t a, int32_t b, int32_t fmt, int32_t round, + int32_t sign); +int32_t dspSub(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl); +int32_t dspSubh(int32_t a, int32_t b, int32_t fmt, int32_t round, + int32_t sign); +int32_t dspShll(int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, + int32_t sign, uint32_t *dspctl); +int32_t dspShrl(int32_t a, uint32_t sa, int32_t fmt, int32_t sign); +int32_t dspShra(int32_t a, uint32_t sa, int32_t fmt, int32_t round, + int32_t sign, uint32_t *dspctl); +int32_t dspMul(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + uint32_t *dspctl); +int32_t dspMulq(int32_t a, int32_t b, int32_t fmt, int32_t saturate, + int32_t round, uint32_t *dspctl); +int32_t dspMuleu(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl); +int32_t dspMuleq(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl); +int64_t dspDpaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, + uint32_t *dspctl); +int64_t dspDpsq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, + uint32_t *dspctl); +int64_t dspDpa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, + int32_t sign, int32_t mode); +int64_t dspDps(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, + int32_t sign, int32_t mode); +int64_t dspMaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, + int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl); +int64_t dspMulsa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt); +int64_t dspMulsaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, + uint32_t *dspctl); +void dspCmp(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, + uint32_t *dspctl); +int32_t dspCmpg(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op); +int32_t dspCmpgd(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, + uint32_t *dspctl); +int32_t dspPrece(int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, + int32_t outsign, int32_t mode); +int32_t dspPrecrqu(int32_t a, int32_t b, uint32_t *dspctl); +int32_t dspPrecrq(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl); +int32_t dspPrecrSra(int32_t a, int32_t b, int32_t sa, int32_t fmt, + int32_t round); +int32_t dspPick(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl); +int32_t dspPack(int32_t a, int32_t b, int32_t fmt); +int32_t dspExtr(int64_t dspac, int32_t fmt, int32_t sa, int32_t round, + int32_t saturate, uint32_t *dspctl); +int32_t dspExtp(int64_t dspac, int32_t size, uint32_t *dspctl); +int32_t dspExtpd(int64_t dspac, int32_t size, uint32_t *dspctl); + +// SIMD pack/unpack utility functions +void simdPack(uint64_t *values_ptr, int32_t *reg, int32_t fmt); +void simdUnpack(int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign); + +// DSPControl r/w utility functions +void writeDSPControl(uint32_t *dspctl, uint32_t value, uint32_t mask); +uint32_t readDSPControl(uint32_t *dspctl, uint32_t mask); + +} /* namespace MipsISA */ + +#endif // __ARCH_MIPS_DSP_HH__ diff --git a/src/arch/mips/idle_event.cc b/src/arch/mips/idle_event.cc index d1d4f7c63..0aea08834 100644 --- a/src/arch/mips/idle_event.cc +++ b/src/arch/mips/idle_event.cc @@ -34,7 +34,7 @@ #include "arch/mips/kernel_stats.hh" #include "cpu/thread_context.hh" -using namespace TheISA; +using namespace MipsISA; void IdleStartEvent::process(ThreadContext *tc) diff --git a/src/arch/mips/interrupts.cc b/src/arch/mips/interrupts.cc index c91ee1e99..99f96fafc 100755 --- a/src/arch/mips/interrupts.cc +++ b/src/arch/mips/interrupts.cc @@ -76,7 +76,7 @@ static inline void setCauseIP_(ThreadContext *tc, uint8_t val) { intstatus &= ~(1 << int_num); } - void Interrupts::clear_all() + void Interrupts::clearAll() { DPRINTF(Interrupt, "Interrupts all cleared\n"); intstatus = 0; @@ -156,12 +156,6 @@ static inline void setCauseIP_(ThreadContext *tc, uint8_t val) { return false; } - - uint64_t Interrupts::get_vec(int int_num) - { - panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); - M5_DUMMY_RETURN - } */ void Interrupts::post(int int_num, ThreadContext* tc) { @@ -195,14 +189,14 @@ void Interrupts::clear(int int_num, int index) fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); } -void Interrupts::clear_all(ThreadContext *tc) +void Interrupts::clearAll(ThreadContext *tc) { DPRINTF(Interrupt, "Interrupts all cleared\n"); uint8_t intstatus = 0; setCauseIP_(tc, intstatus); } -void Interrupts::clear_all() +void Interrupts::clearAll() { fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); } @@ -252,12 +246,6 @@ void Interrupts::updateIntrInfo(ThreadContext *tc) const ; } -uint64_t Interrupts::get_vec(int int_num) -{ - panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); - M5_DUMMY_RETURN - } - bool Interrupts::interruptsPending(ThreadContext *tc) const { //if there is a on cpu timer interrupt (i.e. Compare == Count) diff --git a/src/arch/mips/interrupts.hh b/src/arch/mips/interrupts.hh index f0e928088..af71e4636 100755 --- a/src/arch/mips/interrupts.hh +++ b/src/arch/mips/interrupts.hh @@ -57,23 +57,23 @@ class Interrupts // for posting an interrupt. It sets a bit // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // void post(int int_num, int index); // clear(int int_num, int index) is responsible // for clearing an interrupt. It clear a bit // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // void clear(int int_num, int index); - // clear_all() is responsible + // clearAll() is responsible // for clearing all interrupts. It clears all bits // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // - void clear_all(); + void clearAll(); // getInterrupt(ThreadContext * tc) checks if an interrupt // should be returned. It ands the interrupt mask and @@ -91,9 +91,7 @@ class Interrupts void updateIntrInfoCpuTimerIntr(ThreadContext *tc) const; bool onCpuTimerInterrupt(ThreadContext *tc) const; - uint64_t get_vec(int int_num); - - bool check_interrupts(ThreadContext * tc) const{ + bool checkInterrupts(ThreadContext *tc) const { //return (intstatus != 0) && !(tc->readPC() & 0x3); if (oncputimerintr == false){ updateIntrInfo(tc); @@ -121,7 +119,7 @@ class Interrupts // for posting an interrupt. It sets a bit // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // void post(int int_num, ThreadContext* tc); void post(int int_num, int index); @@ -130,19 +128,19 @@ class Interrupts // for clearing an interrupt. It clear a bit // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // void clear(int int_num, ThreadContext* tc); void clear(int int_num, int index); - // clear_all() is responsible + // clearAll() is responsible // for clearing all interrupts. It clears all bits // in intstatus corresponding to Cause IP*. The // MIPS register Cause is updated by updateIntrInfo - // which is called by check_interrupts + // which is called by checkInterrupts // - void clear_all(ThreadContext* tc); - void clear_all(); + void clearAll(ThreadContext* tc); + void clearAll(); // getInterrupt(ThreadContext * tc) checks if an interrupt // should be returned. It ands the interrupt mask and @@ -160,9 +158,9 @@ class Interrupts bool interruptsPending(ThreadContext *tc) const; bool onCpuTimerInterrupt(ThreadContext *tc) const; - uint64_t get_vec(int int_num); - - bool check_interrupts(ThreadContext * tc) const{ + bool + checkInterrupts(ThreadContext *tc) const + { return interruptsPending(tc); } diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa index b1cd03ca1..8af504e55 100644 --- a/src/arch/mips/isa/decoder.isa +++ b/src/arch/mips/isa/decoder.isa @@ -416,16 +416,16 @@ decode OPCODE_HI default Unknown::unknown() { Ctrl_Base_DepTag); break; case 25: - data = 0 | fcsr_val & 0xFE000000 >> 24 - | fcsr_val & 0x00800000 >> 23; + data = (fcsr_val & 0xFE000000 >> 24) + | (fcsr_val & 0x00800000 >> 23); break; case 26: - data = 0 | fcsr_val & 0x0003F07C; + data = fcsr_val & 0x0003F07C; break; case 28: - data = 0 | fcsr_val & 0x00000F80 - | fcsr_val & 0x01000000 >> 21 - | fcsr_val & 0x00000003; + data = (fcsr_val & 0x00000F80) + | (fcsr_val & 0x01000000 >> 21) + | (fcsr_val & 0x00000003); break; case 31: data = fcsr_val; @@ -603,7 +603,8 @@ decode OPCODE_HI default Unknown::unknown() { 0xA: rdpgpr({{ if(Config_AR >= 1) { // Rev 2 of the architecture - Rd = xc->tcBase()->readIntReg(RT + NumIntRegs * SRSCtl_PSS); + panic("Shadow Sets Not Fully Implemented.\n"); + //Rd = xc->tcBase()->readIntReg(RT + NumIntRegs * SRSCtl_PSS); } else { @@ -613,7 +614,8 @@ decode OPCODE_HI default Unknown::unknown() { 0xE: wrpgpr({{ if(Config_AR >= 1) { // Rev 2 of the architecture - xc->tcBase()->setIntReg(RD + NumIntRegs * SRSCtl_PSS,Rt); + panic("Shadow Sets Not Fully Implemented.\n"); + //xc->tcBase()->setIntReg(RD + NumIntRegs * SRSCtl_PSS,Rt); // warn("Writing %d to %d, PSS: %d, SRS: %x\n",Rt,RD + NumIntRegs * SRSCtl_PSS, SRSCtl_PSS,SRSCtl); } else @@ -1963,7 +1965,7 @@ decode OPCODE_HI default Unknown::unknown() { 0x0: decode OP_LO { format IntOp { 0x0: append({{ Rt.uw = (Rt.uw << RD) | bits(Rs.uw,RD-1,0); }}); - 0x1: prepend({{ Rt.uw = (Rt.uw >> RD) | (bits(Rs.uw,RD-1,0) << 32-RD); }}); + 0x1: prepend({{ Rt.uw = (Rt.uw >> RD) | (bits(Rs.uw, RD - 1, 0) << (32 - RD)); }}); } } 0x2: decode OP_LO { @@ -2050,11 +2052,11 @@ decode OPCODE_HI default Unknown::unknown() { format LoadUnalignedMemory { 0x2: lwl({{ uint32_t mem_shift = 24 - (8 * byte_offset); Rt.uw = mem_word << mem_shift | - Rt.uw & mask(mem_shift); + (Rt.uw & mask(mem_shift)); }}); 0x6: lwr({{ uint32_t mem_shift = 8 * byte_offset; - Rt.uw = Rt.uw & (mask(mem_shift) << (32 - mem_shift)) | - mem_word >> mem_shift; + Rt.uw = (Rt.uw & (mask(mem_shift) << (32 - mem_shift))) | + (mem_word >> mem_shift); }}); } } @@ -2069,12 +2071,12 @@ decode OPCODE_HI default Unknown::unknown() { format StoreUnalignedMemory { 0x2: swl({{ uint32_t reg_shift = 24 - (8 * byte_offset); uint32_t mem_shift = 32 - reg_shift; - mem_word = mem_word & (mask(reg_shift) << mem_shift) | - Rt.uw >> reg_shift; + mem_word = (mem_word & (mask(reg_shift) << mem_shift)) | + (Rt.uw >> reg_shift); }}); 0x6: swr({{ uint32_t reg_shift = 8 * byte_offset; mem_word = Rt.uw << reg_shift | - mem_word & (mask(reg_shift)); + (mem_word & (mask(reg_shift))); }}); } format CP0Control { diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa index f0210c29b..8596308e2 100644 --- a/src/arch/mips/isa/formats/mem.isa +++ b/src/arch/mips/isa/formats/mem.isa @@ -43,7 +43,7 @@ output header {{ protected: /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; + Request::Flags memAccessFlags; /// Pointer to EAComp object. const StaticInstPtr eaCompPtr; /// Pointer to MemAcc object. @@ -57,7 +57,7 @@ output header {{ StaticInstPtr _eaCompPtr = nullStaticInstPtr, StaticInstPtr _memAccPtr = nullStaticInstPtr) : MipsStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), + eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), disp(sext<16>(OFFSET)) { } @@ -70,7 +70,7 @@ output header {{ const StaticInstPtr &eaCompInst() const { return eaCompPtr; } const StaticInstPtr &memAccInst() const { return memAccPtr; } - unsigned memAccFlags() { return memAccessFlags; } + Request::Flags memAccFlags() { return memAccessFlags; } }; /** diff --git a/src/arch/mips/isa/formats/mt.isa b/src/arch/mips/isa/formats/mt.isa index 81fdc2898..1928ee903 100644 --- a/src/arch/mips/isa/formats/mt.isa +++ b/src/arch/mips/isa/formats/mt.isa @@ -196,7 +196,7 @@ def format MT_Control(code, *opt_flags) {{ def format MT_MFTR(code, *flags) {{ flags += ('IsNonSpeculative', ) -# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->getThreadNum() << \": Executing MT INST: ' + name + '\" << endl;\n' + code +# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->threadId() << \": Executing MT INST: ' + name + '\" << endl;\n' + code code += 'if (MT_H == 1) {\n' code += 'data = bits(data, top_bit, bottom_bit);\n' @@ -212,7 +212,7 @@ def format MT_MFTR(code, *flags) {{ def format MT_MTTR(code, *flags) {{ flags += ('IsNonSpeculative', ) -# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->getThreadNum() << \": Executing MT INST: ' + name + '\" << endl;\n' + code +# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->threadId() << \": Executing MT INST: ' + name + '\" << endl;\n' + code iop = InstObjParams(name, Name, 'MTOp', code, flags) header_output = BasicDeclare.subst(iop) decoder_output = BasicConstructor.subst(iop) diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa index 0405aa5b3..f729cbf63 100644 --- a/src/arch/mips/isa/formats/util.isa +++ b/src/arch/mips/isa/formats/util.isa @@ -61,6 +61,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, inst_flags) if mem_flags: + mem_flags = [ 'Request::%s' % flag for flag in mem_flags ] s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' iop.constructor += s memacc_iop.constructor += s diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh index fe28ad601..12c887132 100644 --- a/src/arch/mips/isa_traits.hh +++ b/src/arch/mips/isa_traits.hh @@ -147,11 +147,11 @@ namespace MipsISA // MIPS modes enum mode_type { - mode_kernel = 0, // kernel - mode_supervisor = 1, // supervisor - mode_user = 2, // user mode + mode_kernel = 0, // kernel + mode_supervisor = 1, // supervisor + mode_user = 2, // user mode mode_debug = 3, // debug mode - mode_number // number of modes + mode_number // number of modes }; inline mode_type getOperatingMode(MiscReg Stat) @@ -181,6 +181,8 @@ namespace MipsISA const int NumIntRegs = NumIntArchRegs*NumShadowRegSets + NumIntSpecialRegs; //HI & LO Regs const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;// + const int TotalArchRegs = NumIntArchRegs * NumShadowRegSets; + // Static instruction parameters const int MaxInstSrcRegs = 10; const int MaxInstDestRegs = 8; @@ -188,13 +190,6 @@ namespace MipsISA // semantically meaningful register indices const int ZeroReg = 0; const int AssemblerReg = 1; - const int ReturnValueReg = 2; - const int ReturnValueReg1 = 2; - const int ReturnValueReg2 = 3; - const int ArgumentReg0 = 4; - const int ArgumentReg1 = 5; - const int ArgumentReg2 = 6; - const int ArgumentReg3 = 7; const int KernelReg0 = 26; const int KernelReg1 = 27; const int GlobalPointerReg = 28; @@ -202,14 +197,9 @@ namespace MipsISA const int FramePointerReg = 30; const int ReturnAddressReg = 31; - const int ArgumentReg[] = {4, 5, 6, 7}; - const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); - - const int SyscallNumReg = ReturnValueReg1; - const int SyscallPseudoReturnReg = ReturnValueReg2; - const int SyscallSuccessReg = ArgumentReg3; + const int SyscallPseudoReturnReg = 3; - const int LogVMPageSize = 13; // 8K bytes + const int LogVMPageSize = 13; // 8K bytes const int VMPageSize = (1 << LogVMPageSize); const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned @@ -391,6 +381,4 @@ namespace MipsISA }; -using namespace MipsISA; - #endif // __ARCH_MIPS_ISA_TRAITS_HH__ diff --git a/src/arch/mips/linux/linux.cc b/src/arch/mips/linux/linux.cc index 4499107d7..8745731dc 100644 --- a/src/arch/mips/linux/linux.cc +++ b/src/arch/mips/linux/linux.cc @@ -35,34 +35,34 @@ // open(2) flags translation table OpenFlagTransTable MipsLinux::openFlagTable[] = { #ifdef _MSC_VER - { MipsLinux::TGT_O_RDONLY, _O_RDONLY }, - { MipsLinux::TGT_O_WRONLY, _O_WRONLY }, - { MipsLinux::TGT_O_RDWR, _O_RDWR }, - { MipsLinux::TGT_O_APPEND, _O_APPEND }, - { MipsLinux::TGT_O_CREAT, _O_CREAT }, - { MipsLinux::TGT_O_TRUNC, _O_TRUNC }, - { MipsLinux::TGT_O_EXCL, _O_EXCL }, + { MipsLinux::TGT_O_RDONLY, _O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, _O_WRONLY }, + { MipsLinux::TGT_O_RDWR, _O_RDWR }, + { MipsLinux::TGT_O_APPEND, _O_APPEND }, + { MipsLinux::TGT_O_CREAT, _O_CREAT }, + { MipsLinux::TGT_O_TRUNC, _O_TRUNC }, + { MipsLinux::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, + { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY }, + { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { MipsLinux::TGT_O_SYNC, _O_SYNC }, + { MipsLinux::TGT_O_SYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { MipsLinux::TGT_O_RDONLY, O_RDONLY }, - { MipsLinux::TGT_O_WRONLY, O_WRONLY }, - { MipsLinux::TGT_O_RDWR, O_RDWR }, - { MipsLinux::TGT_O_APPEND, O_APPEND }, - { MipsLinux::TGT_O_CREAT, O_CREAT }, - { MipsLinux::TGT_O_TRUNC, O_TRUNC }, - { MipsLinux::TGT_O_EXCL, O_EXCL }, - { MipsLinux::TGT_O_NONBLOCK, O_NONBLOCK }, - { MipsLinux::TGT_O_NOCTTY, O_NOCTTY }, + { MipsLinux::TGT_O_RDONLY, O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, O_WRONLY }, + { MipsLinux::TGT_O_RDWR, O_RDWR }, + { MipsLinux::TGT_O_APPEND, O_APPEND }, + { MipsLinux::TGT_O_CREAT, O_CREAT }, + { MipsLinux::TGT_O_TRUNC, O_TRUNC }, + { MipsLinux::TGT_O_EXCL, O_EXCL }, + { MipsLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { MipsLinux::TGT_O_NOCTTY, O_NOCTTY }, #ifdef O_SYNC - { MipsLinux::TGT_O_SYNC, O_SYNC }, + { MipsLinux::TGT_O_SYNC, O_SYNC }, #endif #endif /* _MSC_VER */ }; diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh index fcfaa18ea..aaeba0a42 100644 --- a/src/arch/mips/linux/linux.hh +++ b/src/arch/mips/linux/linux.hh @@ -32,9 +32,6 @@ #define __ARCH_MIPS_LINUX_LINUX_HH__ #include "kern/linux/linux.hh" -#include <string> - -using std::string; class MipsLinux : public Linux { @@ -49,21 +46,21 @@ class MipsLinux : public Linux //@{ /// open(2) flag values. - static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK - static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND - static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT - static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC - static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL - static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY - static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC - static const int TGT_O_DRD = 0x00010000; //!< O_DRD - static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO - static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE - static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC - static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DRD = 0x00010000; //!< O_DRD + static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE + static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC + static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC //@} /// For mmap(). @@ -72,12 +69,12 @@ class MipsLinux : public Linux //@{ /// For getsysinfo(). static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz //@} //@{ @@ -94,15 +91,15 @@ class MipsLinux : public Linux //@{ /// ioctl() command codes. - static const unsigned TIOCGETP = 0x7408; - static const unsigned TIOCSETP = 0x7409; - static const unsigned TIOCSETN = 0x740a; - static const unsigned TIOCSETC = 0x7411; - static const unsigned TIOCGETC = 0x7412; - static const unsigned FIONREAD = 0x467f; - static const unsigned TIOCISATTY = 0x5480; - static const unsigned TIOCGETS = 0x540d; - static const unsigned TIOCGETA = 0x7417; + static const unsigned TIOCGETP_ = 0x7408; + static const unsigned TIOCSETP_ = 0x7409; + static const unsigned TIOCSETN_ = 0x740a; + static const unsigned TIOCSETC_ = 0x7411; + static const unsigned TIOCGETC_ = 0x7412; + static const unsigned FIONREAD_ = 0x467f; + static const unsigned TIOCISATTY_ = 0x5480; + static const unsigned TIOCGETS_ = 0x540d; + static const unsigned TIOCGETA_ = 0x7417; //@} /// For table(). diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc index 06e6e2cf4..24e71305a 100644 --- a/src/arch/mips/linux/process.cc +++ b/src/arch/mips/linux/process.cc @@ -51,7 +51,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename,"m5.eecs.umich.edu"); @@ -70,13 +70,13 @@ static SyscallReturn sys_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); - // unsigned nbytes = tc->getSyscallArg(2); + unsigned op = process->getSyscallArg(tc, 0); + // unsigned nbytes = process->getSyscallArg(tc, 2); switch (op) { case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1)); // I don't think this exactly matches the HW FPCR *fpcr = 0; fpcr.copyOut(tc->getMemPort()); @@ -97,13 +97,13 @@ static SyscallReturn sys_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned op = tc->getSyscallArg(0); - // unsigned nbytes = tc->getSyscallArg(2); + unsigned op = process->getSyscallArg(tc, 0); + // unsigned nbytes = process->getSyscallArg(tc, 2); switch (op) { case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1)); // I don't think this exactly matches the HW FPCR fpcr.copyIn(tc->getMemPort()); DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): " @@ -138,7 +138,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>), /* 16 */ SyscallDesc("lchown", chownFunc), - /* 17 */ SyscallDesc("break", obreakFunc), + /* 17 */ SyscallDesc("break", brkFunc), /* 18 */ SyscallDesc("unused#18", unimplementedFunc), /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getpid", getpidFunc), @@ -160,13 +160,13 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 36 */ SyscallDesc("sync", unimplementedFunc), /* 37 */ SyscallDesc("kill", unimplementedFunc), /* 38 */ SyscallDesc("rename", unimplementedFunc), - /* 39 */ SyscallDesc("mkdir", unimplementedFunc), + /* 39 */ SyscallDesc("mkdir", mkdirFunc), /* 40 */ SyscallDesc("rmdir", unimplementedFunc), /* 41 */ SyscallDesc("dup", unimplementedFunc), /* 42 */ SyscallDesc("pipe", pipePseudoFunc), /* 43 */ SyscallDesc("times", unimplementedFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), - /* 45 */ SyscallDesc("brk", obreakFunc), + /* 45 */ SyscallDesc("brk", brkFunc), /* 46 */ SyscallDesc("setgid", unimplementedFunc), /* 47 */ SyscallDesc("getgid", getgidFunc), /* 48 */ SyscallDesc("signal", ignoreFunc), @@ -175,13 +175,13 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 51 */ SyscallDesc("acct", unimplementedFunc), /* 52 */ SyscallDesc("umount2", unimplementedFunc), /* 53 */ SyscallDesc("lock", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", unimplementedFunc/*ioctlFunc<MipsLinux>*/), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>), /* 55 */ SyscallDesc("fcntl", fcntlFunc), /* 56 */ SyscallDesc("mpx", unimplementedFunc), /* 57 */ SyscallDesc("setpgid", unimplementedFunc), /* 58 */ SyscallDesc("ulimit", unimplementedFunc), /* 59 */ SyscallDesc("unused#59", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 60 */ SyscallDesc("umask", umaskFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("ustat", unimplementedFunc), /* 63 */ SyscallDesc("dup2", unimplementedFunc), @@ -206,7 +206,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 82 */ SyscallDesc("reserved#82", unimplementedFunc), /* 83 */ SyscallDesc("symlink", unimplementedFunc), /* 84 */ SyscallDesc("unused#84", unimplementedFunc), - /* 85 */ SyscallDesc("readlink", unimplementedFunc), + /* 85 */ SyscallDesc("readlink", readlinkFunc), /* 86 */ SyscallDesc("uselib", unimplementedFunc), /* 87 */ SyscallDesc("swapon", gethostnameFunc), /* 88 */ SyscallDesc("reboot", unimplementedFunc), @@ -288,7 +288,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 164 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), /* 165 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), /* 166 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 167 */ SyscallDesc("mremap", unimplementedFunc), + /* 167 */ SyscallDesc("mremap", mremapFunc<MipsLinux>), /* 168 */ SyscallDesc("accept", unimplementedFunc), /* 169 */ SyscallDesc("bind", unimplementedFunc), /* 170 */ SyscallDesc("connect", unimplementedFunc), @@ -324,7 +324,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = { /* 200 */ SyscallDesc("pread64", unimplementedFunc), /* 201 */ SyscallDesc("pwrite64", unimplementedFunc), /* 202 */ SyscallDesc("chown", unimplementedFunc), - /* 203 */ SyscallDesc("getcwd", unimplementedFunc), + /* 203 */ SyscallDesc("getcwd", getcwdFunc), /* 204 */ SyscallDesc("capget", unimplementedFunc), /* 205 */ SyscallDesc("capset", unimplementedFunc), /* 206 */ SyscallDesc("sigalstack", unimplementedFunc), @@ -425,7 +425,7 @@ MipsLinuxProcess::getDesc(int callnum) //MIPS32 syscalls are in the range of 4000 - 4999 int m5_sys_idx = callnum - 4000; - if (m5_sys_idx < 0 || m5_sys_idx > Num_Syscall_Descs) + if (m5_sys_idx < 0 || m5_sys_idx >= Num_Syscall_Descs) return NULL; return &syscallDescs[m5_sys_idx]; diff --git a/src/arch/mips/linux/system.cc b/src/arch/mips/linux/system.cc index bed863e9d..23062c96b 100644 --- a/src/arch/mips/linux/system.cc +++ b/src/arch/mips/linux/system.cc @@ -168,7 +168,6 @@ LinuxMipsSystem::setDelayLoop(ThreadContext *tc) vp = tc->getVirtPort(); vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988)); - tc->delVirtPort(vp); } } diff --git a/src/arch/mips/linux/system.hh b/src/arch/mips/linux/system.hh index 24fb604ed..984f74694 100644 --- a/src/arch/mips/linux/system.hh +++ b/src/arch/mips/linux/system.hh @@ -43,9 +43,6 @@ class IdleStartEvent; #include "kern/linux/events.hh" #include "params/LinuxMipsSystem.hh" -using namespace MipsISA; -using namespace Linux; - /** * This class contains linux specific system code (Loading, Events). * It points to objects that are the system binaries to load and patches them @@ -112,7 +109,7 @@ class LinuxMipsSystem : public MipsSystem * PC based event to skip the dprink() call and emulate its * functionality */ - DebugPrintkEvent *debugPrintkEvent; + Linux::DebugPrintkEvent *debugPrintkEvent; /** * Skip calculate_delay_loop() rather than waiting for this to be diff --git a/src/arch/mips/linux/threadinfo.hh b/src/arch/mips/linux/threadinfo.hh index 25ee74dd3..b0d0cd811 100644 --- a/src/arch/mips/linux/threadinfo.hh +++ b/src/arch/mips/linux/threadinfo.hh @@ -55,7 +55,7 @@ class ThreadInfo CopyOut(tc, &data, addr, sizeof(T)); - data = TheISA::gtoh(data); + data = MipsISA::gtoh(data); return true; } @@ -77,7 +77,7 @@ class ThreadInfo Addr sp; if (!addr) - addr = tc->readMiscRegNoEffect(0/*TheISA::IPR_PALtemp23*/); + addr = tc->readMiscRegNoEffect(0/*MipsISA::IPR_PALtemp23*/); FunctionalPort *p = tc->getPhysPort(); p->readBlob(addr, (uint8_t *)&sp, sizeof(Addr)); diff --git a/src/arch/mips/locked_mem.hh b/src/arch/mips/locked_mem.hh index 34da79ed9..021b8cf73 100644 --- a/src/arch/mips/locked_mem.hh +++ b/src/arch/mips/locked_mem.hh @@ -49,11 +49,10 @@ template <class XC> inline void handleLockedRead(XC *xc, Request *req) { - unsigned tid = req->getThreadNum(); - xc->setMiscRegNoEffect(LLAddr, req->getPaddr() & ~0xf, tid); - xc->setMiscRegNoEffect(LLFlag, true, tid); + xc->setMiscRegNoEffect(LLAddr, req->getPaddr() & ~0xf); + xc->setMiscRegNoEffect(LLFlag, true); DPRINTF(LLSC, "[tid:%i]: Load-Link Flag Set & Load-Link Address set to %x.\n", - tid, req->getPaddr() & ~0xf); + req->threadId(), req->getPaddr() & ~0xf); } @@ -61,22 +60,20 @@ template <class XC> inline bool handleLockedWrite(XC *xc, Request *req) { - unsigned tid = req->getThreadNum(); - if (req->isUncacheable()) { // Funky Turbolaser mailbox access...don't update // result register (see stq_c in decoder.isa) req->setExtraData(2); } else { // standard store conditional - bool lock_flag = xc->readMiscRegNoEffect(LLFlag, tid); - Addr lock_addr = xc->readMiscRegNoEffect(LLAddr, tid); + bool lock_flag = xc->readMiscRegNoEffect(LLFlag); + Addr lock_addr = xc->readMiscRegNoEffect(LLAddr); if (!lock_flag || (req->getPaddr() & ~0xf) != lock_addr) { // Lock flag not set or addr mismatch in CPU; // don't even bother sending to memory system req->setExtraData(0); - xc->setMiscRegNoEffect(LLFlag, false, tid); + xc->setMiscRegNoEffect(LLFlag, false); // the rest of this code is not architectural; // it's just a debugging aid to help detect @@ -86,9 +83,9 @@ handleLockedWrite(XC *xc, Request *req) stCondFailures++; xc->setStCondFailures(stCondFailures); if (stCondFailures % 10 == 0) { - warn("%i: cpu %d: %d consecutive " + warn("%i: context %d: %d consecutive " "store conditional failures\n", - curTick, xc->readCpuId(), stCondFailures); + curTick, xc->contextId(), stCondFailures); } if (stCondFailures == 5000) { @@ -97,10 +94,10 @@ handleLockedWrite(XC *xc, Request *req) if (!lock_flag){ DPRINTF(LLSC, "[tid:%i]: Lock Flag Set, Store Conditional Failed.\n", - tid); + req->threadId()); } else if ((req->getPaddr() & ~0xf) != lock_addr) { DPRINTF(LLSC, "[tid:%i]: Load-Link Address Mismatch, Store Conditional Failed.\n", - tid); + req->threadId()); } // store conditional failed already, so don't issue it to mem return false; diff --git a/src/arch/mips/microcode_rom.hh b/src/arch/mips/microcode_rom.hh new file mode 100644 index 000000000..a5be81e2a --- /dev/null +++ b/src/arch/mips/microcode_rom.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_MIPS_MICROCODE_ROM_HH__ +#define __ARCH_MIPS_MICROCODE_ROM_HH__ + +#include "sim/microcode_rom.hh" + +namespace MipsISA +{ + using ::MicrocodeRom; +} + +#endif // __ARCH_MIPS_MICROCODE_ROM_HH__ diff --git a/src/arch/mips/mips_core_specific.cc b/src/arch/mips/mips_core_specific.cc index a17ebcdf3..80d856b0c 100755 --- a/src/arch/mips/mips_core_specific.cc +++ b/src/arch/mips/mips_core_specific.cc @@ -113,13 +113,13 @@ MipsISA::processInterrupts(CPU *cpu) /*int MipsISA::MiscRegFile::getInstAsid() { - return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); + return AlphaISA::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } int MipsISA::MiscRegFile::getDataAsid() { - return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); + return AlphaISA::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); }*/ diff --git a/src/arch/mips/mt.hh b/src/arch/mips/mt.hh index 6765c27a9..d0c333d86 100755 --- a/src/arch/mips/mt.hh +++ b/src/arch/mips/mt.hh @@ -45,7 +45,6 @@ #include "base/misc.hh" #include <iostream> -using namespace std; namespace MipsISA { @@ -78,7 +77,7 @@ haltThread(TC *tc) // @TODO: Needs to check if this is a branch and if so, take previous instruction tc->setMiscReg(TCRestart, tc->readNextPC()); - warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->getThreadNum(), tc->getCpuPtr()->name(), + warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->threadId(), tc->getCpuPtr()->name(), tc->readPC(), tc->readNextPC()); } } @@ -98,7 +97,7 @@ restoreThread(TC *tc) tc->setNextNPC(pc + 8); tc->activate(0); - warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->getThreadNum(), tc->getCpuPtr()->name(), + warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->threadId(), tc->getCpuPtr()->name(), tc->readPC()); } } @@ -164,7 +163,7 @@ forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt) success = 1; } } else { - std::cerr << "Bad VPEs" << endl; + std::cerr << "Bad VPEs" << std::endl; } } @@ -217,10 +216,10 @@ yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask) if (ok == 1) { unsigned tcstatus = tc->readMiscRegNoEffect(TCStatus); tc->setMiscReg(TCStatus, insertBits(tcstatus, TCS_A, TCS_A, 0)); - warn("%i: Deactivating Hardware Thread Context #%i", curTick, tc->getThreadNum()); + warn("%i: Deactivating Hardware Thread Context #%i", curTick, tc->threadId()); } } else if (src_reg > 0) { - if (src_reg & !yield_mask != 0) { + if (src_reg && !yield_mask != 0) { unsigned vpe_control = tc->readMiscReg(VPEControl); tc->setMiscReg(VPEControl, insertBits(vpe_control, VPEC_EXCPT_HI, VPEC_EXCPT_LO, 2)); fault = new ThreadFault(); @@ -238,7 +237,7 @@ yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask) fault = new ThreadFault(); } else { //tc->ScheduleOtherThreads(); - //std::cerr << "T" << tc->getThreadNum() << "YIELD: Schedule Other Threads.\n" << std::endl; + //std::cerr << "T" << tc->threadId() << "YIELD: Schedule Other Threads.\n" << std::endl; //tc->suspend(); // Save last known PC in TCRestart // @TODO: Needs to check if this is a branch and if so, take previous instruction diff --git a/src/arch/mips/pagetable.hh b/src/arch/mips/pagetable.hh index 8c43a7b0c..bbed94194 100755 --- a/src/arch/mips/pagetable.hh +++ b/src/arch/mips/pagetable.hh @@ -59,9 +59,9 @@ namespace MipsISA { Addr level3() const { return MipsISA::PteAddr(addr >> PageShift); } Addr level2() const - { return MipsISA::PteAddr(addr >> NPtePageShift + PageShift); } + { return MipsISA::PteAddr(addr >> (NPtePageShift + PageShift)); } Addr level1() const - { return MipsISA::PteAddr(addr >> 2 * NPtePageShift + PageShift); } + { return MipsISA::PteAddr(addr >> (2 * NPtePageShift + PageShift)); } }; // ITB/DTB page table entry diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc index b7bd22d78..784ddfe33 100644 --- a/src/arch/mips/process.cc +++ b/src/arch/mips/process.cc @@ -40,6 +40,10 @@ using namespace std; using namespace MipsISA; +static const int SyscallSuccessReg = 7; +static const int FirstArgumentReg = 4; +static const int ReturnValueReg = 2; + MipsLiveProcess::MipsLiveProcess(LiveProcessParams * params, ObjectFile *objFile) : LiveProcess(params, objFile) @@ -64,3 +68,33 @@ MipsLiveProcess::startup() { argsInit(MachineBytes, VMPageSize); } + +MipsISA::IntReg +MipsLiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < 6); + return tc->readIntReg(FirstArgumentReg + i); +} + +void +MipsLiveProcess::setSyscallArg(ThreadContext *tc, + int i, MipsISA::IntReg val) +{ + assert(i < 6); + tc->setIntReg(FirstArgumentReg + i, val); +} + +void +MipsLiveProcess::setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) +{ + if (return_value.successful()) { + // no error + tc->setIntReg(SyscallSuccessReg, 0); + tc->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, return details + tc->setIntReg(SyscallSuccessReg, (IntReg) -1); + tc->setIntReg(ReturnValueReg, -return_value.value()); + } +} diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh index 18bf289b8..87c62330f 100644 --- a/src/arch/mips/process.hh +++ b/src/arch/mips/process.hh @@ -47,6 +47,10 @@ class MipsLiveProcess : public LiveProcess virtual void startup(); + public: + MipsISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, MipsISA::IntReg val); + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); }; diff --git a/src/arch/mips/regfile.cc b/src/arch/mips/regfile.cc index 0c670af6d..663115bb6 100644 --- a/src/arch/mips/regfile.cc +++ b/src/arch/mips/regfile.cc @@ -188,12 +188,6 @@ RegFile::unserialize(Checkpoint *cp, const std::string §ion) } - -void RegFile::changeContext(RegContextParam param, RegContextVal val) -{ - panic("Change Context Not Implemented for MipsISA"); -} - static inline int flattenIntIndex(ThreadContext * tc, int reg) { return reg; @@ -206,12 +200,6 @@ MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest) } void -MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest); -{ - panic("Copy Regs Not Implemented Yet\n"); -} - -void MipsISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) { panic("Copy Misc. Regs Not Implemented Yet\n"); diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh index 1537855df..0c0ecc7eb 100644 --- a/src/arch/mips/regfile/float_regfile.hh +++ b/src/arch/mips/regfile/float_regfile.hh @@ -44,11 +44,6 @@ class Checkpoint; namespace MipsISA { - static inline std::string getFloatRegName(RegIndex) - { - return ""; - } - const uint32_t MIPS32_QNAN = 0x7fbfffff; const uint64_t MIPS64_QNAN = ULL(0x7fbfffffffffffff); diff --git a/src/arch/mips/regfile/int_regfile.cc b/src/arch/mips/regfile/int_regfile.cc index c46ecf0b3..88de4be94 100644 --- a/src/arch/mips/regfile/int_regfile.cc +++ b/src/arch/mips/regfile/int_regfile.cc @@ -37,7 +37,6 @@ using namespace MipsISA; using namespace std; - void IntRegFile::clear() { @@ -45,29 +44,33 @@ IntRegFile::clear() currShadowSet=0; } +int +IntRegFile::readShadowSet() +{ + return currShadowSet; +} + void IntRegFile::setShadowSet(int css) { - DPRINTF(MipsPRA,"Setting Shadow Set to :%d (%s)\n",css,currShadowSet); + DPRINTF(MipsPRA, "Setting Shadow Set to :%d (%s)\n", css, currShadowSet); currShadowSet = css; } IntReg IntRegFile::readReg(int intReg) { - if(intReg < NumIntRegs) - { // Regular GPR Read - DPRINTF(MipsPRA,"Reading Reg: %d, CurrShadowSet: %d\n",intReg,currShadowSet); - if(intReg >= NumIntArchRegs*NumShadowRegSets){ - return regs[intReg+NumIntRegs*currShadowSet]; - } - else { - return regs[(intReg + NumIntArchRegs*currShadowSet) % NumIntArchRegs]; - } - } - else - { // Read from shadow GPR .. probably called by RDPGPR - return regs[intReg]; + if (intReg < NumIntArchRegs) { + // Regular GPR Read + DPRINTF(MipsPRA, "Reading Reg: %d, CurrShadowSet: %d\n", intReg, + currShadowSet); + + return regs[intReg + NumIntArchRegs * currShadowSet]; + } else { + unsigned special_reg_num = intReg - NumIntArchRegs; + + // Read A Special Reg + return regs[TotalArchRegs + special_reg_num]; } } @@ -75,20 +78,15 @@ Fault IntRegFile::setReg(int intReg, const IntReg &val) { if (intReg != ZeroReg) { + if (intReg < NumIntArchRegs) { + regs[intReg + NumIntArchRegs * currShadowSet] = val; + } else { + unsigned special_reg_num = intReg - NumIntArchRegs; - if(intReg < NumIntRegs) - { - if(intReg >= NumIntArchRegs*NumShadowRegSets){ - regs[intReg] = val; - } - else{ - regs[intReg+NumIntRegs*currShadowSet] = val; - } - } - else{ - regs[intReg] = val; + regs[TotalArchRegs + special_reg_num] = val; } } + return NoFault; } @@ -103,4 +101,3 @@ IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_ARRAY(regs, NumIntRegs); } - diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh index 8ddd276e6..c5a6bb345 100644 --- a/src/arch/mips/regfile/int_regfile.hh +++ b/src/arch/mips/regfile/int_regfile.hh @@ -42,13 +42,8 @@ class Checkpoint; namespace MipsISA { - static inline std::string getIntRegName(RegIndex) - { - return ""; - } - enum MiscIntRegNums { - LO = NumIntArchRegs*NumShadowRegSets, + LO = NumIntArchRegs, HI, DSPACX0, DSPLo1, @@ -72,6 +67,7 @@ namespace MipsISA int currShadowSet; public: void clear(); + int readShadowSet(); void setShadowSet(int css); IntReg readReg(int intReg); Fault setReg(int intReg, const IntReg &val); diff --git a/src/arch/mips/regfile/misc_regfile.cc b/src/arch/mips/regfile/misc_regfile.cc index dc6ae0baf..a00bf166e 100755..100644 --- a/src/arch/mips/regfile/misc_regfile.cc +++ b/src/arch/mips/regfile/misc_regfile.cc @@ -40,42 +40,55 @@ #include "cpu/base.hh" #include "cpu/exetrace.hh" +//#include "params/DerivO3CPU.hh" + using namespace std; +using namespace MipsISA; std::string MiscRegFile::miscRegNames[NumMiscRegs] = -{"Index", "MVPControl", "MVPConf0", "MVPConf1", "", "", "", "", - "Random", "VPEControl", "VPEConf0", "VPEConf1", "YQMask", "VPESchedule", "VPEScheFBack", "VPEOpt", - "EntryLo0", "TCStatus", "TCBind", "TCRestart", "TCHalt", "TCContext", "TCSchedule", "TCScheFBack", - "EntryLo1", "", "", "", "", "", "", "", - "Context", "ContextConfig", "", "", "", "", "", "", - "PageMask", "PageGrain", "", "", "", "", "", "", - "Wired", "SRSConf0", "SRCConf1", "SRSConf2", "SRSConf3", "SRSConf4", "", "", - "HWREna", "", "", "", "", "", "", "", - "BadVAddr", "", "", "", "", "", "", "", - "Count", "", "", "", "", "", "", "", - "EntryHi", "", "", "", "", "", "", "", - "Compare", "", "", "", "", "", "", "", - "Status", "IntCtl", "SRSCtl", "SRSMap", "", "", "", "", - "Cause", "", "", "", "", "", "", "", - "EPC", "", "", "", "", "", "", "", - "PRId", "EBase", "", "", "", "", "", "", - "Config", "Config1", "Config2", "Config3", "", "", "", "", - "LLAddr", "", "", "", "", "", "", "", - "WatchLo0", "WatchLo1", "WatchLo2", "WatchLo3", "WatchLo4", "WatchLo5", "WatchLo6", "WatchLo7", - "WatchHi0", "WatchHi1", "WatchHi2", "WatchHi3", "WatchHi4", "WatchHi5", "WatchHi6", "WatchHi7", - "XCContext64", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "Debug", "TraceControl1", "TraceControl2", "UserTraceData", "TraceBPC", "", "", "", - "DEPC", "", "", "", "", "", "", "", - "PerfCnt0", "PerfCnt1", "PerfCnt2", "PerfCnt3", "PerfCnt4", "PerfCnt5", "PerfCnt6", "PerfCnt7", - "ErrCtl", "", "", "", "", "", "", "", - "CacheErr0", "CacheErr1", "CacheErr2", "CacheErr3", "", "", "", "", - "TagLo0", "DataLo1", "TagLo2", "DataLo3", "TagLo4", "DataLo5", "TagLo6", "DataLo7", - "TagHi0", "DataHi1", "TagHi2", "DataHi3", "TagHi4", "DataHi5", "TagHi6", "DataHi7", - "ErrorEPC", "", "", "", "", "", "", "", - "DESAVE", "", "", "", "", "", "", "", - "LLFlag" +{ + "Index", "MVPControl", "MVPConf0", "MVPConf1", "", "", "", "", + "Random", "VPEControl", "VPEConf0", "VPEConf1", + "YQMask", "VPESchedule", "VPEScheFBack", "VPEOpt", + "EntryLo0", "TCStatus", "TCBind", "TCRestart", + "TCHalt", "TCContext", "TCSchedule", "TCScheFBack", + "EntryLo1", "", "", "", "", "", "", "", + "Context", "ContextConfig", "", "", "", "", "", "", + "PageMask", "PageGrain", "", "", "", "", "", "", + "Wired", "SRSConf0", "SRCConf1", "SRSConf2", + "SRSConf3", "SRSConf4", "", "", + "HWREna", "", "", "", "", "", "", "", + "BadVAddr", "", "", "", "", "", "", "", + "Count", "", "", "", "", "", "", "", + "EntryHi", "", "", "", "", "", "", "", + "Compare", "", "", "", "", "", "", "", + "Status", "IntCtl", "SRSCtl", "SRSMap", "", "", "", "", + "Cause", "", "", "", "", "", "", "", + "EPC", "", "", "", "", "", "", "", + "PRId", "EBase", "", "", "", "", "", "", + "Config", "Config1", "Config2", "Config3", "", "", "", "", + "LLAddr", "", "", "", "", "", "", "", + "WatchLo0", "WatchLo1", "WatchLo2", "WatchLo3", + "WatchLo4", "WatchLo5", "WatchLo6", "WatchLo7", + "WatchHi0", "WatchHi1", "WatchHi2", "WatchHi3", + "WatchHi4", "WatchHi5", "WatchHi6", "WatchHi7", + "XCContext64", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "Debug", "TraceControl1", "TraceControl2", "UserTraceData", + "TraceBPC", "", "", "", + "DEPC", "", "", "", "", "", "", "", + "PerfCnt0", "PerfCnt1", "PerfCnt2", "PerfCnt3", + "PerfCnt4", "PerfCnt5", "PerfCnt6", "PerfCnt7", + "ErrCtl", "", "", "", "", "", "", "", + "CacheErr0", "CacheErr1", "CacheErr2", "CacheErr3", "", "", "", "", + "TagLo0", "DataLo1", "TagLo2", "DataLo3", + "TagLo4", "DataLo5", "TagLo6", "DataLo7", + "TagHi0", "DataHi1", "TagHi2", "DataHi3", + "TagHi4", "DataHi5", "TagHi6", "DataHi7", + "ErrorEPC", "", "", "", "", "", "", "", + "DESAVE", "", "", "", "", "", "", "", + "LLFlag" }; MiscRegFile::MiscRegFile() @@ -170,11 +183,12 @@ void MiscRegFile::reset(std::string core_name, unsigned num_threads, unsigned num_vpes, BaseCPU *_cpu) { - DPRINTF(MipsPRA, "Resetting CP0 State with %i TCs and %i VPEs\n", num_threads, num_vpes); cpu = _cpu; - const BaseCPU::Params *p = _cpu->params; + + MipsISA::CoreSpecific &cp = cpu->coreParams; + // Do Default CP0 initialization HERE // Do Initialization for MT cores here (eventually use @@ -183,10 +197,10 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, DPRINTF(MipsPRA, "Initializing CP0 State.... "); MiscReg ProcID = readRegNoEffect(PRId); - replaceBits(ProcID,PRIdCoOp_HI,PRIdCoOp_LO,p->coreParams.CP0_PRId_CompanyOptions); - replaceBits(ProcID,PRIdCoID_HI,PRIdCoID_LO,p->coreParams.CP0_PRId_CompanyID); - replaceBits(ProcID,PRIdProc_ID_HI,PRIdProc_ID_LO,p->coreParams.CP0_PRId_ProcessorID); - replaceBits(ProcID,PRIdRev_HI,PRIdRev_LO,p->coreParams.CP0_PRId_Revision); + replaceBits(ProcID,PRIdCoOp_HI,PRIdCoOp_LO,cp.CP0_PRId_CompanyOptions); + replaceBits(ProcID,PRIdCoID_HI,PRIdCoID_LO,cp.CP0_PRId_CompanyID); + replaceBits(ProcID,PRIdProc_ID_HI,PRIdProc_ID_LO,cp.CP0_PRId_ProcessorID); + replaceBits(ProcID,PRIdRev_HI,PRIdRev_LO,cp.CP0_PRId_Revision); setRegNoEffect(PRId,ProcID); // Now, create Write Mask for ProcID register MiscReg ProcID_Mask = 0; // Read-Only register @@ -195,11 +209,11 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Config MiscReg cfg = readRegNoEffect(Config); - replaceBits(cfg, Config_BE_HI, Config_BE_LO, p->coreParams.CP0_Config_BE); - replaceBits(cfg, Config_AT_HI, Config_AT_LO, p->coreParams.CP0_Config_AT); - replaceBits(cfg, Config_AR_HI, Config_AR_LO, p->coreParams.CP0_Config_AR); - replaceBits(cfg, Config_MT_HI, Config_MT_LO, p->coreParams.CP0_Config_MT); - replaceBits(cfg, Config_VI_HI, Config_VI_LO, p->coreParams.CP0_Config_VI); + replaceBits(cfg, Config_BE_HI, Config_BE_LO, cp.CP0_Config_BE); + replaceBits(cfg, Config_AT_HI, Config_AT_LO, cp.CP0_Config_AT); + replaceBits(cfg, Config_AR_HI, Config_AR_LO, cp.CP0_Config_AR); + replaceBits(cfg, Config_MT_HI, Config_MT_LO, cp.CP0_Config_MT); + replaceBits(cfg, Config_VI_HI, Config_VI_LO, cp.CP0_Config_VI); replaceBits(cfg, Config_M, 1); setRegNoEffect(Config, cfg); // Now, create Write Mask for Config register @@ -209,20 +223,21 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Config1 MiscReg cfg1 = readRegNoEffect(Config1); - replaceBits(cfg1, Config1_MMUSize_HI, Config1_MMUSize_LO, p->coreParams.CP0_Config1_MMU); - replaceBits(cfg1, Config1_IS_HI, Config1_IS_LO, p->coreParams.CP0_Config1_IS); - replaceBits(cfg1, Config1_IL_HI, Config1_IL_LO, p->coreParams.CP0_Config1_IL); - replaceBits(cfg1, Config1_IA_HI, Config1_IA_LO, p->coreParams.CP0_Config1_IA); - replaceBits(cfg1, Config1_DS_HI, Config1_DS_LO, p->coreParams.CP0_Config1_DS); - replaceBits(cfg1, Config1_DL_HI, Config1_DL_LO, p->coreParams.CP0_Config1_DL); - replaceBits(cfg1, Config1_DA_HI, Config1_DA_LO, p->coreParams.CP0_Config1_DA); - replaceBits(cfg1, Config1_FP_HI, Config1_FP_LO, p->coreParams.CP0_Config1_FP); - replaceBits(cfg1, Config1_EP_HI, Config1_EP_LO, p->coreParams.CP0_Config1_EP); - replaceBits(cfg1, Config1_WR_HI, Config1_WR_LO, p->coreParams.CP0_Config1_WR); - replaceBits(cfg1, Config1_MD_HI, Config1_MD_LO, p->coreParams.CP0_Config1_MD); - replaceBits(cfg1, Config1_C2_HI, Config1_C2_LO, p->coreParams.CP0_Config1_C2); - replaceBits(cfg1, Config1_PC_HI, Config1_PC_LO, p->coreParams.CP0_Config1_PC); - replaceBits(cfg1, Config1_M, p->coreParams.CP0_Config1_M); + replaceBits(cfg1, Config1_MMUSize_HI, Config1_MMUSize_LO, + cp.CP0_Config1_MMU); + replaceBits(cfg1, Config1_IS_HI, Config1_IS_LO, cp.CP0_Config1_IS); + replaceBits(cfg1, Config1_IL_HI, Config1_IL_LO, cp.CP0_Config1_IL); + replaceBits(cfg1, Config1_IA_HI, Config1_IA_LO, cp.CP0_Config1_IA); + replaceBits(cfg1, Config1_DS_HI, Config1_DS_LO, cp.CP0_Config1_DS); + replaceBits(cfg1, Config1_DL_HI, Config1_DL_LO, cp.CP0_Config1_DL); + replaceBits(cfg1, Config1_DA_HI, Config1_DA_LO, cp.CP0_Config1_DA); + replaceBits(cfg1, Config1_FP_HI, Config1_FP_LO, cp.CP0_Config1_FP); + replaceBits(cfg1, Config1_EP_HI, Config1_EP_LO, cp.CP0_Config1_EP); + replaceBits(cfg1, Config1_WR_HI, Config1_WR_LO, cp.CP0_Config1_WR); + replaceBits(cfg1, Config1_MD_HI, Config1_MD_LO, cp.CP0_Config1_MD); + replaceBits(cfg1, Config1_C2_HI, Config1_C2_LO, cp.CP0_Config1_C2); + replaceBits(cfg1, Config1_PC_HI, Config1_PC_LO, cp.CP0_Config1_PC); + replaceBits(cfg1, Config1_M, cp.CP0_Config1_M); setRegNoEffect(Config1, cfg1); // Now, create Write Mask for Config register MiscReg cfg1_Mask = 0; // Read Only Register @@ -231,15 +246,15 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Config2 MiscReg cfg2 = readRegNoEffect(Config2); - replaceBits(cfg2, Config2_TU_HI, Config2_TU_LO, p->coreParams.CP0_Config2_TU); - replaceBits(cfg2, Config2_TS_HI, Config2_TS_LO, p->coreParams.CP0_Config2_TS); - replaceBits(cfg2, Config2_TL_HI, Config2_TL_LO, p->coreParams.CP0_Config2_TL); - replaceBits(cfg2, Config2_TA_HI, Config2_TA_LO, p->coreParams.CP0_Config2_TA); - replaceBits(cfg2, Config2_SU_HI, Config2_SU_LO, p->coreParams.CP0_Config2_SU); - replaceBits(cfg2, Config2_SS_HI, Config2_SS_LO, p->coreParams.CP0_Config2_SS); - replaceBits(cfg2, Config2_SL_HI, Config2_SL_LO, p->coreParams.CP0_Config2_SL); - replaceBits(cfg2, Config2_SA_HI, Config2_SA_LO, p->coreParams.CP0_Config2_SA); - replaceBits(cfg2, Config2_M, p->coreParams.CP0_Config2_M); + replaceBits(cfg2, Config2_TU_HI, Config2_TU_LO, cp.CP0_Config2_TU); + replaceBits(cfg2, Config2_TS_HI, Config2_TS_LO, cp.CP0_Config2_TS); + replaceBits(cfg2, Config2_TL_HI, Config2_TL_LO, cp.CP0_Config2_TL); + replaceBits(cfg2, Config2_TA_HI, Config2_TA_LO, cp.CP0_Config2_TA); + replaceBits(cfg2, Config2_SU_HI, Config2_SU_LO, cp.CP0_Config2_SU); + replaceBits(cfg2, Config2_SS_HI, Config2_SS_LO, cp.CP0_Config2_SS); + replaceBits(cfg2, Config2_SL_HI, Config2_SL_LO, cp.CP0_Config2_SL); + replaceBits(cfg2, Config2_SA_HI, Config2_SA_LO, cp.CP0_Config2_SA); + replaceBits(cfg2, Config2_M, cp.CP0_Config2_M); setRegNoEffect(Config2, cfg2); // Now, create Write Mask for Config register MiscReg cfg2_Mask = 0x7000F000; // Read Only Register @@ -248,14 +263,14 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Config3 MiscReg cfg3 = readRegNoEffect(Config3); - replaceBits(cfg3, Config3_DSPP_HI, Config3_DSPP_LO, p->coreParams.CP0_Config3_DSPP); - replaceBits(cfg3, Config3_LPA_HI, Config3_LPA_LO, p->coreParams.CP0_Config3_LPA); - replaceBits(cfg3, Config3_VEIC_HI, Config3_VEIC_LO, p->coreParams.CP0_Config3_VEIC); - replaceBits(cfg3, Config3_VINT_HI, Config3_VINT_LO, p->coreParams.CP0_Config3_VInt); - replaceBits(cfg3, Config3_SP_HI, Config3_SP_LO, p->coreParams.CP0_Config3_SP); - replaceBits(cfg3, Config3_MT_HI, Config3_MT_LO, p->coreParams.CP0_Config3_MT); - replaceBits(cfg3, Config3_SM_HI, Config3_SM_LO, p->coreParams.CP0_Config3_SM); - replaceBits(cfg3, Config3_TL_HI, Config3_TL_LO, p->coreParams.CP0_Config3_TL); + replaceBits(cfg3, Config3_DSPP_HI, Config3_DSPP_LO, cp.CP0_Config3_DSPP); + replaceBits(cfg3, Config3_LPA_HI, Config3_LPA_LO, cp.CP0_Config3_LPA); + replaceBits(cfg3, Config3_VEIC_HI, Config3_VEIC_LO, cp.CP0_Config3_VEIC); + replaceBits(cfg3, Config3_VINT_HI, Config3_VINT_LO, cp.CP0_Config3_VInt); + replaceBits(cfg3, Config3_SP_HI, Config3_SP_LO, cp.CP0_Config3_SP); + replaceBits(cfg3, Config3_MT_HI, Config3_MT_LO, cp.CP0_Config3_MT); + replaceBits(cfg3, Config3_SM_HI, Config3_SM_LO, cp.CP0_Config3_SM); + replaceBits(cfg3, Config3_TL_HI, Config3_TL_LO, cp.CP0_Config3_TL); setRegNoEffect(Config3, cfg3); // Now, create Write Mask for Config register MiscReg cfg3_Mask = 0; // Read Only Register @@ -264,7 +279,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // EBase - CPUNum MiscReg EB = readRegNoEffect(EBase); - replaceBits(EB, EBase_CPUNum_HI, EBase_CPUNum_LO, p->coreParams.CP0_EBase_CPUNum); + replaceBits(EB, EBase_CPUNum_HI, EBase_CPUNum_LO, cp.CP0_EBase_CPUNum); replaceBits(EB, 31, 31, 1); setRegNoEffect(EBase, EB); // Now, create Write Mask for Config register @@ -275,7 +290,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // SRS Control - HSS (Highest Shadow Set) MiscReg SC = readRegNoEffect(SRSCtl); - replaceBits(SC, SRSCtl_HSS_HI,SRSCtl_HSS_LO,p->coreParams.CP0_SrsCtl_HSS); + replaceBits(SC, SRSCtl_HSS_HI,SRSCtl_HSS_LO,cp.CP0_SrsCtl_HSS); setRegNoEffect(SRSCtl, SC); // Now, create Write Mask for the SRS Ctl register MiscReg SC_Mask = 0x0000F3C0; @@ -284,8 +299,8 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // IntCtl - IPTI, IPPCI MiscReg IC = readRegNoEffect(IntCtl); - replaceBits(IC, IntCtl_IPTI_HI,IntCtl_IPTI_LO,p->coreParams.CP0_IntCtl_IPTI); - replaceBits(IC, IntCtl_IPPCI_HI,IntCtl_IPPCI_LO,p->coreParams.CP0_IntCtl_IPPCI); + replaceBits(IC, IntCtl_IPTI_HI,IntCtl_IPTI_LO,cp.CP0_IntCtl_IPTI); + replaceBits(IC, IntCtl_IPPCI_HI,IntCtl_IPPCI_LO,cp.CP0_IntCtl_IPPCI); setRegNoEffect(IntCtl, IC); // Now, create Write Mask for the IntCtl register MiscReg IC_Mask = 0x000003E0; @@ -294,7 +309,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Watch Hi - M - FIXME (More than 1 Watch register) MiscReg WHi = readRegNoEffect(WatchHi0); - replaceBits(WHi, WatchHi_M, p->coreParams.CP0_WatchHi_M); + replaceBits(WHi, WatchHi_M, cp.CP0_WatchHi_M); setRegNoEffect(WatchHi0, WHi); // Now, create Write Mask for the IntCtl register MiscReg wh_Mask = 0x7FFF0FFF; @@ -303,8 +318,8 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Perf Ctr - M - FIXME (More than 1 PerfCnt Pair) MiscReg PCtr = readRegNoEffect(PerfCnt0); - replaceBits(PCtr, PerfCntCtl_M, p->coreParams.CP0_PerfCtr_M); - replaceBits(PCtr, PerfCntCtl_W, p->coreParams.CP0_PerfCtr_W); + replaceBits(PCtr, PerfCntCtl_M, cp.CP0_PerfCtr_M); + replaceBits(PCtr, PerfCntCtl_W, cp.CP0_PerfCtr_W); setRegNoEffect(PerfCnt0, PCtr); // Now, create Write Mask for the IntCtl register MiscReg pc_Mask = 0x00007FF; @@ -322,7 +337,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // PageGrain MiscReg pagegrain = readRegNoEffect(PageGrain); - replaceBits(pagegrain,PageGrain_ESP,p->coreParams.CP0_Config3_SP); + replaceBits(pagegrain,PageGrain_ESP,cp.CP0_Config3_SP); setRegNoEffect(PageGrain, pagegrain); // Now, create Write Mask for the IntCtl register MiscReg pg_Mask = 0x10000000; @@ -331,12 +346,18 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, // Status MiscReg stat = readRegNoEffect(Status); - // Only CU0 and IE are modified on a reset - everything else needs to be controlled - // on a per CPU model basis - // replaceBits(stat, Status_CU0_HI,Status_CU0_LO, 1); // Enable CP0 on reset + // Only CU0 and IE are modified on a reset - everything else needs + // to be controlled on a per CPU model basis + + // Enable CP0 on reset + // replaceBits(stat, Status_CU0_HI,Status_CU0_LO, 1); + + // Enable ERL bit on a reset + replaceBits(stat, Status_ERL_HI, Status_ERL_LO, 1); + + // Enable BEV bit on a reset + replaceBits(stat, Status_BEV_HI, Status_BEV_LO, 1); - replaceBits(stat, Status_ERL_HI, Status_ERL_LO, 1); // Enable ERL bit on a reset - replaceBits(stat, Status_BEV_HI, Status_BEV_LO, 1); // Enable BEV bit on a reset setRegNoEffect(Status, stat); // Now, create Write Mask for the Status register MiscReg stat_Mask = 0xFF78FF17; @@ -417,12 +438,6 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads, } -inline std::string -MipsISA::getMiscRegName(unsigned reg_idx) -{ - return MiscRegFile::miscRegNames[reg_idx]; -} - inline unsigned MiscRegFile::getVPENum(unsigned tid) { @@ -437,7 +452,8 @@ MiscRegFile::readRegNoEffect(int reg_idx, unsigned tid) unsigned reg_sel = (bankType[misc_reg] == perThreadContext) ? tid : getVPENum(tid); DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) (%lx).\n", - misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg),miscRegFile[misc_reg][reg_sel]); + misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], + miscRegFile[misc_reg][reg_sel]); return miscRegFile[misc_reg][reg_sel]; } @@ -451,8 +467,10 @@ MiscRegFile::readReg(int reg_idx, int misc_reg = reg_idx - Ctrl_Base_DepTag; unsigned reg_sel = (bankType[misc_reg] == perThreadContext) ? tid : getVPENum(tid); - DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n", - misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg),miscRegFile[misc_reg][reg_sel]); + DPRINTF(MipsPRA, + "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n", + misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], + miscRegFile[misc_reg][reg_sel]); switch (misc_reg) @@ -468,8 +486,10 @@ MiscRegFile::setRegNoEffect(int reg_idx, const MiscReg &val, unsigned tid) int misc_reg = reg_idx - Ctrl_Base_DepTag; unsigned reg_sel = (bankType[misc_reg] == perThreadContext) ? tid : getVPENum(tid); - DPRINTF(MipsPRA, "[tid:%i]: Setting (direct set) CP0 Register:%u Select:%u (%s) to %#x.\n", - tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val); + DPRINTF(MipsPRA, + "[tid:%i]: Setting (direct set) CP0 Register:%u " + "Select:%u (%s) to %#x.\n", + tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); miscRegFile[misc_reg][reg_sel] = val; } @@ -480,7 +500,9 @@ MiscRegFile::setRegMask(int reg_idx, const MiscReg &val, unsigned tid) int misc_reg = reg_idx - Ctrl_Base_DepTag; unsigned reg_sel = (bankType[misc_reg] == perThreadContext) ? tid : getVPENum(tid); - DPRINTF(MipsPRA,"[tid:%i]: Setting CP0 Register: %u Select: %u (%s) to %#x\n",tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val); + DPRINTF(MipsPRA, + "[tid:%i]: Setting CP0 Register: %u Select: %u (%s) to %#x\n", + tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); miscRegFile_WriteMask[misc_reg][reg_sel] = val; } @@ -497,8 +519,10 @@ MiscRegFile::setReg(int reg_idx, const MiscReg &val, int reg_sel = (bankType[misc_reg] == perThreadContext) ? tid : getVPENum(tid); - DPRINTF(MipsPRA, "[tid:%i]: Setting CP0 Register:%u Select:%u (%s) to %#x, with effect.\n", - tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val); + DPRINTF(MipsPRA, + "[tid:%i]: Setting CP0 Register:%u " + "Select:%u (%s) to %#x, with effect.\n", + tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val); MiscReg cp0_val = filterCP0Write(misc_reg, reg_sel, val); @@ -506,16 +530,28 @@ MiscRegFile::setReg(int reg_idx, const MiscReg &val, scheduleCP0Update(1); } -/** This method doesn't need to adjust the Control Register Offset since - it has already been done in the calling method (setRegWithEffect) */ -MiscReg MiscRegFile::filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val) +/** + * This method doesn't need to adjust the Control Register Offset + * since it has already been done in the calling method + * (setRegWithEffect) +*/ +MiscReg +MiscRegFile::filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val) { MiscReg retVal = val; - retVal &= miscRegFile_WriteMask[misc_reg][reg_sel]; // Mask off read-only regions + + // Mask off read-only regions + retVal &= miscRegFile_WriteMask[misc_reg][reg_sel]; MiscReg curVal = miscRegFile[misc_reg][reg_sel]; - curVal &= (~miscRegFile_WriteMask[misc_reg][reg_sel]); // Mask off current alue with inverse mask (clear writeable bits) + // Mask off current alue with inverse mask (clear writeable bits) + curVal &= (~miscRegFile_WriteMask[misc_reg][reg_sel]); retVal |= curVal; // Combine the two - DPRINTF(MipsPRA,"filterCP0Write: Mask: %lx, Inverse Mask: %lx, write Val: %x, current val: %lx, written val: %x\n",miscRegFile_WriteMask[misc_reg][reg_sel],~miscRegFile_WriteMask[misc_reg][reg_sel],val,miscRegFile[misc_reg][reg_sel],retVal); + DPRINTF(MipsPRA, + "filterCP0Write: Mask: %lx, Inverse Mask: %lx, write Val: %x, " + "current val: %lx, written val: %x\n", + miscRegFile_WriteMask[misc_reg][reg_sel], + ~miscRegFile_WriteMask[misc_reg][reg_sel], + val, miscRegFile[misc_reg][reg_sel], retVal); return retVal; } void @@ -526,7 +562,7 @@ MiscRegFile::scheduleCP0Update(int delay) //schedule UPDATE CP0Event *cp0_event = new CP0Event(this, cpu, UpdateCP0); - cp0_event->schedule(curTick + cpu->ticks(delay)); + cpu->schedule(cp0_event, curTick + cpu->ticks(delay)); } } @@ -560,7 +596,7 @@ MiscRegFile::updateCPU() } MiscRegFile::CP0Event::CP0Event(CP0 *_cp0, BaseCPU *_cpu, CP0EventType e_type) - : Event(&mainEventQueue, CPU_Tick_Pri), cp0(_cp0), cpu(_cpu), cp0EventType(e_type) + : Event(CPU_Tick_Pri), cp0(_cp0), cpu(_cpu), cp0EventType(e_type) { } void @@ -585,10 +621,7 @@ MiscRegFile::CP0Event::description() const void MiscRegFile::CP0Event::scheduleEvent(int delay) { - if (squashed()) - reschedule(curTick + cpu->ticks(delay)); - else if (!scheduled()) - schedule(curTick + cpu->ticks(delay)); + cpu->reschedule(this, curTick + cpu->ticks(delay), true); } void diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh index 5f19579b3..c611d94cc 100644 --- a/src/arch/mips/regfile/misc_regfile.hh +++ b/src/arch/mips/regfile/misc_regfile.hh @@ -75,7 +75,8 @@ namespace MipsISA void clear(unsigned tid_or_vpn = 0); - void reset(std::string core_name, unsigned num_threads, unsigned num_vpes, BaseCPU *_cpu); + void reset(std::string core_name, unsigned num_threads, + unsigned num_vpes, BaseCPU *_cpu); void expandForMultithreading(unsigned num_threads, unsigned num_vpes); @@ -98,7 +99,8 @@ namespace MipsISA MiscReg filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val); void setRegMask(int misc_reg, const MiscReg &val, unsigned tid = 0); - void setRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0); + void setRegNoEffect(int misc_reg, const MiscReg &val, + unsigned tid = 0); //template <class TC> void setReg(int misc_reg, const MiscReg &val, @@ -160,8 +162,6 @@ namespace MipsISA static std::string miscRegNames[NumMiscRegs]; }; - - inline std::string getMiscRegName(unsigned reg_idx); } // namespace MipsISA #endif diff --git a/src/arch/mips/regfile/regfile.cc b/src/arch/mips/regfile/regfile.cc index 996c14f14..a1c8eab6a 100644 --- a/src/arch/mips/regfile/regfile.cc +++ b/src/arch/mips/regfile/regfile.cc @@ -193,7 +193,7 @@ RegFile::setNextNPC(Addr val) } void -RegFile::serialize(std::ostream &os) +RegFile::serialize(EventManager *em, std::ostream &os) { intRegFile.serialize(os); //SERIALIZE_ARRAY(floatRegFile, NumFloatRegs); @@ -207,7 +207,8 @@ RegFile::serialize(std::ostream &os) } void -RegFile::unserialize(Checkpoint *cp, const std::string §ion) +RegFile::unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion) { intRegFile.unserialize(cp, section); //UNSERIALIZE_ARRAY(floatRegFile); diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh index 8304b7cda..ebf793396 100644 --- a/src/arch/mips/regfile/regfile.hh +++ b/src/arch/mips/regfile/regfile.hh @@ -41,22 +41,23 @@ //#include "cpu/base.hh" #include "sim/faults.hh" -class Checkpoint; class BaseCPU; +class Checkpoint; +class EventManager; namespace MipsISA { class RegFile { protected: - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; // next-next-cycle program counter + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; // next-next-cycle program counter // used to implement branch delay slot // not real register - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegFile; // control register file + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file public: void clear(); @@ -99,12 +100,9 @@ namespace MipsISA Addr readNextNPC(); void setNextNPC(Addr val); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - void changeContext(RegContextParam param, RegContextVal val) - { - } + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); }; diff --git a/src/arch/mips/stacktrace.cc b/src/arch/mips/stacktrace.cc index 6c6f6bb3c..04a9a0f18 100644 --- a/src/arch/mips/stacktrace.cc +++ b/src/arch/mips/stacktrace.cc @@ -70,8 +70,6 @@ ProcessInfo::ProcessInfo(ThreadContext *_tc) // if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) // panic("thread info not compiled into kernel\n"); // name_off = vp->readGtoH<int32_t>(addr); - - tc->delVirtPort(vp); } Addr @@ -87,7 +85,6 @@ ProcessInfo::task(Addr ksp) const vp = tc->getVirtPort(); tsk = vp->readGtoH<Addr>(base + task_off); - tc->delVirtPort(vp); return tsk; } @@ -105,7 +102,6 @@ ProcessInfo::pid(Addr ksp) const vp = tc->getVirtPort(); pd = vp->readGtoH<uint16_t>(task + pid_off); - tc->delVirtPort(vp); return pd; } @@ -163,7 +159,7 @@ StackTrace::trace(ThreadContext *_tc, bool is_call) // } // SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; -// Addr ksp = tc->readIntReg(TheISA::StackPointerReg); +// Addr ksp = tc->readIntReg(MipsISA::StackPointerReg); // Addr bottom = ksp & ~0x3fff; // Addr addr; diff --git a/src/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh index e2424523f..4c02cc86c 100644 --- a/src/arch/mips/stacktrace.hh +++ b/src/arch/mips/stacktrace.hh @@ -61,7 +61,7 @@ class ProcessInfo class StackTrace { protected: - typedef TheISA::MachInst MachInst; + typedef MipsISA::MachInst MachInst; private: ThreadContext *tc; std::vector<Addr> stack; diff --git a/src/arch/mips/system.cc b/src/arch/mips/system.cc index 605acfe32..73bc33161 100755 --- a/src/arch/mips/system.cc +++ b/src/arch/mips/system.cc @@ -134,9 +134,9 @@ MipsSystem::~MipsSystem() * in the procedure value register (pv aka t12 == r27). This sequence * looks like the following: * - * opcode Ra Rb offset - * ldah gp,X(pv) 09 29 27 X - * lda gp,Y(gp) 08 29 29 Y + * opcode Ra Rb offset + * ldah gp,X(pv) 09 29 27 X + * lda gp,Y(gp) 08 29 29 Y * * for some constant offsets X and Y. The catch is that the linker * (or maybe even the compiler, I'm not sure) may recognize that the @@ -185,7 +185,7 @@ MipsSystem::setMipsAccess(Addr access) { Addr addr = 0; if (consoleSymtab->findAddress("m5MipsAccess", addr)) { - // virtPort.write(addr, htog(EV5::Phys2K0Seg(access))); + // virtPort.write(addr, htog(AlphaISA::Phys2K0Seg(access))); } else panic("could not find m5MipsAccess\n"); } diff --git a/src/arch/mips/tlb.cc b/src/arch/mips/tlb.cc index d78aefab4..eac44eba8 100644 --- a/src/arch/mips/tlb.cc +++ b/src/arch/mips/tlb.cc @@ -59,7 +59,7 @@ using namespace MipsISA; // MIPS TLB // -#define MODE2MASK(X) (1 << (X)) +#define MODE2MASK(X) (1 << (X)) TLB::TLB(const Params *p) : BaseTLB(p), size(p->size), nlu(0) @@ -91,7 +91,7 @@ TLB::lookup(Addr vpn, uint8_t asn) const Addr Mask = pte->Mask; Addr InvMask = ~Mask; Addr VPN = pte->VPN; - // warn("Valid: %d - %d\n",pte->V0,pte->V1); + // warn("Valid: %d - %d\n",pte->V0,pte->V1); if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid))) { // We have a VPN + ASID Match retval = pte; @@ -149,7 +149,7 @@ TLB::checkCacheability(RequestPtr &req) // or by the TLB entry if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) { // mark request as uncacheable - req->setFlags(req->getFlags() | UNCACHEABLE); + req->setFlags(Request::UNCACHEABLE); } return NoFault; } @@ -310,7 +310,7 @@ TLB::regStats() } Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -389,7 +389,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) } else {// Ok, this is really a match, set paddr - // hits++; + // hits++; Addr PAddr; if(EvenOdd == 0){ PAddr = pte->PFN0; @@ -406,7 +406,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) } else { // Didn't find any match, return a TLB Refill Exception - // misses++; + // misses++; ItbRefillFault *Flt=new ItbRefillFault(); /* EntryHi VPN, ASID fields must be set */ Flt->EntryHi_Asid = Asid; @@ -426,8 +426,16 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) #endif } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -494,7 +502,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if(Valid == false) {//Invalid entry - // invalids++; + // invalids++; DtbInvalidFault *Flt = new DtbInvalidFault(); /* EntryHi VPN, ASID fields must be set */ Flt->EntryHi_Asid = Asid; @@ -512,7 +520,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) } else {// Ok, this is really a match, set paddr - // hits++; + // hits++; if(!Dirty) { TLBModifiedFault *Flt = new TLBModifiedFault(); @@ -544,7 +552,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) } else { // Didn't find any match, return a TLB Refill Exception - // misses++; + // misses++; DtbRefillFault *Flt=new DtbRefillFault(); /* EntryHi VPN, ASID fields must be set */ Flt->EntryHi_Asid = Asid; @@ -564,6 +572,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) #endif } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + /////////////////////////////////////////////////////////////////////// // // Mips ITB @@ -577,19 +593,19 @@ ITB::ITB(const Params *p) // ITB::regStats() // { // /* hits - causes failure for some reason -// .name(name() + ".hits") -// .desc("ITB hits"); +// .name(name() + ".hits") +// .desc("ITB hits"); // misses -// .name(name() + ".misses") -// .desc("ITB misses"); +// .name(name() + ".misses") +// .desc("ITB misses"); // acv -// .name(name() + ".acv") -// .desc("ITB acv"); +// .name(name() + ".acv") +// .desc("ITB acv"); // accesses -// .name(name() + ".accesses") -// .desc("ITB accesses"); +// .name(name() + ".accesses") +// .desc("ITB accesses"); -// accesses = hits + misses + invalids; */ +// accesses = hits + misses + invalids; */ // } diff --git a/src/arch/mips/tlb.hh b/src/arch/mips/tlb.hh index 4333777ff..dc0babf9a 100644 --- a/src/arch/mips/tlb.hh +++ b/src/arch/mips/tlb.hh @@ -68,6 +68,9 @@ struct TlbEntry return _pageStart; } + void + updateVaddr(Addr new_vaddr) {} + void serialize(std::ostream &os) { SERIALIZE_SCALAR(_pageStart); @@ -84,23 +87,23 @@ class TLB : public BaseTLB { protected: typedef std::multimap<Addr, int> PageTable; - PageTable lookupTable; // Quick lookup into page table + PageTable lookupTable; // Quick lookup into page table - MipsISA::PTE *table; // the Page Table - int size; // TLB Size - int nlu; // not last used entry (for replacement) + MipsISA::PTE *table; // the Page Table + int size; // TLB Size + int nlu; // not last used entry (for replacement) void nextnlu() { if (++nlu >= size) nlu = 0; } MipsISA::PTE *lookup(Addr vpn, uint8_t asn) const; - mutable Stats::Scalar<> read_hits; - mutable Stats::Scalar<> read_misses; - mutable Stats::Scalar<> read_acv; - mutable Stats::Scalar<> read_accesses; - mutable Stats::Scalar<> write_hits; - mutable Stats::Scalar<> write_misses; - mutable Stats::Scalar<> write_acv; - mutable Stats::Scalar<> write_accesses; + mutable Stats::Scalar read_hits; + mutable Stats::Scalar read_misses; + mutable Stats::Scalar read_acv; + mutable Stats::Scalar read_accesses; + mutable Stats::Scalar write_hits; + mutable Stats::Scalar write_misses; + mutable Stats::Scalar write_acv; + mutable Stats::Scalar write_accesses; Stats::Formula hits; Stats::Formula misses; Stats::Formula invalids; @@ -142,7 +145,9 @@ class ITB : public TLB { typedef MipsTLBParams Params; ITB(const Params *p); - Fault translate(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); }; class DTB : public TLB { @@ -150,7 +155,10 @@ class DTB : public TLB { typedef MipsTLBParams Params; DTB(const Params *p); - Fault translate(RequestPtr &req, ThreadContext *tc, bool write = false); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, + bool write = false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write = false); }; class UTB : public ITB, public DTB { diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh index 4208cb2d8..b459d9e14 100644 --- a/src/arch/mips/types.hh +++ b/src/arch/mips/types.hh @@ -60,9 +60,6 @@ namespace MipsISA MiscReg ctrlreg; } AnyReg; - typedef int RegContextParam; - typedef int RegContextVal; - //used in FP convert & round function enum ConvertType{ SINGLE_TO_DOUBLE, diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc index c254811fa..5908caf68 100644 --- a/src/arch/mips/utility.cc +++ b/src/arch/mips/utility.cc @@ -59,10 +59,9 @@ getArgument(ThreadContext *tc, int number, bool fp) return tc->readIntReg(ArgumentReg[number]); } else { Addr sp = tc->readIntReg(StackPointerReg); - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); uint64_t arg = vp->read<uint64_t>(sp + (number-NumArgumentRegs) * sizeof(uint64_t)); - tc->delVirtPort(vp); return arg; } #else @@ -146,7 +145,7 @@ genCCVector(uint32_t fcsr, int cc_num, uint32_t cc_val) { int cc_idx = (cc_num == 0) ? 23 : cc_num + 24; - fcsr = bits(fcsr, 31, cc_idx + 1) << cc_idx + 1 | + fcsr = bits(fcsr, 31, cc_idx + 1) << (cc_idx + 1) | cc_val << cc_idx | bits(fcsr, cc_idx - 1, 0); @@ -260,7 +259,7 @@ zeroRegisters(CPU *cpu) void startupCPU(ThreadContext *tc, int cpuId) { - tc->activate(0/*tc->getThreadNum()*/); + tc->activate(0/*tc->threadId()*/); } } // namespace MipsISA diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript index a86c00250..940cf2076 100644 --- a/src/arch/sparc/SConscript +++ b/src/arch/sparc/SConscript @@ -44,11 +44,14 @@ if env['TARGET_ISA'] == 'sparc': Source('utility.cc') SimObject('SparcTLB.py') - TraceFlag('Sparc') + TraceFlag('Sparc', "Generic SPARC ISA stuff") + TraceFlag('RegisterWindows', "Register window manipulation") if env['FULL_SYSTEM']: SimObject('SparcSystem.py') + SimObject('SparcInterrupts.py') + Source('interrupts.cc') Source('stacktrace.cc') Source('system.cc') Source('ua2005.cc') diff --git a/src/arch/sparc/SparcInterrupts.py b/src/arch/sparc/SparcInterrupts.py new file mode 100644 index 000000000..2cc964c2d --- /dev/null +++ b/src/arch/sparc/SparcInterrupts.py @@ -0,0 +1,33 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject + +class SparcInterrupts(SimObject): + type = 'SparcInterrupts' + cxx_class = 'SparcISA::Interrupts' diff --git a/src/arch/sparc/SparcTLB.py b/src/arch/sparc/SparcTLB.py index 2d0257cd7..6758d612a 100644 --- a/src/arch/sparc/SparcTLB.py +++ b/src/arch/sparc/SparcTLB.py @@ -28,21 +28,20 @@ from m5.SimObject import SimObject from m5.params import * -class SparcTLB(SimObject): + +from BaseTLB import BaseTLB + +class SparcTLB(BaseTLB): type = 'SparcTLB' abstract = True size = Param.Int("TLB size") class SparcDTB(SparcTLB): type = 'SparcDTB' - cxx_namespace = 'SparcISA' - cxx_class = 'DTB' - + cxx_class = 'SparcISA::DTB' size = 64 class SparcITB(SparcTLB): type = 'SparcITB' - cxx_namespace = 'SparcISA' - cxx_class = 'ITB' - + cxx_class = 'SparcISA::ITB' size = 64 diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index e201cef95..9c189d164 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -546,7 +546,7 @@ void SparcFaultBase::invoke(ThreadContext * tc) doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, 2); } else if (level == Hyperprivileged || - level == Privileged && trapType() >= 384) { + (level == Privileged && trapType() >= 384)) { doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, trapType()); } else { diff --git a/src/arch/sparc/floatregfile.cc b/src/arch/sparc/floatregfile.cc index e1b5ea7c8..2d1af2218 100644 --- a/src/arch/sparc/floatregfile.cc +++ b/src/arch/sparc/floatregfile.cc @@ -41,20 +41,6 @@ using namespace std; class Checkpoint; -string SparcISA::getFloatRegName(RegIndex index) -{ - static std::string floatRegName[NumFloatRegs] = - {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", - "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", - "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", - "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", - "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63"}; - return floatRegName[index]; -} - void FloatRegFile::clear() { memset(regSpace, 0, sizeof(regSpace)); @@ -75,7 +61,8 @@ FloatReg FloatRegFile::readReg(int floatReg, int width) result32 = htog(result32); memcpy(&fresult32, &result32, sizeof(result32)); result = fresult32; - DPRINTF(Sparc, "Read FP32 register %d = [%f]0x%x\n", floatReg, result, result32); + DPRINTF(FloatRegs, "Read FP32 register %d = [%f]0x%x\n", + floatReg, result, result32); break; case DoubleWidth: uint64_t result64; @@ -84,7 +71,8 @@ FloatReg FloatRegFile::readReg(int floatReg, int width) result64 = htog(result64); memcpy(&fresult64, &result64, sizeof(result64)); result = fresult64; - DPRINTF(Sparc, "Read FP64 register %d = [%f]0x%x\n", floatReg, result, result64); + DPRINTF(FloatRegs, "Read FP64 register %d = [%f]0x%x\n", + floatReg, result, result64); break; case QuadWidth: panic("Quad width FP not implemented."); @@ -107,13 +95,15 @@ FloatRegBits FloatRegFile::readRegBits(int floatReg, int width) uint32_t result32; memcpy(&result32, regSpace + 4 * floatReg, sizeof(result32)); result = htog(result32); - DPRINTF(Sparc, "Read FP32 bits register %d = 0x%x\n", floatReg, result); + DPRINTF(FloatRegs, "Read FP32 bits register %d = 0x%x\n", + floatReg, result); break; case DoubleWidth: uint64_t result64; memcpy(&result64, regSpace + 4 * floatReg, sizeof(result64)); result = htog(result64); - DPRINTF(Sparc, "Read FP64 bits register %d = 0x%x\n", floatReg, result); + DPRINTF(FloatRegs, "Read FP64 bits register %d = 0x%x\n", + floatReg, result); break; case QuadWidth: panic("Quad width FP not implemented."); @@ -141,14 +131,16 @@ Fault FloatRegFile::setReg(int floatReg, const FloatReg &val, int width) memcpy(&result32, &fresult32, sizeof(result32)); result32 = gtoh(result32); memcpy(regSpace + 4 * floatReg, &result32, sizeof(result32)); - DPRINTF(Sparc, "Write FP64 register %d = 0x%x\n", floatReg, result32); + DPRINTF(FloatRegs, "Write FP64 register %d = 0x%x\n", + floatReg, result32); break; case DoubleWidth: fresult64 = val; memcpy(&result64, &fresult64, sizeof(result64)); result64 = gtoh(result64); memcpy(regSpace + 4 * floatReg, &result64, sizeof(result64)); - DPRINTF(Sparc, "Write FP64 register %d = 0x%x\n", floatReg, result64); + DPRINTF(FloatRegs, "Write FP64 register %d = 0x%x\n", + floatReg, result64); break; case QuadWidth: panic("Quad width FP not implemented."); @@ -171,12 +163,14 @@ Fault FloatRegFile::setRegBits(int floatReg, const FloatRegBits &val, int width) case SingleWidth: result32 = gtoh((uint32_t)val); memcpy(regSpace + 4 * floatReg, &result32, sizeof(result32)); - DPRINTF(Sparc, "Write FP64 bits register %d = 0x%x\n", floatReg, result32); + DPRINTF(FloatRegs, "Write FP64 bits register %d = 0x%x\n", + floatReg, result32); break; case DoubleWidth: result64 = gtoh((uint64_t)val); memcpy(regSpace + 4 * floatReg, &result64, sizeof(result64)); - DPRINTF(Sparc, "Write FP64 bits register %d = 0x%x\n", floatReg, result64); + DPRINTF(FloatRegs, "Write FP64 bits register %d = 0x%x\n", + floatReg, result64); break; case QuadWidth: panic("Quad width FP not implemented."); diff --git a/src/arch/sparc/floatregfile.hh b/src/arch/sparc/floatregfile.hh index 72803a5e0..265e71b4a 100644 --- a/src/arch/sparc/floatregfile.hh +++ b/src/arch/sparc/floatregfile.hh @@ -42,8 +42,6 @@ class Checkpoint; namespace SparcISA { - std::string getFloatRegName(RegIndex); - const int NumFloatArchRegs = 64; const int NumFloatRegs = 64; diff --git a/src/cpu/o3/mips/thread_context.cc b/src/arch/sparc/interrupts.cc index 0061a2a63..96d61e559 100755..100644 --- a/src/cpu/o3/mips/thread_context.cc +++ b/src/arch/sparc/interrupts.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,12 +25,13 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim - * Korey Sewell + * Authors: Gabe Black */ -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" - -template class O3ThreadContext<MipsSimpleImpl>; - +#include "arch/sparc/interrupts.hh" + +SparcISA::Interrupts * +SparcInterruptsParams::create() +{ + return new SparcISA::Interrupts(this); +} diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh index 4ad3385fb..ec930e2b0 100644 --- a/src/arch/sparc/interrupts.hh +++ b/src/arch/sparc/interrupts.hh @@ -35,25 +35,43 @@ #include "arch/sparc/faults.hh" #include "arch/sparc/isa_traits.hh" #include "cpu/thread_context.hh" +#include "params/SparcInterrupts.hh" +#include "sim/sim_object.hh" namespace SparcISA { -class Interrupts +class Interrupts : public SimObject { - private: + BaseCPU * cpu; uint64_t interrupts[NumInterruptTypes]; uint64_t intStatus; public: - Interrupts() + + void + setCPU(BaseCPU * _cpu) + { + cpu = _cpu; + } + + typedef SparcInterruptsParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + Interrupts(Params * p) : SimObject(p), cpu(NULL) { - clear_all(); + clearAll(); } - int InterruptLevel(uint64_t softint) + int + InterruptLevel(uint64_t softint) { if (softint & 0x10000 || softint & 0x1) return 14; @@ -66,7 +84,8 @@ class Interrupts return 0; } - void post(int int_num, int index) + void + post(int int_num, int index) { DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); assert(int_num >= 0 && int_num < NumInterruptTypes); @@ -76,7 +95,8 @@ class Interrupts intStatus |= ULL(1) << int_num; } - void clear(int int_num, int index) + void + clear(int int_num, int index) { DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); assert(int_num >= 0 && int_num < NumInterruptTypes); @@ -87,7 +107,8 @@ class Interrupts intStatus &= ~(ULL(1) << int_num); } - void clear_all() + void + clearAll() { for (int i = 0; i < NumInterruptTypes; ++i) { interrupts[i] = 0; @@ -95,12 +116,14 @@ class Interrupts intStatus = 0; } - bool check_interrupts(ThreadContext * tc) const + bool + checkInterrupts(ThreadContext *tc) const { return intStatus; } - Fault getInterrupt(ThreadContext * tc) + Fault + getInterrupt(ThreadContext *tc) { int hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); int pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); @@ -143,8 +166,8 @@ class Interrupts return new DevMondo; } if (interrupts[IT_SOFT_INT]) { - return new - InterruptLevelN(InterruptLevel(interrupts[IT_SOFT_INT])); + int level = InterruptLevel(interrupts[IT_SOFT_INT]); + return new InterruptLevelN(level); } if (interrupts[IT_RES_ERROR]) { @@ -155,24 +178,28 @@ class Interrupts return NoFault; } - void updateIntrInfo(ThreadContext * tc) + void + updateIntrInfo(ThreadContext *tc) { } - uint64_t get_vec(int int_num) + uint64_t + get_vec(int int_num) { assert(int_num >= 0 && int_num < NumInterruptTypes); return interrupts[int_num]; } - void serialize(std::ostream &os) + void + serialize(std::ostream &os) { SERIALIZE_ARRAY(interrupts,NumInterruptTypes); SERIALIZE_SCALAR(intStatus); } - void unserialize(Checkpoint *cp, const std::string §ion) + void + unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_ARRAY(interrupts,NumInterruptTypes); UNSERIALIZE_SCALAR(intStatus); diff --git a/src/arch/sparc/intregfile.cc b/src/arch/sparc/intregfile.cc index 39a613a0d..54c30d1cc 100644 --- a/src/arch/sparc/intregfile.cc +++ b/src/arch/sparc/intregfile.cc @@ -41,138 +41,40 @@ using namespace std; class Checkpoint; -string SparcISA::getIntRegName(RegIndex index) -{ - static std::string intRegName[NumIntArchRegs] = - {"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7"}; - return intRegName[index]; -} - -int IntRegFile::flattenIndex(int reg) -{ - int flatIndex = offset[reg >> FrameOffsetBits] - | (reg & FrameOffsetMask); - DPRINTF(Sparc, "Flattened index %d into %d.\n", reg, flatIndex); - return flatIndex; -} - void IntRegFile::clear() { - int x; - for (x = 0; x < MaxGL; x++) - memset(regGlobals[x], 0, sizeof(IntReg) * RegsPerFrame); - for(int x = 0; x < 2 * NWindows; x++) - memset(regSegments[x], 0, sizeof(IntReg) * RegsPerFrame); memset(regs, 0, sizeof(IntReg) * NumIntRegs); } IntRegFile::IntRegFile() { - offset[Globals] = 0; - regView[Globals] = regGlobals[0]; - setCWP(0); clear(); } IntReg IntRegFile::readReg(int intReg) { - DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, regs[intReg]); + DPRINTF(IntRegs, "Read register %d = 0x%x\n", intReg, regs[intReg]); return regs[intReg]; - /* XXX Currently not used. When used again regView/offset need to be - * serialized! - IntReg val; - if(intReg < NumIntArchRegs) - val = regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask]; - else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) - val = microRegs[intReg]; - else - panic("Tried to read non-existant integer register %d, %d\n", - NumIntArchRegs + NumMicroIntRegs + intReg, intReg); - - DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val); - return val; - */ } void IntRegFile::setReg(int intReg, const IntReg &val) { if(intReg) { - DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); + DPRINTF(IntRegs, "Wrote register %d = 0x%x\n", intReg, val); regs[intReg] = val; } return; - /* XXX Currently not used. When used again regView/offset need to be - * serialized! - if(intReg) - { - DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); - if(intReg < NumIntArchRegs) - regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val; - else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) - microRegs[intReg] = val; - else - panic("Tried to set non-existant integer register\n"); - } */ -} - -//This doesn't effect the actual CWP register. -//It's purpose is to adjust the view of the register file -//to what it would be if CWP = cwp. -void IntRegFile::setCWP(int cwp) -{ - int index = ((NWindows - cwp) % NWindows) * 2; - if (index < 0) - panic("Index less than 0. cwp=%d nwin=%d\n", cwp, NWindows); - offset[Outputs] = FrameOffset + (index * RegsPerFrame); - offset[Locals] = FrameOffset + ((index+1) * RegsPerFrame); - offset[Inputs] = FrameOffset + - (((index+2) % (NWindows * 2)) * RegsPerFrame); - regView[Outputs] = regSegments[index]; - regView[Locals] = regSegments[index+1]; - regView[Inputs] = regSegments[(index+2) % (NWindows * 2)]; - - DPRINTF(Sparc, "Changed the CWP value to %d\n", cwp); -} - -void IntRegFile::setGlobals(int gl) -{ - DPRINTF(Sparc, "Now using %d globals\n", gl); - - regView[Globals] = regGlobals[gl]; - offset[Globals] = RegGlobalOffset + gl * RegsPerFrame; - - if (regView[Globals] == regView[Inputs] || - regView[Globals] == regView[Locals] || - regView[Globals] == regView[Outputs] ) - panic("Two register arrays set to the same thing!\n"); } void IntRegFile::serialize(std::ostream &os) { SERIALIZE_ARRAY(regs, NumIntRegs); SERIALIZE_ARRAY(microRegs, NumMicroIntRegs); - - /* the below doesn't seem needed unless gabe makes regview work*/ - unsigned int x; - for(x = 0; x < MaxGL; x++) - SERIALIZE_ARRAY(regGlobals[x], RegsPerFrame); - for(x = 0; x < 2 * NWindows; x++) - SERIALIZE_ARRAY(regSegments[x], RegsPerFrame); } void IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_ARRAY(regs, NumIntRegs); UNSERIALIZE_ARRAY(microRegs, NumMicroIntRegs); - - /* the below doesn't seem needed unless gabe makes regview work*/ - unsigned int x; - for(x = 0; x < MaxGL; x++) - UNSERIALIZE_ARRAY(regGlobals[x], RegsPerFrame); - for(unsigned int x = 0; x < 2 * NWindows; x++) - UNSERIALIZE_ARRAY(regSegments[x], RegsPerFrame); } diff --git a/src/arch/sparc/intregfile.hh b/src/arch/sparc/intregfile.hh index 83ef1d17b..f669f6b0d 100644 --- a/src/arch/sparc/intregfile.hh +++ b/src/arch/sparc/intregfile.hh @@ -42,53 +42,17 @@ class Checkpoint; namespace SparcISA { - class RegFile; - - //This function translates integer register file indices into names - std::string getIntRegName(RegIndex); - const int NumIntArchRegs = 32; const int NumIntRegs = (MaxGL + 1) * 8 + NWindows * 16 + NumMicroIntRegs; class IntRegFile { - private: - friend class RegFile; protected: - //The number of bits needed to index into each 8 register frame - static const int FrameOffsetBits = 3; - //The number of bits to choose between the 4 sets of 8 registers - static const int FrameNumBits = 2; - - //The number of registers per "frame" (8) - static const int RegsPerFrame = 1 << FrameOffsetBits; - //A mask to get the frame number - static const uint64_t FrameNumMask = - (FrameNumBits == sizeof(int)) ? - (unsigned int)(-1) : - (1 << FrameNumBits) - 1; - static const uint64_t FrameOffsetMask = - (FrameOffsetBits == sizeof(int)) ? - (unsigned int)(-1) : - (1 << FrameOffsetBits) - 1; - - IntReg regGlobals[MaxGL+1][RegsPerFrame]; - IntReg regSegments[2 * NWindows][RegsPerFrame]; IntReg microRegs[NumMicroIntRegs]; IntReg regs[NumIntRegs]; - enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames}; - - IntReg * regView[NumFrames]; - - static const int RegGlobalOffset = 0; - static const int FrameOffset = (MaxGL + 1) * RegsPerFrame; - int offset[NumFrames]; - public: - int flattenIndex(int reg); - void clear(); IntRegFile(); @@ -100,14 +64,6 @@ namespace SparcISA void serialize(std::ostream &os); void unserialize(Checkpoint *cp, const std::string §ion); - - protected: - //This doesn't effect the actual CWP register. - //It's purpose is to adjust the view of the register file - //to what it would be if CWP = cwp. - void setCWP(int cwp); - - void setGlobals(int gl); }; } diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index c35b231ff..e34ca033f 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1231,16 +1231,14 @@ decode OP default Unknown::unknown() 0x23: Load::lddf({{Frd.udw = Mem.udw;}}); 0x24: Store::stf({{Mem.uw = Frds.uw;}}); 0x25: decode RD { - 0x0: Store::stfsr({{fault = checkFpEnableFault(xc); - if (fault) - return fault; - Mem.uw = Fsr<31:0>; - Fsr = insertBits(Fsr,16,14,0);}}); - 0x1: Store::stxfsr({{fault = checkFpEnableFault(xc); - if (fault) - return fault; - Mem.udw = Fsr; - Fsr = insertBits(Fsr,16,14,0);}}); + 0x0: StoreFsr::stfsr({{fault = checkFpEnableFault(xc); + if (fault) + return fault; + Mem.uw = Fsr<31:0>;}}); + 0x1: StoreFsr::stxfsr({{fault = checkFpEnableFault(xc); + if (fault) + return fault; + Mem.udw = Fsr;}}); default: FailUnimpl::stfsrOther(); } 0x26: stqf({{fault = new FpDisabled;}}); diff --git a/src/arch/sparc/isa/formats/mem/basicmem.isa b/src/arch/sparc/isa/formats/mem/basicmem.isa index e3c043cf3..c7bb3e435 100644 --- a/src/arch/sparc/isa/formats/mem/basicmem.isa +++ b/src/arch/sparc/isa/formats/mem/basicmem.isa @@ -108,6 +108,16 @@ def format Store(code, *opt_flags) {{ StoreFuncs, '', name, Name, 0, opt_flags) }}; +def format StoreFsr(code, *opt_flags) {{ + code = filterDoubles(code) + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, + StoreFuncs, '', name, Name, 0, opt_flags, + 'Fsr = insertBits(Fsr,16,14,0);') +}}; + def format TwinLoad(code, *opt_flags) {{ (header_output, decoder_output, diff --git a/src/arch/sparc/isa/formats/mem/swap.isa b/src/arch/sparc/isa/formats/mem/swap.isa index 2ebe9aa15..046f89822 100644 --- a/src/arch/sparc/isa/formats/mem/swap.isa +++ b/src/arch/sparc/isa/formats/mem/swap.isa @@ -133,6 +133,7 @@ let {{ def format Swap(code, postacc_code, mem_flags, *opt_flags) {{ mem_flags = makeList(mem_flags) + mem_flags = [ 'Request::%s' % flag for flag in mem_flags ] flags = string.join(mem_flags, '|') (header_output, @@ -144,6 +145,7 @@ def format Swap(code, postacc_code, mem_flags, *opt_flags) {{ def format SwapAlt(code, postacc_code, mem_flags, *opt_flags) {{ mem_flags = makeList(mem_flags) + mem_flags = [ 'Request::%s' % flag for flag in mem_flags ] mem_flags.append("EXT_ASI") flags = string.join(mem_flags, '|') (header_output, @@ -175,6 +177,7 @@ let {{ def format CasAlt(code, postacc_code, mem_flags, *opt_flags) {{ mem_flags = makeList(mem_flags) + mem_flags = [ 'Request::%s' % flag for flag in mem_flags ] mem_flags.append("EXT_ASI") flags = string.join(mem_flags, '|') (header_output, diff --git a/src/arch/sparc/isa/formats/mem/util.isa b/src/arch/sparc/isa/formats/mem/util.isa index 38cde9a50..31efb9cf6 100644 --- a/src/arch/sparc/isa/formats/mem/util.isa +++ b/src/arch/sparc/isa/formats/mem/util.isa @@ -264,11 +264,6 @@ def template StoreInitiateAcc {{ fault = xc->write((%(mem_acc_type)s%(mem_acc_size)s_t)Mem, EA, %(asi_val)s, 0); } - if(fault == NoFault) - { - //Write the resulting state to the execution context - %(op_wb)s; - } return fault; } }}; @@ -277,6 +272,15 @@ def template StoreCompleteAcc {{ Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const { + Fault fault = NoFault; + %(op_decl)s; + + %(op_rd)s; + %(postacc_code)s; + if (fault == NoFault) + { + %(op_wb)s; + } return NoFault; } }}; @@ -314,10 +318,11 @@ let {{ # are split into ones that are available in priv and hpriv, and # those that are only available in hpriv AlternateASIPrivFaultCheck = ''' - if(!bits(Pstate,2,2) && !bits(Hpstate,2,2) && !AsiIsUnPriv((ASI)EXT_ASI) || - !bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI)) - fault = new PrivilegedAction; - else if(AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2)) + if ((!bits(Pstate,2,2) && !bits(Hpstate,2,2) && + !AsiIsUnPriv((ASI)EXT_ASI)) || + (!bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI))) + fault = new PrivilegedAction; + else if (AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2)) fault = new PrivilegedAction; ''' diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 133817eb5..501f2f990 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -66,18 +66,14 @@ namespace SparcISA }; // semantically meaningful register indices - const int ZeroReg = 0; // architecturally meaningful + const int ZeroReg = 0; // architecturally meaningful // the rest of these depend on the ABI - const int StackPointerReg = 14; const int ReturnAddressReg = 31; // post call, precall is 15 - const int ReturnValueReg = 8; // Post return, 24 is pre-return. + const int StackPointerReg = 14; const int FramePointerReg = 30; - const int ArgumentReg[] = {8, 9, 10, 11, 12, 13}; - const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); - // Some OS syscall use a second register (o1) to return a second value - const int SyscallPseudoReturnReg = ArgumentReg[1]; + const int SyscallPseudoReturnReg = 9; //8K. This value is implmentation specific; and should probably //be somewhere else. diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc index 1211d5f65..102e5af3b 100644 --- a/src/arch/sparc/linux/linux.cc +++ b/src/arch/sparc/linux/linux.cc @@ -34,34 +34,34 @@ // open(2) flags translation table OpenFlagTransTable SparcLinux::openFlagTable[] = { #ifdef _MSC_VER - { SparcLinux::TGT_O_RDONLY, _O_RDONLY }, - { SparcLinux::TGT_O_WRONLY, _O_WRONLY }, - { SparcLinux::TGT_O_RDWR, _O_RDWR }, - { SparcLinux::TGT_O_APPEND, _O_APPEND }, - { SparcLinux::TGT_O_CREAT, _O_CREAT }, - { SparcLinux::TGT_O_TRUNC, _O_TRUNC }, - { SparcLinux::TGT_O_EXCL, _O_EXCL }, + { SparcLinux::TGT_O_RDONLY, _O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, _O_WRONLY }, + { SparcLinux::TGT_O_RDWR, _O_RDWR }, + { SparcLinux::TGT_O_APPEND, _O_APPEND }, + { SparcLinux::TGT_O_CREAT, _O_CREAT }, + { SparcLinux::TGT_O_TRUNC, _O_TRUNC }, + { SparcLinux::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, + { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY }, + { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { SparcLinux::TGT_O_SYNC, _O_SYNC }, + { SparcLinux::TGT_O_SYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { SparcLinux::TGT_O_RDONLY, O_RDONLY }, - { SparcLinux::TGT_O_WRONLY, O_WRONLY }, - { SparcLinux::TGT_O_RDWR, O_RDWR }, - { SparcLinux::TGT_O_APPEND, O_APPEND }, - { SparcLinux::TGT_O_CREAT, O_CREAT }, - { SparcLinux::TGT_O_TRUNC, O_TRUNC }, - { SparcLinux::TGT_O_EXCL, O_EXCL }, - { SparcLinux::TGT_O_NONBLOCK, O_NONBLOCK }, - { SparcLinux::TGT_O_NOCTTY, O_NOCTTY }, + { SparcLinux::TGT_O_RDONLY, O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, O_WRONLY }, + { SparcLinux::TGT_O_RDWR, O_RDWR }, + { SparcLinux::TGT_O_APPEND, O_APPEND }, + { SparcLinux::TGT_O_CREAT, O_CREAT }, + { SparcLinux::TGT_O_TRUNC, O_TRUNC }, + { SparcLinux::TGT_O_EXCL, O_EXCL }, + { SparcLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcLinux::TGT_O_NOCTTY, O_NOCTTY }, #ifdef O_SYNC - { SparcLinux::TGT_O_SYNC, O_SYNC }, + { SparcLinux::TGT_O_SYNC, O_SYNC }, #endif #endif /* _MSC_VER */ }; diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh index f396eb5cd..b1dc691ce 100644 --- a/src/arch/sparc/linux/linux.hh +++ b/src/arch/sparc/linux/linux.hh @@ -58,21 +58,21 @@ class SparcLinux : public Linux static OpenFlagTransTable openFlagTable[]; - static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 0x00004000; //!< O_NONBLOCK - static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND - static const int TGT_O_CREAT = 0x00000200; //!< O_CREAT - static const int TGT_O_TRUNC = 0x00000400; //!< O_TRUNC - static const int TGT_O_EXCL = 0x00000800; //!< O_EXCL - static const int TGT_O_NOCTTY = 0x00008000; //!< O_NOCTTY - static const int TGT_O_SYNC = 0x00002000; //!< O_SYNC -// static const int TGT_O_DRD = 0x00010000; //!< O_DRD -// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO -// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE -// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC -// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000200; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000400; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000800; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00008000; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00002000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC static const int NUM_OPEN_FLAGS; diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc index f4ec28c00..2078c1dce 100644 --- a/src/arch/sparc/linux/process.cc +++ b/src/arch/sparc/linux/process.cc @@ -47,7 +47,7 @@ using namespace SparcISA; SyscallDesc* SparcLinuxProcess::getDesc(int callnum) { - if (callnum < 0 || callnum > Num_Syscall_Descs) + if (callnum < 0 || callnum >= Num_Syscall_Descs) return NULL; return &syscallDescs[callnum]; } @@ -55,7 +55,7 @@ SparcLinuxProcess::getDesc(int callnum) SyscallDesc* SparcLinuxProcess::getDesc32(int callnum) { - if (callnum < 0 || callnum > Num_Syscall32_Descs) + if (callnum < 0 || callnum >= Num_Syscall32_Descs) return NULL; return &syscall32Descs[callnum]; } diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh index 06eee9235..a76b4b3b2 100644 --- a/src/arch/sparc/linux/process.hh +++ b/src/arch/sparc/linux/process.hh @@ -32,7 +32,6 @@ #define __SPARC_LINUX_PROCESS_HH__ #include "arch/sparc/linux/linux.hh" -#include "arch/sparc/syscallreturn.hh" #include "arch/sparc/process.hh" #include "sim/process.hh" diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc index 03c8bafe2..8496fca13 100644 --- a/src/arch/sparc/linux/syscalls.cc +++ b/src/arch/sparc/linux/syscalls.cc @@ -29,7 +29,6 @@ */ #include "arch/sparc/linux/process.hh" -#include "arch/sparc/syscallreturn.hh" #include "sim/syscall_emul.hh" class LiveProcess; @@ -42,7 +41,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -60,9 +59,9 @@ SyscallReturn getresuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { const IntReg id = htog(100); - Addr ruid = tc->getSyscallArg(0); - Addr euid = tc->getSyscallArg(1); - Addr suid = tc->getSyscallArg(2); + Addr ruid = p->getSyscallArg(tc, 0); + Addr euid = p->getSyscallArg(tc, 1); + Addr suid = p->getSyscallArg(tc, 2); //Handle the EFAULT case //Set the ruid if(ruid) @@ -106,7 +105,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", unimplementedFunc), /* 16 */ SyscallDesc("lchown", unimplementedFunc), //32 bit - /* 17 */ SyscallDesc("brk", obreakFunc), + /* 17 */ SyscallDesc("brk", brkFunc), /* 18 */ SyscallDesc("perfctr", unimplementedFunc), //32 bit /* 19 */ SyscallDesc("lseek", lseekFunc), //32 bit /* 20 */ SyscallDesc("getpid", getpidFunc), @@ -147,7 +146,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 55 */ SyscallDesc("reboot", unimplementedFunc), //32 bit /* 56 */ SyscallDesc("mmap2", unimplementedFunc), //32 bit /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), //32 bit + /* 58 */ SyscallDesc("readlink", readlinkFunc), //32 bit /* 59 */ SyscallDesc("execve", unimplementedFunc), //32 bit /* 60 */ SyscallDesc("umask", unimplementedFunc), //32 bit /* 61 */ SyscallDesc("chroot", unimplementedFunc), @@ -208,7 +207,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc), //32 bit /* 117 */ SyscallDesc("getrusage", unimplementedFunc), //32 bit /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("getcwd", unimplementedFunc), + /* 119 */ SyscallDesc("getcwd", getcwdFunc), /* 120 */ SyscallDesc("readv", unimplementedFunc), /* 121 */ SyscallDesc("writev", unimplementedFunc), /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), //32 bit @@ -225,7 +224,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 133 */ SyscallDesc("sendto", unimplementedFunc), /* 134 */ SyscallDesc("shutdown", unimplementedFunc), /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), //32 bit + /* 136 */ SyscallDesc("mkdir", mkdirFunc), //32 bit /* 137 */ SyscallDesc("rmdir", unimplementedFunc), /* 138 */ SyscallDesc("utimes", unimplementedFunc), //32 bit /* 139 */ SyscallDesc("stat64", unimplementedFunc), @@ -339,7 +338,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), //32 bit /* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), //32 bit /* 249 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 250 */ SyscallDesc("mremap", unimplementedFunc), //32 bit + /* 250 */ SyscallDesc("mremap", mremapFunc<Sparc32Linux>), //32 bit /* 251 */ SyscallDesc("_sysctl", unimplementedFunc), //32 bit /* 252 */ SyscallDesc("getsid", unimplementedFunc), //32 bit /* 253 */ SyscallDesc("fdatasync", unimplementedFunc), @@ -409,7 +408,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), /* 16 */ SyscallDesc("lchown", unimplementedFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), + /* 17 */ SyscallDesc("brk", brkFunc), /* 18 */ SyscallDesc("perfctr", unimplementedFunc), /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getpid", getpidFunc), @@ -450,7 +449,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 55 */ SyscallDesc("reboot", unimplementedFunc), /* 56 */ SyscallDesc("mmap2", unimplementedFunc), /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", readlinkFunc), /* 59 */ SyscallDesc("execve", unimplementedFunc), /* 60 */ SyscallDesc("umask", unimplementedFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), @@ -528,7 +527,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 133 */ SyscallDesc("sendto", unimplementedFunc), /* 134 */ SyscallDesc("shutdown", unimplementedFunc), /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", mkdirFunc), /* 137 */ SyscallDesc("rmdir", unimplementedFunc), /* 138 */ SyscallDesc("utimes", unimplementedFunc), /* 139 */ SyscallDesc("stat64", unimplementedFunc), @@ -642,7 +641,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), /* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), /* 249 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 250 */ SyscallDesc("mremap", unimplementedFunc), + /* 250 */ SyscallDesc("mremap", mremapFunc<SparcLinux>), /* 251 */ SyscallDesc("_sysctl", unimplementedFunc), /* 252 */ SyscallDesc("getsid", unimplementedFunc), /* 253 */ SyscallDesc("fdatasync", unimplementedFunc), diff --git a/src/arch/sparc/microcode_rom.hh b/src/arch/sparc/microcode_rom.hh new file mode 100644 index 000000000..e46000dcc --- /dev/null +++ b/src/arch/sparc/microcode_rom.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_SPARC_MICROCODE_ROM_HH__ +#define __ARCH_SPARC_MICROCODE_ROM_HH__ + +#include "sim/microcode_rom.hh" + +namespace SparcISA +{ + using ::MicrocodeRom; +} + +#endif // __ARCH_SPARC_MICROCODE_ROM_HH__ diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index 7b9c73433..38eba3862 100644 --- a/src/arch/sparc/miscregfile.cc +++ b/src/arch/sparc/miscregfile.cc @@ -42,27 +42,6 @@ using namespace std; class Checkpoint; -//These functions map register indices to names -string SparcISA::getMiscRegName(RegIndex index) -{ - static::string miscRegName[NumMiscRegs] = - {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic", - "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr", - "stick", "stick_cmpr", - "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl", - "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin", - "wstate",*/ "gl", - "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg", - "hstick_cmpr", - "fsr", "prictx", "secctx", "partId", "lsuCtrlReg", - "scratch0", "scratch1", "scratch2", "scratch3", "scratch4", - "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail", - "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail", - "nresErrorHead", "nresErrorTail", "TlbData" }; - - return miscRegName[index]; -} - enum RegMask { PSTATE_MASK = (((1 << 4) - 1) << 1) | (((1 << 4) - 1) << 6) | (1 << 12) @@ -227,7 +206,7 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg) /** Floating Point Status Register */ case MISCREG_FSR: - DPRINTF(Sparc, "FSR read as: %#x\n", fsr); + DPRINTF(MiscRegs, "FSR read as: %#x\n", fsr); return fsr; case MISCREG_MMU_P_CONTEXT: @@ -322,12 +301,13 @@ MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc) return readFSReg(miscReg, tc); #else case MISCREG_HPSTATE: - //HPSTATE is special because because sometimes in privilege checks for instructions - //it will read HPSTATE to make sure the priv. level is ok - //So, we'll just have to tell it it isn't, instead of panicing. + //HPSTATE is special because because sometimes in privilege + //checks for instructions it will read HPSTATE to make sure + //the priv. level is ok So, we'll just have to tell it it + //isn't, instead of panicing. return 0; - panic("Accessing Fullsystem register %s in SE mode\n",getMiscRegName(miscReg)); + panic("Accessing Fullsystem register %d in SE mode\n", miscReg); #endif } @@ -444,7 +424,7 @@ void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val) /** Floating Point Status Register */ case MISCREG_FSR: fsr = val; - DPRINTF(Sparc, "FSR written with: %#x\n", fsr); + DPRINTF(MiscRegs, "FSR written with: %#x\n", fsr); break; case MISCREG_MMU_P_CONTEXT: @@ -540,20 +520,17 @@ void MiscRegFile::setReg(int miscReg, tl = val; #if FULL_SYSTEM if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv)) - tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0); + tc->getCpuPtr()->postInterrupt(IT_TRAP_LEVEL_ZERO, 0); else - tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0); + tc->getCpuPtr()->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0); #endif return; case MISCREG_CWP: new_val = val >= NWindows ? NWindows - 1 : val; if (val >= NWindows) new_val = NWindows - 1; - - tc->changeRegFileContext(CONTEXT_CWP, new_val); break; case MISCREG_GL: - tc->changeRegFileContext(CONTEXT_GLOBALS, val); break; case MISCREG_PIL: case MISCREG_SOFTINT: @@ -584,13 +561,15 @@ void MiscRegFile::setReg(int miscReg, //HPSTATE is special because normal trap processing saves HPSTATE when //it goes into a trap, and restores it when it returns. return; - panic("Accessing Fullsystem register %s to %#x in SE mode\n", getMiscRegName(miscReg), val); + panic("Accessing Fullsystem register %d to %#x in SE mode\n", + miscReg, val); #endif } setRegNoEffect(miscReg, new_val); } -void MiscRegFile::serialize(std::ostream & os) +void +MiscRegFile::serialize(EventManager *em, std::ostream &os) { SERIALIZE_SCALAR(asi); SERIALIZE_SCALAR(tick); @@ -667,7 +646,9 @@ void MiscRegFile::serialize(std::ostream & os) #endif } -void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section) +void +MiscRegFile::unserialize(EventManager *em, Checkpoint *cp, + const string §ion) { UNSERIALIZE_SCALAR(asi); UNSERIALIZE_SCALAR(tick); @@ -726,15 +707,15 @@ void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section) if (tick_cmp) { tickCompare = new TickCompareEvent(this, tc); - tickCompare->schedule(tick_cmp); + em->schedule(tickCompare, tick_cmp); } if (stick_cmp) { sTickCompare = new STickCompareEvent(this, tc); - sTickCompare->schedule(stick_cmp); + em->schedule(sTickCompare, stick_cmp); } if (hstick_cmp) { hSTickCompare = new HSTickCompareEvent(this, tc); - hSTickCompare->schedule(hstick_cmp); + em->schedule(hSTickCompare, hstick_cmp); } } } diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh index 3e17779a9..9eff7fcac 100644 --- a/src/arch/sparc/miscregfile.hh +++ b/src/arch/sparc/miscregfile.hh @@ -43,9 +43,6 @@ class Checkpoint; namespace SparcISA { - //These functions map register indices to names - std::string getMiscRegName(RegIndex); - enum MiscRegIndex { /** Ancillary State Registers */ @@ -171,50 +168,50 @@ namespace SparcISA private: /* ASR Registers */ - //uint64_t y; // Y (used in obsolete multiplication) - //uint8_t ccr; // Condition Code Register - uint8_t asi; // Address Space Identifier - uint64_t tick; // Hardware clock-tick counter - uint8_t fprs; // Floating-Point Register State - uint64_t gsr; // General Status Register + //uint64_t y; // Y (used in obsolete multiplication) + //uint8_t ccr; // Condition Code Register + uint8_t asi; // Address Space Identifier + uint64_t tick; // Hardware clock-tick counter + uint8_t fprs; // Floating-Point Register State + uint64_t gsr; // General Status Register uint64_t softint; - uint64_t tick_cmpr; // Hardware tick compare registers - uint64_t stick; // Hardware clock-tick counter - uint64_t stick_cmpr; // Hardware tick compare registers + uint64_t tick_cmpr; // Hardware tick compare registers + uint64_t stick; // Hardware clock-tick counter + uint64_t stick_cmpr; // Hardware tick compare registers /* Privileged Registers */ - uint64_t tpc[MaxTL]; // Trap Program Counter (value from + uint64_t tpc[MaxTL]; // Trap Program Counter (value from // previous trap level) - uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from + uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from // previous trap level) - uint64_t tstate[MaxTL]; // Trap State - uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured + uint64_t tstate[MaxTL]; // Trap State + uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured // on the previous level) - uint64_t tba; // Trap Base Address - - uint16_t pstate; // Process State Register - uint8_t tl; // Trap Level - uint8_t pil; // Process Interrupt Register - uint8_t cwp; // Current Window Pointer - //uint8_t cansave; // Savable windows - //uint8_t canrestore; // Restorable windows - //uint8_t cleanwin; // Clean windows - //uint8_t otherwin; // Other windows - //uint8_t wstate; // Window State + uint64_t tba; // Trap Base Address + + uint16_t pstate; // Process State Register + uint8_t tl; // Trap Level + uint8_t pil; // Process Interrupt Register + uint8_t cwp; // Current Window Pointer + //uint8_t cansave; // Savable windows + //uint8_t canrestore; // Restorable windows + //uint8_t cleanwin; // Clean windows + //uint8_t otherwin; // Other windows + //uint8_t wstate; // Window State uint8_t gl; // Global level register /** Hyperprivileged Registers */ - uint64_t hpstate; // Hyperprivileged State Register + uint64_t hpstate; // Hyperprivileged State Register uint64_t htstate[MaxTL];// Hyperprivileged Trap State Register uint64_t hintp; - uint64_t htba; // Hyperprivileged Trap Base Address register - uint64_t hstick_cmpr; // Hardware tick compare registers + uint64_t htba; // Hyperprivileged Trap Base Address register + uint64_t hstick_cmpr; // Hardware tick compare registers uint64_t strandStatusReg;// Per strand status register /** Floating point misc registers. */ - uint64_t fsr; // Floating-Point State Register + uint64_t fsr; // Floating-Point State Register /** MMU Internal Registers */ uint16_t priContext; @@ -288,9 +285,10 @@ namespace SparcISA return priContext | (uint32_t)partId << 13; } - void serialize(std::ostream & os); + void serialize(EventManager *em, std::ostream & os); - void unserialize(Checkpoint * cp, const std::string & section); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string & section); void copyMiscRegs(ThreadContext * tc); diff --git a/src/arch/sparc/pagetable.hh b/src/arch/sparc/pagetable.hh index bf7f34b60..cbdabe4c3 100644 --- a/src/arch/sparc/pagetable.hh +++ b/src/arch/sparc/pagetable.hh @@ -31,6 +31,8 @@ #ifndef __ARCH_SPARC_PAGETABLE_HH__ #define __ARCH_SPARC_PAGETABLE_HH__ +#include <cassert> + #include "arch/sparc/isa_traits.hh" #include "base/bitfield.hh" #include "base/misc.hh" @@ -38,8 +40,8 @@ class Checkpoint; -namespace SparcISA -{ +namespace SparcISA { + struct VAddr { VAddr(Addr a) { panic("not implemented yet."); } @@ -54,8 +56,15 @@ class TteTag public: TteTag() : entry(0), populated(false) {} TteTag(uint64_t e) : entry(e), populated(true) {} - const TteTag &operator=(uint64_t e) { populated = true; - entry = e; return *this; } + + const TteTag & + operator=(uint64_t e) + { + populated = true; + entry = e; + return *this; + } + bool valid() const {assert(populated); return !bits(entry,62,62); } Addr va() const {assert(populated); return bits(entry,41,0); } }; @@ -76,13 +85,13 @@ class PageTableEntry uint64_t entry4u; bool populated; - public: - PageTableEntry() : entry(0), type(invalid), populated(false) {} + PageTableEntry() + : entry(0), type(invalid), populated(false) + {} PageTableEntry(uint64_t e, EntryType t = sun4u) : entry(e), type(t), populated(true) - { populate(entry, type); } @@ -113,49 +122,74 @@ class PageTableEntry } } - void clear() + void + clear() { populated = false; } static int pageSizes[6]; - uint64_t operator()() const { assert(populated); return entry4u; } - const PageTableEntry &operator=(uint64_t e) { populated = true; - entry4u = e; return *this; } - - const PageTableEntry &operator=(const PageTableEntry &e) - { populated = true; entry4u = e.entry4u; type = e.type; return *this; } - - bool valid() const { return bits(entry4u,63,63) && populated; } - uint8_t _size() const { assert(populated); - return bits(entry4u, 62,61) | - bits(entry4u, 48,48) << 2; } - Addr size() const { assert(_size() < 6); return pageSizes[_size()]; } - Addr sizeMask() const { assert(_size() < 6); return pageSizes[_size()]-1;} - bool ie() const { return bits(entry4u, 59,59); } - Addr pfn() const { assert(populated); return bits(entry4u,39,13); } - Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);} - bool locked() const { assert(populated); return bits(entry4u,6,6); } - bool cv() const { assert(populated); return bits(entry4u,4,4); } - bool cp() const { assert(populated); return bits(entry4u,5,5); } - bool priv() const { assert(populated); return bits(entry4u,2,2); } - bool writable() const { assert(populated); return bits(entry4u,1,1); } - bool nofault() const { assert(populated); return bits(entry4u,60,60); } - bool sideffect() const { assert(populated); return bits(entry4u,3,3); } - Addr paddrMask() const { assert(populated); - return mbits(entry4u, 39,13) & ~sizeMask(); } + const PageTableEntry & + operator=(uint64_t e) + { + populated = true; + entry4u = e; + return *this; + } + + const PageTableEntry & + operator=(const PageTableEntry &e) + { + populated = true; + entry4u = e.entry4u; + type = e.type; + return *this; + } + + bool valid() const { return bits(entry4u,63,63) && populated; } + + uint8_t + _size() const + { + assert(populated); + return bits(entry4u, 62,61) | bits(entry4u, 48,48) << 2; + } + + Addr size() const { assert(_size() < 6); return pageSizes[_size()]; } + Addr sizeMask() const { return size() - 1; } + bool ie() const { return bits(entry4u, 59,59); } + Addr pfn() const { assert(populated); return bits(entry4u,39,13); } + Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);} + bool locked() const { assert(populated); return bits(entry4u,6,6); } + bool cv() const { assert(populated); return bits(entry4u,4,4); } + bool cp() const { assert(populated); return bits(entry4u,5,5); } + bool priv() const { assert(populated); return bits(entry4u,2,2); } + bool writable() const { assert(populated); return bits(entry4u,1,1); } + bool nofault() const { assert(populated); return bits(entry4u,60,60); } + bool sideffect() const { assert(populated); return bits(entry4u,3,3); } + Addr paddrMask() const { assert(populated); return paddr() & ~sizeMask(); } + + Addr + translate(Addr vaddr) const + { + assert(populated); + Addr mask = sizeMask(); + return (paddr() & ~mask) | (vaddr & mask); + } }; -struct TlbRange { +struct TlbRange +{ Addr va; Addr size; int contextId; int partitionId; bool real; - inline bool operator<(const TlbRange &r2) const + inline bool + operator<(const TlbRange &r2) const { if (real && !r2.real) return true; @@ -178,7 +212,9 @@ struct TlbRange { return true; return false; } - inline bool operator==(const TlbRange &r2) const + + inline bool + operator==(const TlbRange &r2) const { return va == r2.va && size == r2.size && @@ -189,7 +225,11 @@ struct TlbRange { }; -struct TlbEntry { +struct TlbEntry +{ + TlbEntry() + {} + TlbEntry(Addr asn, Addr vaddr, Addr paddr) { uint64_t entry = 0; @@ -215,8 +255,7 @@ struct TlbEntry { valid = true; } - TlbEntry() - {} + TlbRange range; PageTableEntry pte; bool used; @@ -227,13 +266,17 @@ struct TlbEntry { return pte.paddr(); } + void + updateVaddr(Addr new_vaddr) + { + range.va = new_vaddr; + } + void serialize(std::ostream &os); void unserialize(Checkpoint *cp, const std::string §ion); - }; - -}; // namespace SparcISA +} // namespace SparcISA #endif // __ARCH_SPARC_PAGE_TABLE_HH__ diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 6e490e05e..b2b539816 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -46,6 +46,9 @@ using namespace std; using namespace SparcISA; +static const int FirstArgumentReg = 8; +static const int ReturnValueReg = 8; + SparcLiveProcess::SparcLiveProcess(LiveProcessParams * params, ObjectFile *objFile, Addr _StackBias) @@ -112,44 +115,45 @@ SparcLiveProcess::startup() { Process::startup(); + ThreadContext *tc = system->getThreadContext(contextIds[0]); //From the SPARC ABI //Setup default FP state - threadContexts[0]->setMiscRegNoEffect(MISCREG_FSR, 0); + tc->setMiscRegNoEffect(MISCREG_FSR, 0); - threadContexts[0]->setMiscRegNoEffect(MISCREG_TICK, 0); + tc->setMiscRegNoEffect(MISCREG_TICK, 0); /* * Register window management registers */ //No windows contain info from other programs - //threadContexts[0]->setMiscRegNoEffect(MISCREG_OTHERWIN, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0); + //tc->setMiscRegNoEffect(MISCREG_OTHERWIN, 0); + tc->setIntReg(NumIntArchRegs + 6, 0); //There are no windows to pop - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANRESTORE, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0); + //tc->setMiscRegNoEffect(MISCREG_CANRESTORE, 0); + tc->setIntReg(NumIntArchRegs + 4, 0); //All windows are available to save into - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2); - threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2); + //tc->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2); + tc->setIntReg(NumIntArchRegs + 3, NWindows - 2); //All windows are "clean" - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows); - threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows); + //tc->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows); + tc->setIntReg(NumIntArchRegs + 5, NWindows); //Start with register window 0 - threadContexts[0]->setMiscRegNoEffect(MISCREG_CWP, 0); + tc->setMiscRegNoEffect(MISCREG_CWP, 0); //Always use spill and fill traps 0 - //threadContexts[0]->setMiscRegNoEffect(MISCREG_WSTATE, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0); + //tc->setMiscRegNoEffect(MISCREG_WSTATE, 0); + tc->setIntReg(NumIntArchRegs + 7, 0); //Set the trap level to 0 - threadContexts[0]->setMiscRegNoEffect(MISCREG_TL, 0); + tc->setMiscRegNoEffect(MISCREG_TL, 0); //Set the ASI register to something fixed - threadContexts[0]->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY); + tc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY); /* * T1 specific registers */ //Turn on the icache, dcache, dtb translation, and itb translation. - threadContexts[0]->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15); + tc->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15); } void @@ -160,8 +164,9 @@ Sparc32LiveProcess::startup() SparcLiveProcess::startup(); + ThreadContext *tc = system->getThreadContext(contextIds[0]); //The process runs in user mode with 32 bit addresses - threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x0a); + tc->setMiscReg(MISCREG_PSTATE, 0x0a); argsInit(32 / 8, VMPageSize); } @@ -174,8 +179,9 @@ Sparc64LiveProcess::startup() SparcLiveProcess::startup(); + ThreadContext *tc = system->getThreadContext(contextIds[0]); //The process runs in user mode - threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x02); + tc->setMiscReg(MISCREG_PSTATE, 0x02); argsInit(sizeof(IntReg), VMPageSize); } @@ -186,7 +192,7 @@ SparcLiveProcess::argsInit(int pageSize) { int intSize = sizeof(IntType); - typedef M5_auxv_t<IntType> auxv_t; + typedef AuxVector<IntType> auxv_t; std::vector<auxv_t> auxv; @@ -335,18 +341,18 @@ SparcLiveProcess::argsInit(int pageSize) IntType window_save_base = argc_base - window_save_size; #endif - DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); - DPRINTF(Sparc, "%#x - sentry NULL\n", sentry_base); - DPRINTF(Sparc, "filename = %s\n", filename); - DPRINTF(Sparc, "%#x - file name\n", file_name_base); - DPRINTF(Sparc, "%#x - env data\n", env_data_base); - DPRINTF(Sparc, "%#x - arg data\n", arg_data_base); - DPRINTF(Sparc, "%#x - auxv array\n", auxv_array_base); - DPRINTF(Sparc, "%#x - envp array\n", envp_array_base); - DPRINTF(Sparc, "%#x - argv array\n", argv_array_base); - DPRINTF(Sparc, "%#x - argc \n", argc_base); - DPRINTF(Sparc, "%#x - window save\n", window_save_base); - DPRINTF(Sparc, "%#x - stack min\n", stack_min); + DPRINTF(Stack, "The addresses of items on the initial stack:\n"); + DPRINTF(Stack, "%#x - sentry NULL\n", sentry_base); + DPRINTF(Stack, "filename = %s\n", filename); + DPRINTF(Stack, "%#x - file name\n", file_name_base); + DPRINTF(Stack, "%#x - env data\n", env_data_base); + DPRINTF(Stack, "%#x - arg data\n", arg_data_base); + DPRINTF(Stack, "%#x - auxv array\n", auxv_array_base); + DPRINTF(Stack, "%#x - envp array\n", envp_array_base); + DPRINTF(Stack, "%#x - argv array\n", argv_array_base); + DPRINTF(Stack, "%#x - argc \n", argc_base); + DPRINTF(Stack, "%#x - window save\n", window_save_base); + DPRINTF(Stack, "%#x - stack min\n", stack_min); assert(window_save_base == stack_min); @@ -354,7 +360,7 @@ SparcLiveProcess::argsInit(int pageSize) // figure out argc IntType argc = argv.size(); - IntType guestArgc = TheISA::htog(argc); + IntType guestArgc = SparcISA::htog(argc); //Write out the sentry void * uint64_t sentry_NULL = 0; @@ -391,20 +397,21 @@ SparcLiveProcess::argsInit(int pageSize) fillStart = stack_base; spillStart = fillStart + sizeof(MachInst) * numFillInsts; + ThreadContext *tc = system->getThreadContext(contextIds[0]); //Set up the thread context to start running the process //assert(NumArgumentRegs >= 2); - //threadContexts[0]->setIntReg(ArgumentReg[0], argc); - //threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); - threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias); + //tc->setIntReg(ArgumentReg[0], argc); + //tc->setIntReg(ArgumentReg[1], argv_array_base); + tc->setIntReg(StackPointerReg, stack_min - StackBias); // %g1 is a pointer to a function that should be run at exit. Since we // don't have anything like that, it should be set to 0. - threadContexts[0]->setIntReg(1, 0); + tc->setIntReg(1, 0); Addr prog_entry = objFile->entryPoint(); - threadContexts[0]->setPC(prog_entry); - threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); - threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); + tc->setNextNPC(prog_entry + (2 * sizeof(MachInst))); //Align the "stack_min" to a page boundary. stack_min = roundDown(stack_min, pageSize); @@ -505,3 +512,63 @@ void Sparc64LiveProcess::flushWindows(ThreadContext *tc) tc->setIntReg(NumIntArchRegs + 4, Canrestore); tc->setMiscReg(MISCREG_CWP, origCWP); } + +IntReg +Sparc32LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < 6); + return bits(tc->readIntReg(FirstArgumentReg + i), 31, 0); +} + +void +Sparc32LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val) +{ + assert(i < 6); + tc->setIntReg(FirstArgumentReg + i, bits(val, 31, 0)); +} + +IntReg +Sparc64LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < 6); + return tc->readIntReg(FirstArgumentReg + i); +} + +void +Sparc64LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val) +{ + assert(i < 6); + tc->setIntReg(FirstArgumentReg + i, val); +} + +void +SparcLiveProcess::setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) +{ + // check for error condition. SPARC syscall convention is to + // indicate success/failure in reg the carry bit of the ccr + // and put the return value itself in the standard return value reg (). + if (return_value.successful()) { + // no error, clear XCC.C + tc->setIntReg(NumIntArchRegs + 2, + tc->readIntReg(NumIntArchRegs + 2) & 0xEE); + //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) & 0xEE); + IntReg val = return_value.value(); + if (bits(tc->readMiscRegNoEffect( + SparcISA::MISCREG_PSTATE), 3, 3)) { + val = bits(val, 31, 0); + } + tc->setIntReg(ReturnValueReg, val); + } else { + // got an error, set XCC.C + tc->setIntReg(NumIntArchRegs + 2, + tc->readIntReg(NumIntArchRegs + 2) | 0x11); + //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) | 0x11); + IntReg val = -return_value.value(); + if (bits(tc->readMiscRegNoEffect( + SparcISA::MISCREG_PSTATE), 3, 3)) { + val = bits(val, 31, 0); + } + tc->setIntReg(ReturnValueReg, val); + } +} diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh index a37760139..fdb9734ba 100644 --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -69,26 +69,7 @@ class SparcLiveProcess : public LiveProcess { return spillStart; } virtual void flushWindows(ThreadContext *tc) = 0; -}; - -template<class IntType> -struct M5_auxv_t -{ - IntType a_type; - union { - IntType a_val; - IntType a_ptr; - IntType a_fcn; - }; - - M5_auxv_t() - {} - - M5_auxv_t(IntType type, IntType val) - { - a_type = SparcISA::htog(type); - a_val = SparcISA::htog(val); - } + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); }; class Sparc32LiveProcess : public SparcLiveProcess @@ -113,6 +94,9 @@ class Sparc32LiveProcess : public SparcLiveProcess void argsInit(int intSize, int pageSize); void flushWindows(ThreadContext *tc); + + SparcISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val); }; class Sparc64LiveProcess : public SparcLiveProcess @@ -138,6 +122,9 @@ class Sparc64LiveProcess : public SparcLiveProcess void argsInit(int intSize, int pageSize); void flushWindows(ThreadContext *tc); + + SparcISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val); }; #endif // __SPARC_PROCESS_HH__ diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index d6be52424..1c172a4d5 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -155,7 +155,7 @@ int SparcISA::flattenIntIndex(ThreadContext * tc, int reg) { int gl = tc->readMiscRegNoEffect(MISCREG_GL); int cwp = tc->readMiscRegNoEffect(MISCREG_CWP); - //DPRINTF(Sparc, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp); + //DPRINTF(RegisterWindows, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp); int newReg; //The total number of global registers int numGlobals = (MaxGL + 1) * 8; @@ -214,46 +214,33 @@ int SparcISA::flattenIntIndex(ThreadContext * tc, int reg) } else panic("Tried to flatten invalid register index %d!\n", reg); - DPRINTF(Sparc, "Flattened register %d to %d.\n", reg, newReg); + DPRINTF(RegisterWindows, "Flattened register %d to %d.\n", reg, newReg); return newReg; //return intRegFile.flattenIndex(reg); } -void RegFile::serialize(std::ostream &os) +void +RegFile::serialize(EventManager *em, ostream &os) { intRegFile.serialize(os); floatRegFile.serialize(os); - miscRegFile.serialize(os); + miscRegFile.serialize(em, os); SERIALIZE_SCALAR(pc); SERIALIZE_SCALAR(npc); SERIALIZE_SCALAR(nnpc); } -void RegFile::unserialize(Checkpoint *cp, const std::string §ion) +void +RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) { intRegFile.unserialize(cp, section); floatRegFile.unserialize(cp, section); - miscRegFile.unserialize(cp, section); + miscRegFile.unserialize(em, cp, section); UNSERIALIZE_SCALAR(pc); UNSERIALIZE_SCALAR(npc); UNSERIALIZE_SCALAR(nnpc); } -void RegFile::changeContext(RegContextParam param, RegContextVal val) -{ - switch(param) - { - case CONTEXT_CWP: - intRegFile.setCWP(val); - break; - case CONTEXT_GLOBALS: - intRegFile.setGlobals(val); - break; - default: - panic("Tried to set illegal context parameter in the SPARC regfile.\n"); - } -} - void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) { @@ -366,12 +353,12 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) void SparcISA::copyRegs(ThreadContext *src, ThreadContext *dest) { // First loop through the integer registers. - for (int i = 0; i < TheISA::NumIntRegs; ++i) { + for (int i = 0; i < SparcISA::NumIntRegs; ++i) { dest->setIntReg(i, src->readIntReg(i)); } // Then loop through the floating point registers. - for (int i = 0; i < TheISA::NumFloatRegs; ++i) { + for (int i = 0; i < SparcISA::NumFloatRegs; ++i) { dest->setFloatRegBits(i, src->readFloatRegBits(i)); } diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh index c03f69fc5..505d7c8d7 100644 --- a/src/arch/sparc/regfile.hh +++ b/src/arch/sparc/regfile.hh @@ -48,8 +48,8 @@ namespace SparcISA class RegFile { protected: - Addr pc; // Program Counter - Addr npc; // Next Program Counter + Addr pc; // Program Counter + Addr npc; // Next Program Counter Addr nnpc; public: @@ -63,16 +63,14 @@ namespace SparcISA void setNextNPC(Addr val); protected: - IntRegFile intRegFile; // integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegFile; // control register file + IntRegFile intRegFile; // integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file public: void clear(); - int FlattenIntIndex(int reg); - MiscReg readMiscRegNoEffect(int miscReg); MiscReg readMiscReg(int miscReg, ThreadContext *tc); @@ -112,12 +110,11 @@ namespace SparcISA void setIntReg(int intReg, const IntReg &val); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); public: - - void changeContext(RegContextParam param, RegContextVal val); }; int flattenIntIndex(ThreadContext * tc, int reg); diff --git a/src/arch/sparc/remote_gdb.cc b/src/arch/sparc/remote_gdb.cc index 67cc5b0d1..615c5b551 100644 --- a/src/arch/sparc/remote_gdb.cc +++ b/src/arch/sparc/remote_gdb.cc @@ -30,7 +30,7 @@ /* * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and @@ -38,8 +38,8 @@ * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,8 +51,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -69,7 +69,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 */ /*- @@ -89,8 +89,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -137,7 +137,7 @@ #include "sim/system.hh" using namespace std; -using namespace TheISA; +using namespace SparcISA; RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) : BaseRemoteGDB(_system, c, NumGDBRegs), nextBkpt(0) @@ -146,7 +146,7 @@ RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) /////////////////////////////////////////////////////////// // RemoteGDB::acc // -// Determine if the mapping at va..(va+len) is valid. +// Determine if the mapping at va..(va+len) is valid. // bool RemoteGDB::acc(Addr va, size_t len) @@ -171,8 +171,8 @@ RemoteGDB::acc(Addr va, size_t len) /////////////////////////////////////////////////////////// // RemoteGDB::getregs // -// Translate the kernel debugger register format into -// the GDB register format. +// Translate the kernel debugger register format into +// the GDB register format. void RemoteGDB::getregs() { @@ -217,8 +217,8 @@ RemoteGDB::getregs() /////////////////////////////////////////////////////////// // RemoteGDB::setregs // -// Translate the GDB register format into the kernel -// debugger register format. +// Translate the GDB register format into the kernel +// debugger register format. // void RemoteGDB::setregs() diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc index 40d172690..22924736b 100644 --- a/src/arch/sparc/solaris/process.cc +++ b/src/arch/sparc/solaris/process.cc @@ -48,7 +48,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Solaris::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Solaris::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "SunOS"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -80,7 +80,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = { /* 14 */ SyscallDesc("mknod", unimplementedFunc), /* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>), /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), + /* 17 */ SyscallDesc("brk", brkFunc), /* 18 */ SyscallDesc("stat", unimplementedFunc), /* 19 */ SyscallDesc("lseek", lseekFunc), /* 20 */ SyscallDesc("getpid", getpidFunc), @@ -123,7 +123,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = { /* 57 */ SyscallDesc("utssys", unimplementedFunc), /* 58 */ SyscallDesc("fdsync", unimplementedFunc), /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 60 */ SyscallDesc("umask", umaskFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("fcntl", unimplementedFunc), /* 63 */ SyscallDesc("ulimit", unimplementedFunc), @@ -153,7 +153,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = { /* 87 */ SyscallDesc("poll", unimplementedFunc), /* 88 */ SyscallDesc("lstat", unimplementedFunc), /* 89 */ SyscallDesc("symlink", unimplementedFunc), - /* 90 */ SyscallDesc("readlink", unimplementedFunc), + /* 90 */ SyscallDesc("readlink", readlinkFunc), /* 91 */ SyscallDesc("setgroups", unimplementedFunc), /* 92 */ SyscallDesc("getgroups", unimplementedFunc), /* 93 */ SyscallDesc("fchmod", unimplementedFunc), @@ -336,7 +336,7 @@ SparcSolarisProcess::SparcSolarisProcess(LiveProcessParams * params, SyscallDesc* SparcSolarisProcess::getDesc(int callnum) { - if (callnum < 0 || callnum > Num_Syscall_Descs) + if (callnum < 0 || callnum >= Num_Syscall_Descs) return NULL; return &syscallDescs[callnum]; } diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc index c53caa72a..3cc910005 100644 --- a/src/arch/sparc/solaris/solaris.cc +++ b/src/arch/sparc/solaris/solaris.cc @@ -35,40 +35,40 @@ // open(2) flags translation table OpenFlagTransTable SparcSolaris::openFlagTable[] = { #ifdef _MSC_VER - { SparcSolaris::TGT_O_RDONLY, _O_RDONLY }, - { SparcSolaris::TGT_O_WRONLY, _O_WRONLY }, - { SparcSolaris::TGT_O_RDWR, _O_RDWR }, - { SparcSolaris::TGT_O_APPEND, _O_APPEND }, - { SparcSolaris::TGT_O_CREAT, _O_CREAT }, - { SparcSolaris::TGT_O_TRUNC, _O_TRUNC }, - { SparcSolaris::TGT_O_EXCL, _O_EXCL }, + { SparcSolaris::TGT_O_RDONLY, _O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, _O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, _O_RDWR }, + { SparcSolaris::TGT_O_APPEND, _O_APPEND }, + { SparcSolaris::TGT_O_CREAT, _O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, _O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, _O_EXCL }, #ifdef _O_NONBLOCK - { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK }, - { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK }, + { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK }, #endif #ifdef _O_NOCTTY - { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY }, + { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY }, #endif #ifdef _O_SYNC - { SparcSolaris::TGT_O_SYNC, _O_SYNC }, - { SparcSolaris::TGT_O_DSYNC, _O_SYNC }, - { SparcSolaris::TGT_O_RSYNC, _O_SYNC }, + { SparcSolaris::TGT_O_SYNC, _O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, _O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, _O_SYNC }, #endif #else /* !_MSC_VER */ - { SparcSolaris::TGT_O_RDONLY, O_RDONLY }, - { SparcSolaris::TGT_O_WRONLY, O_WRONLY }, - { SparcSolaris::TGT_O_RDWR, O_RDWR }, - { SparcSolaris::TGT_O_APPEND, O_APPEND }, - { SparcSolaris::TGT_O_CREAT, O_CREAT }, - { SparcSolaris::TGT_O_TRUNC, O_TRUNC }, - { SparcSolaris::TGT_O_EXCL, O_EXCL }, - { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK }, - { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK }, - { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY }, + { SparcSolaris::TGT_O_RDONLY, O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, O_RDWR }, + { SparcSolaris::TGT_O_APPEND, O_APPEND }, + { SparcSolaris::TGT_O_CREAT, O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, O_EXCL }, + { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK }, + { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY }, #ifdef O_SYNC - { SparcSolaris::TGT_O_SYNC, O_SYNC }, - { SparcSolaris::TGT_O_DSYNC, O_SYNC }, - { SparcSolaris::TGT_O_RSYNC, O_SYNC }, + { SparcSolaris::TGT_O_SYNC, O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, O_SYNC }, #endif #endif /* _MSC_VER */ }; diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh index 0564faba4..df2565027 100644 --- a/src/arch/sparc/solaris/solaris.hh +++ b/src/arch/sparc/solaris/solaris.hh @@ -39,22 +39,22 @@ class SparcSolaris : public Solaris static OpenFlagTransTable openFlagTable[]; - static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR - static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK - static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC static const int TGT_O_DSYNC = 0x00000040; //!< O_SYNC static const int TGT_O_RSYNC = 0x00008000; //!< O_SYNC static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK static const int TGT_O_PRIV = 0x00001000; //?? static const int TGT_O_LARGEFILE = 0x00002000; //?? - static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT - static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC - static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL - static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY - static const int TGT_O_XATTR = 0x00004000; //?? + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_XATTR = 0x00004000; //?? static const int NUM_OPEN_FLAGS; diff --git a/src/arch/sparc/sparc_traits.hh b/src/arch/sparc/sparc_traits.hh index 715c08c03..e154ba274 100644 --- a/src/arch/sparc/sparc_traits.hh +++ b/src/arch/sparc/sparc_traits.hh @@ -47,8 +47,8 @@ namespace SparcISA // const int NumRegularIntRegs = MaxGL * 8 + NWindows * 16; // const int NumMicroIntRegs = 1; // const int NumIntRegs = -// NumRegularIntRegs + -// NumMicroIntRegs; +// NumRegularIntRegs + +// NumMicroIntRegs; // const int NumFloatRegs = 64; // const int NumMiscRegs = 40; } diff --git a/src/arch/sparc/stacktrace.cc b/src/arch/sparc/stacktrace.cc index 2d7991267..3ab0edb57 100644 --- a/src/arch/sparc/stacktrace.cc +++ b/src/arch/sparc/stacktrace.cc @@ -70,8 +70,6 @@ namespace SparcISA if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) panic("thread info not compiled into kernel\n"); name_off = vp->readGtoH<int32_t>(addr); - - tc->delVirtPort(vp); } Addr @@ -87,7 +85,6 @@ namespace SparcISA vp = tc->getVirtPort(); tsk = vp->readGtoH<Addr>(base + task_off); - tc->delVirtPort(vp); return tsk; } @@ -105,7 +102,6 @@ namespace SparcISA vp = tc->getVirtPort(); pd = vp->readGtoH<uint16_t>(task + pid_off); - tc->delVirtPort(vp); return pd; } @@ -163,7 +159,7 @@ namespace SparcISA } SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; - Addr ksp = tc->readIntReg(TheISA::StackPointerReg); + Addr ksp = tc->readIntReg(SparcISA::StackPointerReg); Addr bottom = ksp & ~0x3fff; Addr addr; diff --git a/src/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh index 4bc5d779b..929990fcb 100644 --- a/src/arch/sparc/stacktrace.hh +++ b/src/arch/sparc/stacktrace.hh @@ -61,7 +61,7 @@ namespace SparcISA class StackTrace { protected: - typedef TheISA::MachInst MachInst; + typedef SparcISA::MachInst MachInst; private: ThreadContext *tc; std::vector<Addr> stack; diff --git a/src/arch/sparc/syscallreturn.hh b/src/arch/sparc/syscallreturn.hh deleted file mode 100644 index cf13fc3e8..000000000 --- a/src/arch/sparc/syscallreturn.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Gabe Black - */ - -#ifndef __ARCH_SPARC_SYSCALLRETURN_HH__ -#define __ARCH_SPARC_SYSCALLRETURN_HH__ - -#include <inttypes.h> - -#include "sim/syscallreturn.hh" -#include "arch/sparc/regfile.hh" -#include "cpu/thread_context.hh" - -namespace SparcISA -{ - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext * tc) - { - // check for error condition. SPARC syscall convention is to - // indicate success/failure in reg the carry bit of the ccr - // and put the return value itself in the standard return value reg (). - if (return_value.successful()) { - // no error, clear XCC.C - tc->setIntReg(NumIntArchRegs + 2, - tc->readIntReg(NumIntArchRegs + 2) & 0xEE); - //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) & 0xEE); - tc->setIntReg(ReturnValueReg, return_value.value()); - } else { - // got an error, set XCC.C - tc->setIntReg(NumIntArchRegs + 2, - tc->readIntReg(NumIntArchRegs + 2) | 0x11); - //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) | 0x11); - tc->setIntReg(ReturnValueReg, -return_value.value()); - } - } -}; - -#endif diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index 22df44908..95ad0229e 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -51,7 +51,7 @@ TLB::TLB(const Params *p) { // To make this work you'll have to change the hypervisor and OS if (size > 64) - fatal("SPARC T1 TLB registers don't support more than 64 TLB entries."); + fatal("SPARC T1 TLB registers don't support more than 64 TLB entries"); tlb = new TlbEntry[size]; std::memset(tlb, 0, sizeof(TlbEntry) * size); @@ -87,8 +87,6 @@ void TLB::insert(Addr va, int partition_id, int context_id, bool real, const PageTableEntry& PTE, int entry) { - - MapIter i; TlbEntry *new_entry = NULL; // TlbRange tr; @@ -103,8 +101,9 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real, tr.real = real; */ - DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n", - va, PTE.paddr(), partition_id, context_id, (int)real, entry); + DPRINTF(TLB, + "TLB: Inserting Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n", + va, PTE.paddr(), partition_id, context_id, (int)real, entry); // Demap any entry that conflicts for (x = 0; x < size; x++) { @@ -128,7 +127,6 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real, } } - /* i = lookupTable.find(tr); if (i != lookupTable.end()) { @@ -195,25 +193,22 @@ insertAllLocked: new_entry->valid = true; usedEntries++; - - i = lookupTable.insert(new_entry->range, new_entry); assert(i != lookupTable.end()); - // If all entries have there used bit set, clear it on them all, but the - // one we just inserted + // If all entries have their used bit set, clear it on them all, + // but the one we just inserted if (usedEntries == size) { clearUsedBits(); new_entry->used = true; usedEntries++; } - } TlbEntry* -TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool - update_used) +TLB::lookup(Addr va, int partition_id, bool real, int context_id, + bool update_used) { MapIter i; TlbRange tr; @@ -240,8 +235,8 @@ TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(), t->pte.size()); - // Update the used bits only if this is a real access (not a fake one from - // virttophys() + // Update the used bits only if this is a real access (not a fake + // one from virttophys() if (!t->used && update_used) { t->used = true; usedEntries++; @@ -304,11 +299,10 @@ TLB::demapPage(Addr va, int partition_id, bool real, int context_id) void TLB::demapContext(int partition_id, int context_id) { - int x; DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n", partition_id, context_id); cacheValid = false; - for (x = 0; x < size; x++) { + for (int x = 0; x < size; x++) { if (tlb[x].range.contextId == context_id && tlb[x].range.partitionId == partition_id) { if (tlb[x].valid == true) { @@ -327,10 +321,9 @@ TLB::demapContext(int partition_id, int context_id) void TLB::demapAll(int partition_id) { - int x; DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id); cacheValid = false; - for (x = 0; x < size; x++) { + for (int x = 0; x < size; x++) { if (tlb[x].valid && !tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) { freeList.push_front(&tlb[x]); @@ -347,11 +340,10 @@ TLB::demapAll(int partition_id) void TLB::invalidateAll() { - int x; cacheValid = false; - lookupTable.clear(); - for (x = 0; x < size; x++) { + + for (int x = 0; x < size; x++) { if (tlb[x].valid == true) freeList.push_back(&tlb[x]); tlb[x].valid = false; @@ -361,7 +353,8 @@ TLB::invalidateAll() } uint64_t -TLB::TteRead(int entry) { +TLB::TteRead(int entry) +{ if (entry >= size) panic("entry: %d\n", entry); @@ -373,7 +366,8 @@ TLB::TteRead(int entry) { } uint64_t -TLB::TagRead(int entry) { +TLB::TagRead(int entry) +{ assert(entry < size); uint64_t tag; if (!tlb[entry].valid) @@ -442,7 +436,7 @@ DTB::writeSfsr(Addr a, bool write, ContextType ct, } Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); @@ -459,9 +453,8 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) if (cacheEntry) { if (cacheEntry->range.va < vaddr + sizeof(MachInst) && cacheEntry->range.va + cacheEntry->range.size >= vaddr) { - req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) | - vaddr & cacheEntry->pte.size()-1 ); - return NoFault; + req->setPaddr(cacheEntry->pte.translate(vaddr)); + return NoFault; } } else { req->setPaddr(vaddr & PAddrImplMask); @@ -550,18 +543,26 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) cacheState = tlbdata; cacheEntry = e; - req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | - vaddr & e->pte.size()-1 ); + req->setPaddr(e->pte.translate(vaddr)); DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); return NoFault; } - +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { - /* @todo this could really use some profiling and fixing to make it faster! */ + /* + * @todo this could really use some profiling and fixing to make + * it faster! + */ uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); Addr vaddr = req->getVaddr(); Addr size = req->getSize(); @@ -569,7 +570,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) asi = (ASI)req->getAsi(); bool implicit = false; bool hpriv = bits(tlbdata,0,0); - bool unaligned = (vaddr & size-1); + bool unaligned = vaddr & (size - 1); DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n", vaddr, size, asi); @@ -599,11 +600,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if (cacheAsi[0] == asi && ce_va < vaddr + size && ce_va + ce->range.size > vaddr && (!write || ce->pte.writable())) { - req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask()); - if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) - req->setFlags(req->getFlags() | UNCACHEABLE); - DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); - return NoFault; + req->setPaddr(ce->pte.translate(vaddr)); + if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) + req->setFlags(Request::UNCACHEABLE); + DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); + return NoFault; } // if matched } // if cache entry valid if (cacheEntry[1]) { @@ -612,11 +613,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if (cacheAsi[1] == asi && ce_va < vaddr + size && ce_va + ce->range.size > vaddr && (!write || ce->pte.writable())) { - req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask()); - if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) - req->setFlags(req->getFlags() | UNCACHEABLE); - DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); - return NoFault; + req->setPaddr(ce->pte.translate(vaddr)); + if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1) + req->setFlags(Request::UNCACHEABLE); + DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); + return NoFault; } // if matched } // if cache entry valid } @@ -639,7 +640,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) TlbEntry *e; DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n", - priv, hpriv, red, lsu_dm, part_id); + priv, hpriv, red, lsu_dm, part_id); if (implicit) { if (tl > 0) { @@ -725,11 +726,10 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) return new DataAccessException; } - if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) { real = true; context = 0; - }; + } if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) { req->setPaddr(vaddr & PAddrImplMask); @@ -776,9 +776,8 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) return new DataAccessException; } - if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1) - req->setFlags(req->getFlags() | UNCACHEABLE); + req->setFlags(Request::UNCACHEABLE); // cache translation date for next translation cacheState = tlbdata; @@ -796,8 +795,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) cacheAsi[0] = (ASI)0; } cacheValid = true; - req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | - vaddr & e->pte.size()-1); + req->setPaddr(e->pte.translate(vaddr)); DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); return NoFault; @@ -811,8 +809,8 @@ handleIntRegAccess: return new PrivilegedAction; } - if (asi == ASI_SWVR_UDB_INTR_W && !write || - asi == ASI_SWVR_UDB_INTR_R && write) { + if ((asi == ASI_SWVR_UDB_INTR_W && !write) || + (asi == ASI_SWVR_UDB_INTR_R && write)) { writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); return new DataAccessException; } @@ -832,7 +830,7 @@ handleQueueRegAccess: writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); return new PrivilegedAction; } - if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) { + if ((!hpriv && vaddr & 0xF) || vaddr > 0x3f8 || vaddr < 0x3c0) { writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi); return new DataAccessException; } @@ -857,6 +855,14 @@ handleMmuRegAccess: return NoFault; }; +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + #if FULL_SYSTEM Tick @@ -869,7 +875,7 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n", (uint32_t)pkt->req->getAsi(), pkt->getAddr()); - ITB * itb = tc->getITBPtr(); + ITB *itb = tc->getITBPtr(); switch (asi) { case ASI_LSU_CONTROL_REG: @@ -1018,12 +1024,22 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) itb->cx_config)); break; case ASI_SWVR_INTR_RECEIVE: - pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC)); + { + SparcISA::Interrupts * interrupts = + dynamic_cast<SparcISA::Interrupts *>( + tc->getCpuPtr()->getInterruptController()); + pkt->set(interrupts->get_vec(IT_INT_VEC)); + } break; case ASI_SWVR_UDB_INTR_R: - temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC)); - tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp); - pkt->set(temp); + { + SparcISA::Interrupts * interrupts = + dynamic_cast<SparcISA::Interrupts *>( + tc->getCpuPtr()->getInterruptController()); + temp = findMsbSet(interrupts->get_vec(IT_INT_VEC)); + tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp); + pkt->set(temp); + } break; default: doMmuReadError: @@ -1055,7 +1071,7 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n", (uint32_t)asi, va, data); - ITB * itb = tc->getITBPtr(); + ITB *itb = tc->getITBPtr(); switch (asi) { case ASI_LSU_CONTROL_REG: @@ -1129,7 +1145,7 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) break; case ASI_SPARC_ERROR_EN_REG: case ASI_SPARC_ERROR_STATUS_REG: - warn("Ignoring write to SPARC ERROR regsiter\n"); + inform("Ignoring write to SPARC ERROR regsiter\n"); break; case ASI_HYP_SCRATCHPAD: case ASI_SCRATCHPAD: @@ -1173,7 +1189,8 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) real_insert = bits(va, 9,9); pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : PageTableEntry::sun4u); - insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert); + insert(va_insert, part_insert, ct_insert, real_insert, pte, + entry_insert); break; case ASI_IMMU_DEMAP: ignore = false; @@ -1261,18 +1278,23 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) } break; case ASI_SWVR_INTR_RECEIVE: - int msb; - // clear all the interrupts that aren't set in the write - while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) { - msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data); - tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb); + { + int msb; + // clear all the interrupts that aren't set in the write + SparcISA::Interrupts * interrupts = + dynamic_cast<SparcISA::Interrupts *>( + tc->getCpuPtr()->getInterruptController()); + while (interrupts->get_vec(IT_INT_VEC) & data) { + msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data); + tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb); + } } break; case ASI_SWVR_UDB_INTR_W: tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()-> - post_interrupt(bits(data,5,0),0); + postInterrupt(bits(data, 5, 0), 0); break; - default: + default: doMmuWriteError: panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n", (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data); @@ -1310,10 +1332,6 @@ DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs) itb->cx_config); } - - - - uint64_t DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb, uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config) @@ -1341,7 +1359,6 @@ DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb, return ptr; } - void TLB::serialize(std::ostream &os) { diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh index 2f7d08320..4fe532d4a 100644 --- a/src/arch/sparc/tlb.hh +++ b/src/arch/sparc/tlb.hh @@ -109,9 +109,9 @@ class TLB : public BaseTLB * @param paritition_id partition this entry is for * @param real is this a real->phys or virt->phys translation * @param context_id if this is virt->phys what context - * @param update_used should ew update the used bits in the entries on not - * useful if we are trying to do a va->pa without mucking with any state for - * a debug read for example. + * @param update_used should ew update the used bits in the + * entries on not useful if we are trying to do a va->pa without + * mucking with any state for a debug read for example. * @return A pointer to a tlb entry */ TlbEntry *lookup(Addr va, int partition_id, bool real, int context_id = 0, @@ -177,7 +177,9 @@ class ITB : public TLB cacheEntry = NULL; } - Fault translate(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); private: void writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi); @@ -199,7 +201,10 @@ class DTB : public TLB cacheEntry[1] = NULL; } - Fault translate(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, + ThreadContext *tc, bool write=false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write=false); #if FULL_SYSTEM Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); diff --git a/src/arch/sparc/tlb_map.hh b/src/arch/sparc/tlb_map.hh index 8285db939..fa49584ba 100644 --- a/src/arch/sparc/tlb_map.hh +++ b/src/arch/sparc/tlb_map.hh @@ -52,7 +52,7 @@ class TlbMap i = tree.upper_bound(r); - if (i == tree.begin()) + if (i == tree.begin()) { if (r.real == i->first.real && r.partitionId == i->first.partitionId && i->first.va < r.va + r.size && @@ -62,6 +62,7 @@ class TlbMap else // Nothing could match, so return end() return tree.end(); + } i--; diff --git a/src/arch/sparc/types.hh b/src/arch/sparc/types.hh index d19e2a99f..dd369cc26 100644 --- a/src/arch/sparc/types.hh +++ b/src/arch/sparc/types.hh @@ -51,14 +51,6 @@ namespace SparcISA MiscReg ctrlreg; } AnyReg; - enum RegContextParam - { - CONTEXT_CWP, - CONTEXT_GLOBALS - }; - - typedef int RegContextVal; - typedef uint16_t RegIndex; struct CoreSpecific { diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc index fe733813c..880d2c3eb 100644 --- a/src/arch/sparc/ua2005.cc +++ b/src/arch/sparc/ua2005.cc @@ -35,34 +35,59 @@ #include "sim/system.hh" using namespace SparcISA; +using namespace std; void MiscRegFile::checkSoftInt(ThreadContext *tc) { + BaseCPU *cpu = tc->getCpuPtr(); + // If PIL < 14, copy over the tm and sm bits if (pil < 14 && softint & 0x10000) - tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,16); + cpu->postInterrupt(IT_SOFT_INT, 16); else - tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,16); + cpu->clearInterrupt(IT_SOFT_INT, 16); if (pil < 14 && softint & 0x1) - tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,0); + cpu->postInterrupt(IT_SOFT_INT, 0); else - tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,0); + cpu->clearInterrupt(IT_SOFT_INT, 0); // Copy over any of the other bits that are set for (int bit = 15; bit > 0; --bit) { if (1 << bit & softint && bit > pil) - tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,bit); + cpu->postInterrupt(IT_SOFT_INT, bit); else - tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,bit); + cpu->clearInterrupt(IT_SOFT_INT, bit); } } +//These functions map register indices to names +static inline string +getMiscRegName(RegIndex index) +{ + static string miscRegName[NumMiscRegs] = + {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic", + "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr", + "stick", "stick_cmpr", + "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl", + "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin", + "wstate",*/ "gl", + "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg", + "hstick_cmpr", + "fsr", "prictx", "secctx", "partId", "lsuCtrlReg", + "scratch0", "scratch1", "scratch2", "scratch3", "scratch4", + "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail", + "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail", + "nresErrorHead", "nresErrorTail", "TlbData" }; + return miscRegName[index]; +} void MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) { + BaseCPU *cpu = tc->getCpuPtr(); + int64_t time; switch (miscReg) { /* Full system only ASRs */ @@ -80,12 +105,12 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) tickCompare = new TickCompareEvent(this, tc); setRegNoEffect(miscReg, val); if ((tick_cmpr & ~mask(63)) && tickCompare->scheduled()) - tickCompare->deschedule(); + cpu->deschedule(tickCompare); time = (tick_cmpr & mask(63)) - (tick & mask(63)); if (!(tick_cmpr & ~mask(63)) && time > 0) { if (tickCompare->scheduled()) - tickCompare->deschedule(); - tickCompare->schedule(time * tc->getCpuPtr()->ticks(1)); + cpu->deschedule(tickCompare); + cpu->schedule(tickCompare, curTick + time * cpu->ticks(1)); } panic("writing to TICK compare register %#X\n", val); break; @@ -95,13 +120,13 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) sTickCompare = new STickCompareEvent(this, tc); setRegNoEffect(miscReg, val); if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled()) - sTickCompare->deschedule(); + cpu->deschedule(sTickCompare); time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - - tc->getCpuPtr()->instCount(); + cpu->instCount(); if (!(stick_cmpr & ~mask(63)) && time > 0) { if (sTickCompare->scheduled()) - sTickCompare->deschedule(); - sTickCompare->schedule(time * tc->getCpuPtr()->ticks(1) + curTick); + cpu->deschedule(sTickCompare); + cpu->schedule(sTickCompare, curTick + time * cpu->ticks(1)); } DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val); break; @@ -120,9 +145,9 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) case MISCREG_HINTP: setRegNoEffect(miscReg, val); if (hintp) - tc->getCpuPtr()->post_interrupt(IT_HINTP,0); + cpu->postInterrupt(IT_HINTP, 0); else - tc->getCpuPtr()->clear_interrupt(IT_HINTP,0); + cpu->clearInterrupt(IT_HINTP, 0); break; case MISCREG_HTBA: @@ -134,25 +159,25 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) case MISCREG_QUEUE_CPU_MONDO_TAIL: setRegNoEffect(miscReg, val); if (cpu_mondo_head != cpu_mondo_tail) - tc->getCpuPtr()->post_interrupt(IT_CPU_MONDO,0); + cpu->postInterrupt(IT_CPU_MONDO, 0); else - tc->getCpuPtr()->clear_interrupt(IT_CPU_MONDO,0); + cpu->clearInterrupt(IT_CPU_MONDO, 0); break; case MISCREG_QUEUE_DEV_MONDO_HEAD: case MISCREG_QUEUE_DEV_MONDO_TAIL: setRegNoEffect(miscReg, val); if (dev_mondo_head != dev_mondo_tail) - tc->getCpuPtr()->post_interrupt(IT_DEV_MONDO,0); + cpu->postInterrupt(IT_DEV_MONDO, 0); else - tc->getCpuPtr()->clear_interrupt(IT_DEV_MONDO,0); + cpu->clearInterrupt(IT_DEV_MONDO, 0); break; case MISCREG_QUEUE_RES_ERROR_HEAD: case MISCREG_QUEUE_RES_ERROR_TAIL: setRegNoEffect(miscReg, val); if (res_error_head != res_error_tail) - tc->getCpuPtr()->post_interrupt(IT_RES_ERROR,0); + cpu->postInterrupt(IT_RES_ERROR, 0); else - tc->getCpuPtr()->clear_interrupt(IT_RES_ERROR,0); + cpu->clearInterrupt(IT_RES_ERROR, 0); break; case MISCREG_QUEUE_NRES_ERROR_HEAD: case MISCREG_QUEUE_NRES_ERROR_TAIL: @@ -165,13 +190,13 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) hSTickCompare = new HSTickCompareEvent(this, tc); setRegNoEffect(miscReg, val); if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled()) - hSTickCompare->deschedule(); + cpu->deschedule(hSTickCompare); time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - - tc->getCpuPtr()->instCount(); + cpu->instCount(); if (!(hstick_cmpr & ~mask(63)) && time > 0) { if (hSTickCompare->scheduled()) - hSTickCompare->deschedule(); - hSTickCompare->schedule(curTick + time * tc->getCpuPtr()->ticks(1)); + cpu->deschedule(hSTickCompare); + cpu->schedule(hSTickCompare, curTick + time * cpu->ticks(1)); } DPRINTF(Timer, "writing to hsTICK compare register value %#X\n", val); break; @@ -181,9 +206,9 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) setRegNoEffect(miscReg, val | HPSTATE::id); #if FULL_SYSTEM if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv)) - tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0); + cpu->postInterrupt(IT_TRAP_LEVEL_ZERO, 0); else - tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0); + cpu->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0); #endif break; case MISCREG_HTSTATE: @@ -200,11 +225,12 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) tc->suspend(); if (tc->getKernelStats()) tc->getKernelStats()->quiesce(); - } + } break; default: - panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg)); + panic("Invalid write to FS misc register %s\n", + getMiscRegName(miscReg)); } } @@ -250,12 +276,13 @@ MiscRegFile::readFSReg(int miscReg, ThreadContext * tc) sys = tc->getSystemPtr(); temp = readRegNoEffect(miscReg) & (STS::active | STS::speculative); - // Check that the CPU array is fully populated (by calling getNumCPus()) - assert(sys->getNumCPUs() > tc->readCpuId()); + // Check that the CPU array is fully populated + // (by calling getNumCPus()) + assert(sys->numContexts() > tc->contextId()); - temp |= tc->readCpuId() << STS::shft_id; + temp |= tc->contextId() << STS::shft_id; - for (x = tc->readCpuId() & ~3; x < sys->threadContexts.size(); x++) { + for (x = tc->contextId() & ~3; x < sys->threadContexts.size(); x++) { switch (sys->threadContexts[x]->status()) { case ThreadContext::Active: temp |= STS::st_run << (STS::shft_fsm0 - @@ -280,16 +307,6 @@ MiscRegFile::readFSReg(int miscReg, ThreadContext * tc) panic("Invalid read to FS misc register\n"); } } -/* - In Niagra STICK==TICK so this isn't needed - case MISCREG_STICK: - SparcSystem *sys; - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63))); -*/ - - void MiscRegFile::processTickCompare(ThreadContext *tc) @@ -300,12 +317,14 @@ MiscRegFile::processTickCompare(ThreadContext *tc) void MiscRegFile::processSTickCompare(ThreadContext *tc) { + BaseCPU *cpu = tc->getCpuPtr(); + // since our microcode instructions take two cycles we need to check if // we're actually at the correct cycle or we need to wait a little while // more int ticks; ticks = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - - tc->getCpuPtr()->instCount(); + cpu->instCount(); assert(ticks >= 0 && "stick compare missed interrupt cycle"); if (ticks == 0 || tc->status() == ThreadContext::Suspended) { @@ -315,12 +334,14 @@ MiscRegFile::processSTickCompare(ThreadContext *tc) setReg(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc); } } else - sTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick); + cpu->schedule(sTickCompare, curTick + ticks * cpu->ticks(1)); } void MiscRegFile::processHSTickCompare(ThreadContext *tc) { + BaseCPU *cpu = tc->getCpuPtr(); + // since our microcode instructions take two cycles we need to check if // we're actually at the correct cycle or we need to wait a little while // more @@ -330,7 +351,7 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc) return; ticks = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - - tc->getCpuPtr()->instCount(); + cpu->instCount(); assert(ticks >= 0 && "hstick compare missed interrupt cycle"); if (ticks == 0 || tc->status() == ThreadContext::Suspended) { @@ -341,6 +362,6 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc) } // Need to do something to cause interrupt to happen here !!! @todo } else - hSTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick); + cpu->schedule(hSTickCompare, curTick + ticks * cpu->ticks(1)); } diff --git a/src/arch/sparc/utility.cc b/src/arch/sparc/utility.cc index 6d4358603..d4cc286e6 100644 --- a/src/arch/sparc/utility.cc +++ b/src/arch/sparc/utility.cc @@ -46,14 +46,14 @@ namespace SparcISA { //first 6 arguments which the caller may use but doesn't have to. uint64_t getArgument(ThreadContext *tc, int number, bool fp) { #if FULL_SYSTEM + const int NumArgumentRegs = 6; if (number < NumArgumentRegs) { - return tc->readIntReg(ArgumentReg[number]); + return tc->readIntReg(8 + number); } else { Addr sp = tc->readIntReg(StackPointerReg); - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); uint64_t arg = vp->read<uint64_t>(sp + 92 + (number-NumArgumentRegs) * sizeof(uint64_t)); - tc->delVirtPort(vp); return arg; } #else diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc index 9a93950d2..f23fb8304 100644 --- a/src/arch/sparc/vtophys.cc +++ b/src/arch/sparc/vtophys.cc @@ -40,85 +40,93 @@ using namespace std; -namespace SparcISA +namespace SparcISA { + +Addr +vtophys(Addr vaddr) { - Addr vtophys(Addr vaddr) - { - // In SPARC it's almost always impossible to turn a VA->PA w/o a context - // The only times we can kinda do it are if we have a SegKPM mapping - // and can find the real address in the tlb or we have a physical - // adddress already (beacuse we are looking at the hypervisor) - // Either case is rare, so we'll just panic. - - panic("vtophys() without context on SPARC largly worthless\n"); - M5_DUMMY_RETURN - } + // In SPARC it's almost always impossible to turn a VA->PA w/o a + // context The only times we can kinda do it are if we have a + // SegKPM mapping and can find the real address in the tlb or we + // have a physical adddress already (beacuse we are looking at the + // hypervisor) Either case is rare, so we'll just panic. + + panic("vtophys() without context on SPARC largly worthless\n"); + M5_DUMMY_RETURN; +} + +Addr +vtophys(ThreadContext *tc, Addr addr) +{ + // Here we have many options and are really implementing something like + // a fill handler to find the address since there isn't a multilevel + // table for us to walk around. + // + // 1. We are currently hyperpriv, return the address unmodified + // 2. The mmu is off return(ra->pa) + // 3. We are currently priv, use ctx0* tsbs to find the page + // 4. We are not priv, use ctxN0* tsbs to find the page + // For all accesses we check the tlbs first since it's possible that + // long standing pages (e.g. locked kernel mappings) won't be in the tsb + uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); + + bool hpriv = bits(tlbdata,0,0); + //bool priv = bits(tlbdata,2,2); + bool addr_mask = bits(tlbdata,3,3); + bool data_real = !bits(tlbdata,5,5); + bool inst_real = !bits(tlbdata,4,4); + bool ctx_zero = bits(tlbdata,18,16) > 0; + int part_id = bits(tlbdata,15,8); + int pri_context = bits(tlbdata,47,32); + //int sec_context = bits(tlbdata,63,48); - Addr vtophys(ThreadContext *tc, Addr addr) - { - // Here we have many options and are really implementing something like - // a fill handler to find the address since there isn't a multilevel - // table for us to walk around. - // - // 1. We are currently hyperpriv, return the address unmodified - // 2. The mmu is off return(ra->pa) - // 3. We are currently priv, use ctx0* tsbs to find the page - // 4. We are not priv, use ctxN0* tsbs to find the page - // For all accesses we check the tlbs first since it's possible that - // long standing pages (e.g. locked kernel mappings) won't be in the tsb - uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); - - bool hpriv = bits(tlbdata,0,0); - //bool priv = bits(tlbdata,2,2); - bool addr_mask = bits(tlbdata,3,3); - bool data_real = !bits(tlbdata,5,5); - bool inst_real = !bits(tlbdata,4,4); - bool ctx_zero = bits(tlbdata,18,16) > 0; - int part_id = bits(tlbdata,15,8); - int pri_context = bits(tlbdata,47,32); - //int sec_context = bits(tlbdata,63,48); - - FunctionalPort *mem = tc->getPhysPort(); - ITB* itb = tc->getITBPtr(); - DTB* dtb = tc->getDTBPtr(); - TlbEntry* tbe; - PageTableEntry pte; - Addr tsbs[4]; - Addr va_tag; - TteTag ttetag; - - if (hpriv) - return addr; - - if (addr_mask) - addr = addr & VAddrAMask; - - tbe = dtb->lookup(addr, part_id, data_real, ctx_zero ? 0 : pri_context , false); - if (tbe) goto foundtbe; - - tbe = itb->lookup(addr, part_id, inst_real, ctx_zero ? 0 : pri_context, false); - if (tbe) goto foundtbe; - - // We didn't find it in the tlbs, so lets look at the TSBs - dtb->GetTsbPtr(tc, addr, ctx_zero ? 0 : pri_context, tsbs); - va_tag = bits(addr, 63, 22); - for (int x = 0; x < 4; x++) { - ttetag = betoh(mem->read<uint64_t>(tsbs[x])); - if (ttetag.valid() && ttetag.va() == va_tag) { - pte.populate(betoh(mem->read<uint64_t>(tsbs[x]) + sizeof(uint64_t)), - PageTableEntry::sun4v); // I think it's sun4v at least! - DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TTE\n", addr, - pte.paddrMask() | addr & pte.sizeMask()); - goto foundpte; - } + FunctionalPort *mem = tc->getPhysPort(); + ITB* itb = tc->getITBPtr(); + DTB* dtb = tc->getDTBPtr(); + TlbEntry* tbe; + PageTableEntry pte; + Addr tsbs[4]; + Addr va_tag; + TteTag ttetag; + + if (hpriv) + return addr; + + if (addr_mask) + addr = addr & VAddrAMask; + + tbe = dtb->lookup(addr, part_id, data_real, ctx_zero ? 0 : pri_context , + false); + if (tbe) + goto foundtbe; + + tbe = itb->lookup(addr, part_id, inst_real, ctx_zero ? 0 : pri_context, + false); + if (tbe) + goto foundtbe; + + // We didn't find it in the tlbs, so lets look at the TSBs + dtb->GetTsbPtr(tc, addr, ctx_zero ? 0 : pri_context, tsbs); + va_tag = bits(addr, 63, 22); + for (int x = 0; x < 4; x++) { + ttetag = betoh(mem->read<uint64_t>(tsbs[x])); + if (ttetag.valid() && ttetag.va() == va_tag) { + uint64_t entry = mem->read<uint64_t>(tsbs[x]) + sizeof(uint64_t); + // I think it's sun4v at least! + pte.populate(betoh(entry), PageTableEntry::sun4v); + DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TTE\n", + addr, pte.translate(addr)); + goto foundpte; } - panic("couldn't translate %#x\n", addr); - -foundtbe: - pte = tbe->pte; - DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TLB\n", addr, - pte.paddrMask() | addr & pte.sizeMask()); -foundpte: - return pte.paddrMask() | addr & pte.sizeMask(); } + panic("couldn't translate %#x\n", addr); + + foundtbe: + pte = tbe->pte; + DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TLB\n", addr, + pte.translate(addr)); + foundpte: + return pte.translate(addr); } + +} /* namespace SparcISA */ diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index 674cd54c2..4c0460e28 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -86,6 +86,7 @@ Import('*') if env['TARGET_ISA'] == 'x86': + Source('cpuid.cc') Source('emulenv.cc') Source('floatregfile.cc') Source('faults.cc') @@ -105,16 +106,22 @@ if env['TARGET_ISA'] == 'x86': Source('utility.cc') SimObject('X86TLB.py') - TraceFlag('Predecoder') - TraceFlag('X86') + TraceFlag('Predecoder', "Predecoder debug output") + TraceFlag('X86', "Generic X86 ISA debugging") if env['FULL_SYSTEM']: + TraceFlag('LocalApic', "Local APIC debugging") + TraceFlag('PageTableWalker', \ + "Page table walker state machine debugging") + TraceFlag('Faults', "Trace all faults/exceptions/traps") + + SimObject('X86LocalApic.py') SimObject('X86System.py') # Full-system sources + Source('interrupts.cc') Source('linux/system.cc') Source('pagetable_walker.cc') - Source('smbios.cc') Source('system.cc') Source('stacktrace.cc') Source('vtophys.cc') @@ -170,7 +177,6 @@ if env['TARGET_ISA'] == 'x86': 'general_purpose/load_segment_registers.py', 'general_purpose/logical.py', 'general_purpose/no_operation.py', - 'general_purpose/processor_information.py', 'general_purpose/rotate_and_shift/__init__.py', 'general_purpose/rotate_and_shift/rotate.py', 'general_purpose/rotate_and_shift/shift.py', @@ -182,7 +188,9 @@ if env['TARGET_ISA'] == 'x86': 'general_purpose/string/scan_string.py', 'general_purpose/string/store_string.py', 'general_purpose/system_calls.py', + 'romutil.py', 'system/__init__.py', + 'system/control_registers.py', 'system/halt.py', 'system/invlpg.py', 'system/undefined_operation.py', diff --git a/src/arch/x86/SConsopts b/src/arch/x86/SConsopts index d8b7cbed1..f8b700271 100644 --- a/src/arch/x86/SConsopts +++ b/src/arch/x86/SConsopts @@ -3,43 +3,16 @@ # Copyright (c) 2007 The Hewlett-Packard Development Company # All rights reserved. # -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the -# following conditions are met: -# -# The software must be used only for Non-Commercial Use which means any -# use which is NOT directed to receiving any direct monetary -# compensation for, or commercial advantage from such use. Illustrative -# examples of non-commercial use are academic research, personal study, -# teaching, education and corporate research & development. -# Illustrative examples of commercial use are distributing products for -# commercial advantage and providing services using the software for -# commercial advantage. -# -# If you wish to use this software or functionality therein that may be -# covered by patents for commercial use, please contact: -# Director of Intellectual Property Licensing -# Office of Strategy and Technology -# Hewlett-Packard Company -# 1501 Page Mill Road -# Palo Alto, California 94304 -# -# Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. Redistributions -# in binary form must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. Neither the name of -# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. No right of -# sublicense is granted herewith. Derivatives of the software and -# output created using the software may be prepared, but only for -# Non-Commercial Uses. Derivatives of the software may be shared with -# others provided: (i) the others agree to abide by the list of -# conditions herein which includes the Non-Commercial Use restrictions; -# and (ii) such Derivatives of the software include the above copyright -# notice to acknowledge the contribution from this software where -# applicable, this list of conditions and the disclaimer below. +# this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/src/arch/x86/X86LocalApic.py b/src/arch/x86/X86LocalApic.py new file mode 100644 index 000000000..483c65ef8 --- /dev/null +++ b/src/arch/x86/X86LocalApic.py @@ -0,0 +1,36 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from Device import BasicPioDevice + +class X86LocalApic(BasicPioDevice): + type = 'X86LocalApic' + cxx_class = 'X86ISA::Interrupts' + pio_latency = Param.Latency('1ns', 'Programmed IO latency in simticks') + int_port = Port("Port for sending and receiving interrupt messages") diff --git a/src/arch/x86/X86System.py b/src/arch/x86/X86System.py index f73764540..527831205 100644 --- a/src/arch/x86/X86System.py +++ b/src/arch/x86/X86System.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -54,10 +54,27 @@ # Authors: Gabe Black from m5.params import * +from E820 import X86E820Table, X86E820Entry +from SMBios import X86SMBiosSMBiosTable +from IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable +from ACPI import X86ACPIRSDP from System import System class X86System(System): type = 'X86System' + smbios_table = Param.X86SMBiosSMBiosTable( + X86SMBiosSMBiosTable(), 'table of smbios/dmi information') + intel_mp_pointer = Param.X86IntelMPFloatingPointer( + X86IntelMPFloatingPointer(), + 'intel mp spec floating pointer structure') + intel_mp_table = Param.X86IntelMPConfigTable( + X86IntelMPConfigTable(), + 'intel mp spec configuration table') + acpi_description_table_pointer = Param.X86ACPIRSDP( + X86ACPIRSDP(), 'ACPI root description pointer structure') class LinuxX86System(X86System): type = 'LinuxX86System' + + e820_table = Param.X86E820Table( + X86E820Table(), 'E820 map of physical memory') diff --git a/src/arch/x86/X86TLB.py b/src/arch/x86/X86TLB.py index dc080f37e..d5ae95372 100644 --- a/src/arch/x86/X86TLB.py +++ b/src/arch/x86/X86TLB.py @@ -54,23 +54,20 @@ # Authors: Gabe Black from MemObject import MemObject -from m5.SimObject import SimObject from m5.params import * from m5.proxy import * from m5 import build_env +from BaseTLB import BaseTLB if build_env['FULL_SYSTEM']: class X86PagetableWalker(MemObject): type = 'X86PagetableWalker' - cxx_namespace = 'X86ISA' - cxx_class = 'Walker' + cxx_class = 'X86ISA::Walker' port = Port("Port for the hardware table walker") system = Param.System(Parent.any, "system object") -class X86TLB(SimObject): +class X86TLB(BaseTLB): type = 'X86TLB' - cxx_namespace = 'X86ISA' - cxx_class = 'TLB' abstract = True size = Param.Int("TLB size") if build_env['FULL_SYSTEM']: @@ -79,14 +76,10 @@ class X86TLB(SimObject): class X86DTB(X86TLB): type = 'X86DTB' - cxx_namespace = 'X86ISA' - cxx_class = 'DTB' - + cxx_class = 'X86ISA::DTB' size = 64 class X86ITB(X86TLB): type = 'X86ITB' - cxx_namespace = 'X86ISA' - cxx_class = 'ITB' - + cxx_class = 'X86ISA::ITB' size = 64 diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/arch/x86/apicregs.hh index 7497959e4..464c3af2d 100644 --- a/src/cpu/o3/sparc/thread_context.hh +++ b/src/arch/x86/apicregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,51 +28,64 @@ * Authors: Gabe Black */ -#include "arch/sparc/types.hh" -#include "cpu/o3/thread_context.hh" +#ifndef __ARCH_X86_APICREGS_HH__ +#define __ARCH_X86_APICREGS_HH__ -template <class Impl> -class SparcTC : public O3ThreadContext<Impl> +namespace X86ISA { - public: -#if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() + enum ApicRegIndex { - return this->thread->quiesceEvent; - } -#endif + APIC_ID, + APIC_VERSION, + APIC_TASK_PRIORITY, + APIC_ARBITRATION_PRIORITY, + APIC_PROCESSOR_PRIORITY, + APIC_EOI, + APIC_LOGICAL_DESTINATION, + APIC_DESTINATION_FORMAT, + APIC_SPURIOUS_INTERRUPT_VECTOR, - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } + APIC_IN_SERVICE_BASE, + + APIC_TRIGGER_MODE_BASE = APIC_IN_SERVICE_BASE + 16, + + APIC_INTERRUPT_REQUEST_BASE = APIC_TRIGGER_MODE_BASE + 16, + + APIC_ERROR_STATUS = APIC_INTERRUPT_REQUEST_BASE + 16, + APIC_INTERRUPT_COMMAND_LOW, + APIC_INTERRUPT_COMMAND_HIGH, + APIC_LVT_TIMER, + APIC_LVT_THERMAL_SENSOR, + APIC_LVT_PERFORMANCE_MONITORING_COUNTERS, + APIC_LVT_LINT0, + APIC_LVT_LINT1, + APIC_LVT_ERROR, + APIC_INITIAL_COUNT, + APIC_CURRENT_COUNT, + APIC_DIVIDE_CONFIGURATION, - virtual void setNextNPC(uint64_t val) + APIC_INTERNAL_STATE, + + NUM_APIC_REGS + }; + + static inline ApicRegIndex + APIC_IN_SERVICE(int index) { - this->cpu->setNextNPC(val, this->thread->readTid()); + return (ApicRegIndex)(APIC_IN_SERVICE_BASE + index); } - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) + static inline ApicRegIndex + APIC_TRIGGER_MODE(int index) { - //XXX Ignore this for now. This -really- needs to get fixed. + return (ApicRegIndex)(APIC_TRIGGER_MODE_BASE + index); } - - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() + static inline ApicRegIndex + APIC_INTERRUPT_REQUEST(int index) { - this->deallocate(); - - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation + return (ApicRegIndex)(APIC_INTERRUPT_REQUEST_BASE + index); } -}; +} + +#endif diff --git a/src/arch/x86/bios/ACPI.py b/src/arch/x86/bios/ACPI.py new file mode 100644 index 000000000..6f7cae946 --- /dev/null +++ b/src/arch/x86/bios/ACPI.py @@ -0,0 +1,99 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +# ACPI description table header. Subclasses contain and handle the actual +# contents as appropriate for that type of table. +class X86ACPISysDescTable(SimObject): + type = 'X86ACPISysDescTable' + cxx_class = 'X86ISA::ACPI::SysDescTable' + abstract = True + + oem_id = Param.String('', 'string identifying the oem') + oem_table_id = Param.String('', 'oem table ID') + oem_revision = Param.UInt32(0, 'oem revision number for the table') + + creator_id = Param.String('', + 'string identifying the generator of the table') + creator_revision = Param.UInt32(0, + 'revision number for the creator of the table') + +class X86ACPIRSDT(X86ACPISysDescTable): + type = 'X86ACPIRSDT' + cxx_class = 'X86ISA::ACPI::RSDT' + + entries = VectorParam.X86ACPISysDescTable([], 'system description tables') + +class X86ACPIXSDT(X86ACPISysDescTable): + type = 'X86ACPIXSDT' + cxx_class = 'X86ISA::ACPI::XSDT' + + entries = VectorParam.X86ACPISysDescTable([], 'system description tables') + +# Root System Description Pointer Structure +class X86ACPIRSDP(SimObject): + type = 'X86ACPIRSDP' + cxx_class = 'X86ISA::ACPI::RSDP' + + oem_id = Param.String('', 'string identifying the oem') + # Because 0 encodes ACPI 1.0, 2 encodes ACPI 3.0, the version implemented + # here. + revision = Param.UInt8(2, 'revision of ACPI being used, zero indexed') + + rsdt = Param.X86ACPIRSDT(NULL, 'root system description table') + xsdt = Param.X86ACPIXSDT(X86ACPIXSDT(), + 'extended system description table') diff --git a/src/arch/x86/bios/E820.py b/src/arch/x86/bios/E820.py new file mode 100644 index 000000000..288c253fb --- /dev/null +++ b/src/arch/x86/bios/E820.py @@ -0,0 +1,71 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86E820Entry(SimObject): + type = 'X86E820Entry' + cxx_class = 'X86ISA::E820Entry' + + addr = Param.Addr(0, 'address of the beginning of the region') + size = Param.MemorySize('0B', 'size of the region') + range_type = Param.UInt64('type of the region') + +class X86E820Table(SimObject): + type = 'X86E820Table' + cxx_class = 'X86ISA::E820Table' + + entries = VectorParam.X86E820Entry([], 'entries for the e820 table') diff --git a/src/arch/x86/bios/IntelMP.py b/src/arch/x86/bios/IntelMP.py new file mode 100644 index 000000000..04e79b6ac --- /dev/null +++ b/src/arch/x86/bios/IntelMP.py @@ -0,0 +1,242 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86IntelMPFloatingPointer(SimObject): + type = 'X86IntelMPFloatingPointer' + cxx_class = 'X86ISA::IntelMP::FloatingPointer' + + # The minor revision of the spec to support. The major version is assumed + # to be 1 in accordance with the spec. + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + # If no default configuration is used, set this to 0. + default_config = Param.UInt8(0, 'which default configuration to use') + imcr_present = Param.Bool(True, + 'whether the IMCR register is present in the APIC') + +class X86IntelMPConfigTable(SimObject): + type = 'X86IntelMPConfigTable' + cxx_class = 'X86ISA::IntelMP::ConfigTable' + + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + oem_id = Param.String("", 'system manufacturer') + product_id = Param.String("", 'product family') + oem_table_addr = Param.UInt32(0, + 'pointer to the optional oem configuration table') + oem_table_size = Param.UInt16(0, 'size of the oem configuration table') + local_apic = Param.UInt32(0xFEE00000, 'address of the local APIC') + + base_entries = VectorParam.X86IntelMPBaseConfigEntry([], + 'base configuration table entries') + + ext_entries = VectorParam.X86IntelMPExtConfigEntry([], + 'extended configuration table entries') + + def add_entry(self, entry): + if isinstance(entry, X86IntelMPBaseConfigEntry): + self.base_entries.append(entry) + elif isinstance(entry, X86IntelMPExtConfigEntry): + self.ext_entries.append(entry) + else: + panic("Don't know what type of Intel MP entry %s is." \ + % entry.__class__.__name__) + +class X86IntelMPBaseConfigEntry(SimObject): + type = 'X86IntelMPBaseConfigEntry' + cxx_class = 'X86ISA::IntelMP::BaseConfigEntry' + abstract = True + +class X86IntelMPExtConfigEntry(SimObject): + type = 'X86IntelMPExtConfigEntry' + cxx_class = 'X86ISA::IntelMP::ExtConfigEntry' + abstract = True + +class X86IntelMPProcessor(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPProcessor' + cxx_class = 'X86ISA::IntelMP::Processor' + + local_apic_id = Param.UInt8(0, 'local APIC id') + local_apic_version = Param.UInt8(0, + 'bits 0-7 of the local APIC version register') + enable = Param.Bool(True, 'if this processor is usable') + bootstrap = Param.Bool(False, 'if this is the bootstrap processor') + + stepping = Param.UInt8(0, 'Processor stepping') + model = Param.UInt8(0, 'Processor model') + family = Param.UInt8(0, 'Processor family') + + feature_flags = Param.UInt32(0, 'flags returned by the CPUID instruction') + +class X86IntelMPBus(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPBus' + cxx_class = 'X86ISA::IntelMP::Bus' + + bus_id = Param.UInt8(0, 'bus id assigned by the bios') + bus_type = Param.String("", 'string that identify the bus type') + # Legal values for bus_type are: + # + # "CBUS", "CBUSII", "EISA", "FUTURE", "INTERN", "ISA", "MBI", "MBII", + # "MCA", "MPI", "MPSA", "NUBUS", "PCI", "PCMCIA", "TC", "VL", "VME", + # "XPRESS" + +class X86IntelMPIOAPIC(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOAPIC' + cxx_class = 'X86ISA::IntelMP::IOAPIC' + + id = Param.UInt8(0, 'id of this APIC') + version = Param.UInt8(0, 'bits 0-7 of the version register') + + enable = Param.Bool(True, 'if this APIC is usable') + + address = Param.UInt32(0xfec00000, 'address of this APIC') + +class X86IntelMPInterruptType(Enum): + map = {'INT' : 0, + 'NMI' : 1, + 'SMI' : 2, + 'ExtInt' : 3 + } + +class X86IntelMPPolarity(Enum): + map = {'ConformPolarity' : 0, + 'ActiveHigh' : 1, + 'ActiveLow' : 3 + } + +class X86IntelMPTriggerMode(Enum): + map = {'ConformTrigger' : 0, + 'EdgeTrigger' : 1, + 'LevelTrigger' : 3 + } + +class X86IntelMPIOIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOIntAssignment' + cxx_class = 'X86ISA::IntelMP::IOIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_io_apic_id = Param.UInt8(0, + 'id of the IO APIC the interrupt is going to') + dest_io_apic_intin = Param.UInt8(0, + 'the INTIN pin on the IO APIC the interrupt is connected to') + +class X86IntelMPLocalIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPLocalIntAssignment' + cxx_class = 'X86ISA::IntelMP::LocalIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_local_apic_id = Param.UInt8(0, + 'id of the local APIC the interrupt is going to') + dest_local_apic_intin = Param.UInt8(0, + 'the INTIN pin on the local APIC the interrupt is connected to') + +class X86IntelMPAddressType(Enum): + map = {"IOAddress" : 0, + "MemoryAddress" : 1, + "PrefetchAddress" : 2 + } + +class X86IntelMPAddrSpaceMapping(X86IntelMPExtConfigEntry): + type = 'X86IntelMPAddrSpaceMapping' + cxx_class = 'X86ISA::IntelMP::AddrSpaceMapping' + + bus_id = Param.UInt8(0, 'id of the bus the address space is mapped to') + address_type = Param.X86IntelMPAddressType('IOAddress', + 'address type used to access bus') + address = Param.Addr(0, 'starting address of the mapping') + length = Param.UInt64(0, 'length of mapping in bytes') + +class X86IntelMPBusHierarchy(X86IntelMPExtConfigEntry): + type = 'X86IntelMPBusHierarchy' + cxx_class = 'X86ISA::IntelMP::BusHierarchy' + + bus_id = Param.UInt8(0, 'id of the bus being described') + subtractive_decode = Param.Bool(False, + 'whether this bus contains all addresses not used by its children') + parent_bus = Param.UInt8(0, 'bus id of this busses parent') + +class X86IntelMPRangeList(Enum): + map = {"ISACompatible" : 0, + "VGACompatible" : 1 + } + +class X86IntelMPCompatAddrSpaceMod(X86IntelMPExtConfigEntry): + type = 'X86IntelMPCompatAddrSpaceMod' + cxx_class = 'X86ISA::IntelMP::CompatAddrSpaceMod' + + bus_id = Param.UInt8(0, 'id of the bus being described') + add = Param.Bool(False, + 'if the range should be added to the original mapping') + range_list = Param.X86IntelMPRangeList('ISACompatible', + 'which predefined range of addresses to use') diff --git a/src/arch/x86/bios/SConscript b/src/arch/x86/bios/SConscript new file mode 100644 index 000000000..912d6599c --- /dev/null +++ b/src/arch/x86/bios/SConscript @@ -0,0 +1,77 @@ +# -*- mode:python -*- + +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +Import('*') + +if env['TARGET_ISA'] == 'x86': + if env['FULL_SYSTEM']: + # The table generated by the bootloader using the BIOS and passed to + # the operating system which maps out physical memory. + SimObject('E820.py') + Source('e820.cc') + + # The DMI tables. + SimObject('SMBios.py') + Source('smbios.cc') + + # Intel Multiprocessor Specification Configuration Table + SimObject('IntelMP.py') + Source('intelmp.cc') + + # ACPI system description tables + SimObject('ACPI.py') + Source('acpi.cc') diff --git a/src/arch/x86/bios/SMBios.py b/src/arch/x86/bios/SMBios.py new file mode 100644 index 000000000..4947b2854 --- /dev/null +++ b/src/arch/x86/bios/SMBios.py @@ -0,0 +1,140 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. Redistributions +# in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. Neither the name of +# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +class X86SMBiosSMBiosStructure(SimObject): + type = 'X86SMBiosSMBiosStructure' + cxx_class = 'X86ISA::SMBios::SMBiosStructure' + abstract = True + +class Characteristic(Enum): + map = {'Unknown' : 2, + 'Unsupported' : 3, + 'ISA' : 4, + 'MCA' : 5, + 'EISA' : 6, + 'PCI' : 7, + 'PCMCIA' : 8, + 'PnP' : 9, + 'APM' : 10, + 'Flash' : 11, + 'Shadow' : 12, + 'VL_Vesa' : 13, + 'ESCD' : 14, + 'CDBoot' : 15, + 'SelectBoot' : 16, + 'Socketed' : 17, + 'PCMCIABoot' : 18, + 'EDD' : 19, + 'NEC9800' : 20, + 'Toshiba' : 21, + 'Floppy_5_25_360KB' : 22, + 'Floppy_5_25_1_2MB' : 23, + 'Floppy_3_5_720KB' : 24, + 'Floppy_3_5_2_88MB' : 25, + 'PrintScreen' : 26, + 'Keyboard8024' : 27, + 'Serial' : 28, + 'Printer' : 29, + 'CGA_Mono' : 30, + 'NEC_PC_98' : 31 + } + +class ExtCharacteristic(Enum): + map = {'ACPI' : 0, + 'USBLegacy' : 1, + 'AGP' : 2, + 'I20Boot' : 3, + 'LS_120Boot' : 4, + 'ZIPBoot' : 5, + 'FirewireBoot' : 6, + 'SmartBattery' : 7, + 'BootSpec' : 8, + 'NetServiceBoot' : 9, + 'TargetContent' : 10 + } + +class X86SMBiosBiosInformation(X86SMBiosSMBiosStructure): + type = 'X86SMBiosBiosInformation' + cxx_class = 'X86ISA::SMBios::BiosInformation' + + vendor = Param.String("", "vendor name string") + version = Param.String("", "version string") + starting_addr_segment = \ + Param.UInt16(0, "segment location of bios starting address") + release_date = Param.String("06/08/2008", "release date") + rom_size = Param.UInt8(0, "rom size") + characteristics = VectorParam.Characteristic([], + "bios characteristic bit vector") + characteristic_ext_bytes = VectorParam.ExtCharacteristic([], + "extended bios characteristic bit vector") + major = Param.UInt8(0, "major version number") + minor = Param.UInt8(0, "minor version number") + emb_cont_firmware_major = Param.UInt8(0, + "embedded controller firmware major version number") + + emb_cont_firmware_minor = Param.UInt8(0, + "embedded controller firmware minor version number") + +class X86SMBiosSMBiosTable(SimObject): + type = 'X86SMBiosSMBiosTable' + cxx_class = 'X86ISA::SMBios::SMBiosTable' + + major_version = Param.UInt8(2, "major version number") + minor_version = Param.UInt8(5, "minor version number") + + structures = VectorParam.X86SMBiosSMBiosStructure([], "smbios structures") diff --git a/src/arch/x86/bios/acpi.cc b/src/arch/x86/bios/acpi.cc new file mode 100644 index 000000000..15b3901eb --- /dev/null +++ b/src/arch/x86/bios/acpi.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/acpi.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" +#include "sim/sim_object.hh" + +#include "params/X86ACPIRSDP.hh" + +#include "params/X86ACPISysDescTable.hh" +#include "params/X86ACPIRSDT.hh" +#include "params/X86ACPIXSDT.hh" + +using namespace std; + +const char X86ISA::ACPI::RSDP::signature[] = "RSD PTR "; + +X86ISA::ACPI::RSDP::RSDP(Params *p) : SimObject(p), oemID(p->oem_id), + revision(p->revision), rsdt(p->rsdt), xsdt(p->xsdt) +{} + +X86ISA::ACPI::SysDescTable::SysDescTable(Params *p, + const char * _signature, uint8_t _revision) : SimObject(p), + signature(_signature), revision(_revision), + oemID(p->oem_id), oemTableID(p->oem_table_id), + oemRevision(p->oem_revision), + creatorID(p->creator_id), creatorRevision(p->creator_revision) +{} + +X86ISA::ACPI::RSDT::RSDT(Params *p) : + SysDescTable(p, "RSDT", 1), entries(p->entries) +{} + +X86ISA::ACPI::XSDT::XSDT(Params *p) : + SysDescTable(p, "XSDT", 1), entries(p->entries) +{} + +X86ISA::ACPI::RSDP * +X86ACPIRSDPParams::create() +{ + return new X86ISA::ACPI::RSDP(this); +} + +X86ISA::ACPI::RSDT * +X86ACPIRSDTParams::create() +{ + return new X86ISA::ACPI::RSDT(this); +} + +X86ISA::ACPI::XSDT * +X86ACPIXSDTParams::create() +{ + return new X86ISA::ACPI::XSDT(this); +} diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh new file mode 100644 index 000000000..7bca17790 --- /dev/null +++ b/src/arch/x86/bios/acpi.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_BIOS_ACPI_HH__ +#define __ARCH_X86_BIOS_ACPI_HH__ + +#include "sim/host.hh" +#include "sim/sim_object.hh" + +#include <vector> +#include <string> + +class Port; + +class X86ACPIRSDPParams; + +class X86ACPISysDescTableParams; +class X86ACPIRSDTParams; +class X86ACPIXSDTParams; + +namespace X86ISA +{ + +namespace ACPI +{ + +class RSDT; +class XSDT; +class SysDescTable; + +class RSDP : public SimObject +{ + protected: + typedef X86ACPIRSDPParams Params; + + static const char signature[]; + + std::string oemID; + uint8_t revision; + + RSDT * rsdt; + XSDT * xsdt; + + public: + RSDP(Params *p); +}; + +class SysDescTable : public SimObject +{ + protected: + typedef X86ACPISysDescTableParams Params; + + const char * signature; + uint8_t revision; + + std::string oemID; + std::string oemTableID; + uint32_t oemRevision; + + std::string creatorID; + uint32_t creatorRevision; + + public: + SysDescTable(Params *p, const char * _signature, uint8_t _revision); +}; + +class RSDT : public SysDescTable +{ + protected: + typedef X86ACPIRSDTParams Params; + + std::vector<SysDescTable *> entries; + + public: + RSDT(Params *p); +}; + +class XSDT : public SysDescTable +{ + protected: + typedef X86ACPIXSDTParams Params; + + std::vector<SysDescTable *> entries; + + public: + XSDT(Params *p); +}; + +} // namespace ACPI + +} // namespace X86ISA + +#endif // __ARCH_X86_BIOS_E820_HH__ diff --git a/src/arch/x86/bios/e820.cc b/src/arch/x86/bios/e820.cc new file mode 100644 index 000000000..47adb703a --- /dev/null +++ b/src/arch/x86/bios/e820.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/e820.hh" +#include "arch/x86/isa_traits.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" + +using namespace std; +using namespace X86ISA; + +template<class T> +void writeVal(T val, Port * port, Addr &addr) +{ + T guestVal = htog(val); + port->writeBlob(addr, (uint8_t *)&guestVal, sizeof(T)); + addr += sizeof(T); +} + +void X86ISA::E820Table::writeTo(Port * port, Addr countAddr, Addr addr) +{ + uint8_t e820Nr = entries.size(); + + // Make sure the number of entries isn't bigger than what the kernel + // would be capable of handling. + assert(e820Nr <= 128); + + uint8_t guestE820Nr = htog(e820Nr); + + port->writeBlob(countAddr, (uint8_t *)&guestE820Nr, sizeof(guestE820Nr)); + + for (int i = 0; i < e820Nr; i++) { + writeVal(entries[i]->addr, port, addr); + writeVal(entries[i]->size, port, addr); + writeVal(entries[i]->type, port, addr); + } +} + +E820Table * +X86E820TableParams::create() +{ + return new E820Table(this); +} + +E820Entry * +X86E820EntryParams::create() +{ + return new E820Entry(this); +} diff --git a/src/arch/x86/syscallreturn.hh b/src/arch/x86/bios/e820.hh index 6a7fdba58..da738343b 100644 --- a/src/arch/x86/syscallreturn.hh +++ b/src/arch/x86/bios/e820.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -55,20 +55,46 @@ * Authors: Gabe Black */ -#ifndef __ARCH_X86_SYSCALLRETURN_HH__ -#define __ARCH_X86_SYSCALLRETURN_HH__ +#ifndef __ARCH_X86_BIOS_E820_HH__ +#define __ARCH_X86_BIOS_E820_HH__ -#include "base/misc.hh" -#include "cpu/thread_context.hh" -#include "sim/syscallreturn.hh" +#include "params/X86E820Entry.hh" +#include "params/X86E820Table.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +#include <vector> + +class Port; namespace X86ISA { - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext * tc) + class E820Entry : public SimObject { - tc->setIntReg(INTREG_RAX, return_value.value()); - } + public: + Addr addr; + Addr size; + uint32_t type; + + public: + typedef X86E820EntryParams Params; + E820Entry(Params *p) : + SimObject(p), addr(p->addr), size(p->size), type(p->range_type) + {} + }; + + class E820Table : public SimObject + { + public: + std::vector<E820Entry *> entries; + + public: + typedef X86E820TableParams Params; + E820Table(Params *p) : SimObject(p), entries(p->entries) + {} + + void writeTo(Port * port, Addr countAddr, Addr addr); + }; }; -#endif // __ARCH_X86_SYSCALLRETURN_HH__ +#endif // __ARCH_X86_BIOS_E820_HH__ diff --git a/src/arch/x86/bios/intelmp.cc b/src/arch/x86/bios/intelmp.cc new file mode 100644 index 000000000..2332e7a5c --- /dev/null +++ b/src/arch/x86/bios/intelmp.cc @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/bios/intelmp.hh" +#include "arch/x86/isa_traits.hh" +#include "base/misc.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" +#include "sim/host.hh" + +// Config entry types +#include "params/X86IntelMPBaseConfigEntry.hh" +#include "params/X86IntelMPExtConfigEntry.hh" + +// General table structures +#include "params/X86IntelMPConfigTable.hh" +#include "params/X86IntelMPFloatingPointer.hh" + +// Base entry types +#include "params/X86IntelMPBus.hh" +#include "params/X86IntelMPIOAPIC.hh" +#include "params/X86IntelMPIOIntAssignment.hh" +#include "params/X86IntelMPLocalIntAssignment.hh" +#include "params/X86IntelMPProcessor.hh" + +// Extended entry types +#include "params/X86IntelMPAddrSpaceMapping.hh" +#include "params/X86IntelMPBusHierarchy.hh" +#include "params/X86IntelMPCompatAddrSpaceMod.hh" + +using namespace std; + +const char X86ISA::IntelMP::FloatingPointer::signature[] = "_MP_"; + +template<class T> +uint8_t +writeOutField(FunctionalPort * port, Addr addr, T val) +{ + T guestVal = X86ISA::htog(val); + port->writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T)); + + uint8_t checkSum = 0; + while(guestVal) { + checkSum += guestVal; + guestVal >>= 8; + } + return checkSum; +} + +uint8_t +writeOutString(FunctionalPort * port, Addr addr, string str, int length) +{ + char cleanedString[length + 1]; + cleanedString[length] = 0; + + if (str.length() > length) { + memcpy(cleanedString, str.c_str(), length); + warn("Intel MP configuration table string \"%s\" " + "will be truncated to \"%s\".\n", str, cleanedString); + } else { + memcpy(cleanedString, str.c_str(), str.length()); + memset(cleanedString + str.length(), 0, length - str.length()); + } + port->writeBlob(addr, (uint8_t *)(&cleanedString), length); + + uint8_t checkSum = 0; + for (int i = 0; i < length; i++) + checkSum += cleanedString[i]; + + return checkSum; +} + +Addr +X86ISA::IntelMP::FloatingPointer::writeOut(FunctionalPort * port, Addr addr) +{ + // Make sure that either a config table is present or a default + // configuration was found but not both. + if (!tableAddr && !defaultConfig) + fatal("Either an MP configuration table or a default configuration " + "must be used."); + if (tableAddr && defaultConfig) + fatal("Both an MP configuration table and a default configuration " + "were set."); + + uint8_t checkSum = 0; + + port->writeBlob(addr, (uint8_t *)signature, 4); + for (int i = 0; i < 4; i++) + checkSum += signature[i]; + + checkSum += writeOutField(port, addr + 4, tableAddr); + + // The length of the structure in paragraphs, aka 16 byte chunks. + uint8_t length = 1; + port->writeBlob(addr + 8, &length, 1); + checkSum += length; + + port->writeBlob(addr + 9, &specRev, 1); + checkSum += specRev; + + port->writeBlob(addr + 11, &defaultConfig, 1); + checkSum += defaultConfig; + + uint32_t features2_5 = imcrPresent ? (1 << 7) : 0; + checkSum += writeOutField(port, addr + 12, features2_5); + + checkSum = -checkSum; + port->writeBlob(addr + 10, &checkSum, 1); + + return 16; +} + +X86ISA::IntelMP::FloatingPointer::FloatingPointer(Params * p) : + SimObject(p), tableAddr(0), specRev(p->spec_rev), + defaultConfig(p->default_config), imcrPresent(p->imcr_present) +{} + +X86ISA::IntelMP::FloatingPointer * +X86IntelMPFloatingPointerParams::create() +{ + return new X86ISA::IntelMP::FloatingPointer(this); +} + +Addr +X86ISA::IntelMP::BaseConfigEntry::writeOut(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->writeBlob(addr, &type, 1); + checkSum += type; + return 1; +} + +X86ISA::IntelMP::BaseConfigEntry::BaseConfigEntry(Params * p, uint8_t _type) : + SimObject(p), type(_type) +{} + +Addr +X86ISA::IntelMP::ExtConfigEntry::writeOut(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->writeBlob(addr, &type, 1); + checkSum += type; + port->writeBlob(addr + 1, &length, 1); + checkSum += length; + return 1; +} + +X86ISA::IntelMP::ExtConfigEntry::ExtConfigEntry(Params * p, + uint8_t _type, uint8_t _length) : + SimObject(p), type(_type), length(_length) +{} + +const char X86ISA::IntelMP::ConfigTable::signature[] = "PCMP"; + +Addr +X86ISA::IntelMP::ConfigTable::writeOut(FunctionalPort * port, Addr addr) +{ + uint8_t checkSum = 0; + + port->writeBlob(addr, (uint8_t *)signature, 4); + for (int i = 0; i < 4; i++) + checkSum += signature[i]; + + // Base table length goes here but will be calculated later. + + port->writeBlob(addr + 6, (uint8_t *)(&specRev), 1); + checkSum += specRev; + + // The checksum goes here but is still being calculated. + + checkSum += writeOutString(port, addr + 8, oemID, 8); + checkSum += writeOutString(port, addr + 16, productID, 12); + + checkSum += writeOutField(port, addr + 28, oemTableAddr); + checkSum += writeOutField(port, addr + 32, oemTableSize); + checkSum += writeOutField(port, addr + 34, (uint16_t)baseEntries.size()); + checkSum += writeOutField(port, addr + 36, localApic); + + uint8_t reserved = 0; + port->writeBlob(addr + 43, &reserved, 1); + checkSum += reserved; + + vector<BaseConfigEntry *>::iterator baseEnt; + uint16_t offset = 44; + for (baseEnt = baseEntries.begin(); + baseEnt != baseEntries.end(); baseEnt++) { + offset += (*baseEnt)->writeOut(port, addr + offset, checkSum); + } + + // We've found the end of the base table this point. + checkSum += writeOutField(port, addr + 4, offset); + + vector<ExtConfigEntry *>::iterator extEnt; + uint16_t extOffset = 0; + uint8_t extCheckSum = 0; + for (extEnt = extEntries.begin(); + extEnt != extEntries.end(); extEnt++) { + extOffset += (*extEnt)->writeOut(port, + addr + offset + extOffset, extCheckSum); + } + + checkSum += writeOutField(port, addr + 40, extOffset); + extCheckSum = -extCheckSum; + checkSum += writeOutField(port, addr + 42, extCheckSum); + + // And now, we finally have the whole check sum completed. + checkSum = -checkSum; + writeOutField(port, addr + 7, checkSum); + + return offset + extOffset; +}; + +X86ISA::IntelMP::ConfigTable::ConfigTable(Params * p) : SimObject(p), + specRev(p->spec_rev), oemID(p->oem_id), productID(p->product_id), + oemTableAddr(p->oem_table_addr), oemTableSize(p->oem_table_size), + localApic(p->local_apic), + baseEntries(p->base_entries), extEntries(p->ext_entries) +{} + +X86ISA::IntelMP::ConfigTable * +X86IntelMPConfigTableParams::create() +{ + return new X86ISA::IntelMP::ConfigTable(this); +} + +Addr +X86ISA::IntelMP::Processor::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, localApicID); + checkSum += writeOutField(port, addr + 2, localApicVersion); + checkSum += writeOutField(port, addr + 3, cpuFlags); + checkSum += writeOutField(port, addr + 4, cpuSignature); + checkSum += writeOutField(port, addr + 8, featureFlags); + + uint32_t reserved = 0; + port->writeBlob(addr + 12, (uint8_t *)(&reserved), 4); + port->writeBlob(addr + 16, (uint8_t *)(&reserved), 4); + return 20; +} + +X86ISA::IntelMP::Processor::Processor(Params * p) : BaseConfigEntry(p, 0), + localApicID(p->local_apic_id), localApicVersion(p->local_apic_version), + cpuFlags(0), cpuSignature(0), featureFlags(p->feature_flags) +{ + if (p->enable) + cpuFlags |= (1 << 0); + if (p->bootstrap) + cpuFlags |= (1 << 1); + + replaceBits(cpuSignature, 0, 3, p->stepping); + replaceBits(cpuSignature, 4, 7, p->model); + replaceBits(cpuSignature, 8, 11, p->family); +} + +X86ISA::IntelMP::Processor * +X86IntelMPProcessorParams::create() +{ + return new X86ISA::IntelMP::Processor(this); +} + +Addr +X86ISA::IntelMP::Bus::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, busID); + checkSum += writeOutString(port, addr + 2, busType, 6); + return 8; +} + +X86ISA::IntelMP::Bus::Bus(Params * p) : BaseConfigEntry(p, 1), + busID(p->bus_id), busType(p->bus_type) +{} + +X86ISA::IntelMP::Bus * +X86IntelMPBusParams::create() +{ + return new X86ISA::IntelMP::Bus(this); +} + +Addr +X86ISA::IntelMP::IOAPIC::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, id); + checkSum += writeOutField(port, addr + 2, version); + checkSum += writeOutField(port, addr + 3, flags); + checkSum += writeOutField(port, addr + 4, address); + return 8; +} + +X86ISA::IntelMP::IOAPIC::IOAPIC(Params * p) : BaseConfigEntry(p, 2), + id(p->id), version(p->version), flags(0), address(p->address) +{ + if (p->enable) + flags |= 1; +} + +X86ISA::IntelMP::IOAPIC * +X86IntelMPIOAPICParams::create() +{ + return new X86ISA::IntelMP::IOAPIC(this); +} + +Addr +X86ISA::IntelMP::IntAssignment::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, interruptType); + checkSum += writeOutField(port, addr + 2, flags); + checkSum += writeOutField(port, addr + 4, sourceBusID); + checkSum += writeOutField(port, addr + 5, sourceBusIRQ); + checkSum += writeOutField(port, addr + 6, destApicID); + checkSum += writeOutField(port, addr + 7, destApicIntIn); + return 8; +} + +X86ISA::IntelMP::IOIntAssignment::IOIntAssignment(Params * p) : + IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 3, + p->source_bus_id, p->source_bus_irq, + p->dest_io_apic_id, p->dest_io_apic_intin) +{} + +X86ISA::IntelMP::IOIntAssignment * +X86IntelMPIOIntAssignmentParams::create() +{ + return new X86ISA::IntelMP::IOIntAssignment(this); +} + +X86ISA::IntelMP::LocalIntAssignment::LocalIntAssignment(Params * p) : + IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 4, + p->source_bus_id, p->source_bus_irq, + p->dest_local_apic_id, p->dest_local_apic_intin) +{} + +X86ISA::IntelMP::LocalIntAssignment * +X86IntelMPLocalIntAssignmentParams::create() +{ + return new X86ISA::IntelMP::LocalIntAssignment(this); +} + +Addr +X86ISA::IntelMP::AddrSpaceMapping::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, addrType); + checkSum += writeOutField(port, addr + 4, addr); + checkSum += writeOutField(port, addr + 12, addrLength); + return length; +} + +X86ISA::IntelMP::AddrSpaceMapping::AddrSpaceMapping(Params * p) : + ExtConfigEntry(p, 128, 20), + busID(p->bus_id), addrType(p->address_type), + addr(p->address), addrLength(p->length) +{} + +X86ISA::IntelMP::AddrSpaceMapping * +X86IntelMPAddrSpaceMappingParams::create() +{ + return new X86ISA::IntelMP::AddrSpaceMapping(this); +} + +Addr +X86ISA::IntelMP::BusHierarchy::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, info); + checkSum += writeOutField(port, addr + 4, parentBus); + + uint32_t reserved = 0; + port->writeBlob(addr + 5, (uint8_t *)(&reserved), 3); + + return length; +} + +X86ISA::IntelMP::BusHierarchy::BusHierarchy(Params * p) : + ExtConfigEntry(p, 129, 8), + busID(p->bus_id), info(0), parentBus(p->parent_bus) +{ + if (p->subtractive_decode) + info |= 1; +} + +X86ISA::IntelMP::BusHierarchy * +X86IntelMPBusHierarchyParams::create() +{ + return new X86ISA::IntelMP::BusHierarchy(this); +} + +Addr +X86ISA::IntelMP::CompatAddrSpaceMod::writeOut( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, mod); + checkSum += writeOutField(port, addr + 4, rangeList); + return length; +} + +X86ISA::IntelMP::CompatAddrSpaceMod::CompatAddrSpaceMod(Params * p) : + ExtConfigEntry(p, 130, 8), + busID(p->bus_id), mod(0), rangeList(p->range_list) +{ + if (p->add) + mod |= 1; +} + +X86ISA::IntelMP::CompatAddrSpaceMod * +X86IntelMPCompatAddrSpaceModParams::create() +{ + return new X86ISA::IntelMP::CompatAddrSpaceMod(this); +} diff --git a/src/arch/x86/bios/intelmp.hh b/src/arch/x86/bios/intelmp.hh new file mode 100644 index 000000000..e8d1d656e --- /dev/null +++ b/src/arch/x86/bios/intelmp.hh @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_BIOS_INTELMP_HH__ +#define __ARCH_X86_BIOS_INTELMP_HH__ + +#include <string> +#include <vector> + +#include "base/bitfield.hh" +#include "sim/sim_object.hh" + +#include "enums/X86IntelMPAddressType.hh" +#include "enums/X86IntelMPInterruptType.hh" +#include "enums/X86IntelMPPolarity.hh" +#include "enums/X86IntelMPRangeList.hh" +#include "enums/X86IntelMPTriggerMode.hh" + +class FunctionalPort; + +// Config entry types +class X86IntelMPBaseConfigEntryParams; +class X86IntelMPExtConfigEntryParams; + +// General table structures +class X86IntelMPConfigTableParams; +class X86IntelMPFloatingPointerParams; + +// Base entry types +class X86IntelMPBusParams; +class X86IntelMPIOAPICParams; +class X86IntelMPIOIntAssignmentParams; +class X86IntelMPLocalIntAssignmentParams; +class X86IntelMPProcessorParams; + +// Extended entry types +class X86IntelMPAddrSpaceMappingParams; +class X86IntelMPBusHierarchyParams; +class X86IntelMPCompatAddrSpaceModParams; + +namespace X86ISA +{ + +namespace IntelMP +{ + +class FloatingPointer : public SimObject +{ + protected: + typedef X86IntelMPFloatingPointerParams Params; + + uint32_t tableAddr; + uint8_t specRev; + uint8_t defaultConfig; + bool imcrPresent; + + static const char signature[]; + + public: + + Addr writeOut(FunctionalPort * port, Addr addr); + + Addr getTableAddr() + { + return tableAddr; + } + + void setTableAddr(Addr addr) + { + tableAddr = addr; + } + + FloatingPointer(Params * p); +}; + +class BaseConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPBaseConfigEntryParams Params; + + uint8_t type; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BaseConfigEntry(Params * p, uint8_t _type); +}; + +class ExtConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPExtConfigEntryParams Params; + + uint8_t type; + uint8_t length; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + ExtConfigEntry(Params * p, uint8_t _type, uint8_t _length); +}; + +class ConfigTable : public SimObject +{ + protected: + typedef X86IntelMPConfigTableParams Params; + + static const char signature[]; + + uint8_t specRev; + std::string oemID; + std::string productID; + uint32_t oemTableAddr; + uint16_t oemTableSize; + uint32_t localApic; + + std::vector<BaseConfigEntry *> baseEntries; + std::vector<ExtConfigEntry *> extEntries; + + public: + Addr writeOut(FunctionalPort * port, Addr addr); + + ConfigTable(Params * p); +}; + +class Processor : public BaseConfigEntry +{ + protected: + typedef X86IntelMPProcessorParams Params; + + uint8_t localApicID; + uint8_t localApicVersion; + uint8_t cpuFlags; + uint32_t cpuSignature; + uint32_t featureFlags; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Processor(Params * p); +}; + +class Bus : public BaseConfigEntry +{ + protected: + typedef X86IntelMPBusParams Params; + + uint8_t busID; + std::string busType; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Bus(Params * p); +}; + +class IOAPIC : public BaseConfigEntry +{ + protected: + typedef X86IntelMPIOAPICParams Params; + + uint8_t id; + uint8_t version; + uint8_t flags; + uint32_t address; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IOAPIC(Params * p); +}; + +class IntAssignment : public BaseConfigEntry +{ + protected: + uint8_t interruptType; + + uint16_t flags; + + uint8_t sourceBusID; + uint8_t sourceBusIRQ; + + uint8_t destApicID; + uint8_t destApicIntIn; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IntAssignment(X86IntelMPBaseConfigEntryParams * p, + Enums::X86IntelMPInterruptType _interruptType, + Enums::X86IntelMPPolarity polarity, + Enums::X86IntelMPTriggerMode trigger, + uint8_t _type, + uint8_t _sourceBusID, uint8_t _sourceBusIRQ, + uint8_t _destApicID, uint8_t _destApicIntIn) : + BaseConfigEntry(p, _type), + interruptType(_interruptType), flags(0), + sourceBusID(_sourceBusID), sourceBusIRQ(_sourceBusIRQ), + destApicID(_destApicID), destApicIntIn(_destApicIntIn) + { + replaceBits(flags, 0, 1, polarity); + replaceBits(flags, 2, 3, trigger); + } +}; + +class IOIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPIOIntAssignmentParams Params; + + public: + IOIntAssignment(Params * p); +}; + +class LocalIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPLocalIntAssignmentParams Params; + + public: + LocalIntAssignment(Params * p); +}; + +class AddrSpaceMapping : public ExtConfigEntry +{ + protected: + typedef X86IntelMPAddrSpaceMappingParams Params; + + uint8_t busID; + uint8_t addrType; + uint64_t addr; + uint64_t addrLength; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + AddrSpaceMapping(Params * p); +}; + +class BusHierarchy : public ExtConfigEntry +{ + protected: + typedef X86IntelMPBusHierarchyParams Params; + + uint8_t busID; + uint8_t info; + uint8_t parentBus; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BusHierarchy(Params * p); +}; + +class CompatAddrSpaceMod : public ExtConfigEntry +{ + protected: + typedef X86IntelMPCompatAddrSpaceModParams Params; + + uint8_t busID; + uint8_t mod; + uint32_t rangeList; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + CompatAddrSpaceMod(Params * p); +}; + +} //IntelMP + +} //X86ISA + +#endif diff --git a/src/arch/x86/smbios.cc b/src/arch/x86/bios/smbios.cc index 319650c1f..95ade1e4d 100644 --- a/src/arch/x86/smbios.cc +++ b/src/arch/x86/bios/smbios.cc @@ -85,12 +85,17 @@ * Authors: Gabe Black */ -#include "arch/x86/smbios.hh" +#include "arch/x86/bios/smbios.hh" #include "arch/x86/isa_traits.hh" #include "mem/port.hh" +#include "params/X86SMBiosBiosInformation.hh" +#include "params/X86SMBiosSMBiosStructure.hh" +#include "params/X86SMBiosSMBiosTable.hh" #include "sim/byteswap.hh" #include "sim/host.hh" +using namespace std; + const char X86ISA::SMBios::SMBiosTable::SMBiosHeader::anchorString[] = "_SM_"; const uint8_t X86ISA::SMBios::SMBiosTable:: SMBiosHeader::formattedArea[] = {0,0,0,0,0}; @@ -101,6 +106,116 @@ const uint8_t X86ISA::SMBios::SMBiosTable:: const char X86ISA::SMBios::SMBiosTable:: SMBiosHeader::IntermediateHeader::anchorString[] = "_DMI_"; +template <class T> +uint64_t +composeBitVector(T vec) +{ + uint64_t val = 0; + typename T::iterator vecIt; + for (vecIt = vec.begin(); vecIt != vec.end(); vecIt++) { + val |= (1 << (*vecIt)); + } + return val; +} + +uint16_t +X86ISA::SMBios::SMBiosStructure::writeOut(FunctionalPort * port, Addr addr) +{ + port->writeBlob(addr, (uint8_t *)(&type), 1); + + uint8_t length = getLength(); + port->writeBlob(addr + 1, (uint8_t *)(&length), 1); + + uint16_t handleGuest = X86ISA::htog(handle); + port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2); + + return length + getStringLength(); +} + +X86ISA::SMBios::SMBiosStructure::SMBiosStructure(Params * p, uint8_t _type) : + SimObject(p), type(_type), handle(0), stringFields(false) +{} + +void +X86ISA::SMBios::SMBiosStructure::writeOutStrings( + FunctionalPort * port, Addr addr) +{ + std::vector<std::string>::iterator it; + Addr offset = 0; + + const uint8_t nullTerminator = 0; + + // If there are string fields but none of them are used, that's a + // special case which is handled by this if. + if (strings.size() == 0 && stringFields) { + port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); + offset++; + } else { + for (it = strings.begin(); it != strings.end(); it++) { + port->writeBlob(addr + offset, + (uint8_t *)it->c_str(), it->length() + 1); + offset += it->length() + 1; + } + } + port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); +} + +int +X86ISA::SMBios::SMBiosStructure::getStringLength() +{ + int size = 0; + std::vector<std::string>::iterator it; + + for (it = strings.begin(); it != strings.end(); it++) { + size += it->length() + 1; + } + + return size + 1; +} + +int +X86ISA::SMBios::SMBiosStructure::addString(string & newString) +{ + stringFields = true; + // If a string is empty, treat it as not existing. The index for empty + // strings is 0. + if (newString.length() == 0) + return 0; + strings.push_back(newString); + return strings.size(); +} + +string +X86ISA::SMBios::SMBiosStructure::readString(int n) +{ + assert(n > 0 && n <= strings.size()); + return strings[n - 1]; +} + +void +X86ISA::SMBios::SMBiosStructure::setString(int n, std::string & newString) +{ + assert(n > 0 && n <= strings.size()); + strings[n - 1] = newString; +} + +X86ISA::SMBios::BiosInformation::BiosInformation(Params * p) : + SMBiosStructure(p, Type), + startingAddrSegment(p->starting_addr_segment), + romSize(p->rom_size), + majorVer(p->major), minorVer(p->minor), + embContFirmwareMajor(p->emb_cont_firmware_major), + embContFirmwareMinor(p->emb_cont_firmware_minor) + { + vendor = addString(p->vendor); + version = addString(p->version); + releaseDate = addString(p->release_date); + + characteristics = composeBitVector(p->characteristics); + characteristicExtBytes = + composeBitVector(p->characteristic_ext_bytes); + } + uint16_t X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) { @@ -122,8 +237,8 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) X86ISA::htog(characteristicExtBytes); port->writeBlob(addr + 0x12, (uint8_t *)(&characteristicExtBytesGuest), 2); - port->writeBlob(addr + 0x14, (uint8_t *)(&major), 1); - port->writeBlob(addr + 0x15, (uint8_t *)(&minor), 1); + port->writeBlob(addr + 0x14, (uint8_t *)(&majorVer), 1); + port->writeBlob(addr + 0x15, (uint8_t *)(&minorVer), 1); port->writeBlob(addr + 0x16, (uint8_t *)(&embContFirmwareMajor), 1); port->writeBlob(addr + 0x17, (uint8_t *)(&embContFirmwareMinor), 1); @@ -132,9 +247,22 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr) return size; } +X86ISA::SMBios::SMBiosTable::SMBiosTable(Params * p) : + SimObject(p), structures(p->structures) +{ + smbiosHeader.majorVersion = p->major_version; + smbiosHeader.minorVersion = p->minor_version; + assert(p->major_version <= 9); + assert(p->minor_version <= 9); + smbiosHeader.intermediateHeader.smbiosBCDRevision = + (p->major_version << 4) | p->minor_version; +} + void -X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) +X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr, + Addr &headerSize, Addr &structSize) { + headerSize = 0x1F; /* * The main header @@ -205,14 +333,16 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) Addr base = smbiosHeader.intermediateHeader.tableAddr; Addr offset = 0; uint16_t maxSize = 0; - std::vector<SMBiosStructure>::iterator it; + std::vector<SMBiosStructure *>::iterator it; for (it = structures.begin(); it != structures.end(); it++) { - uint16_t size = it->writeOut(port, base + offset); + uint16_t size = (*it)->writeOut(port, base + offset); if (size > maxSize) maxSize = size; offset += size; } + structSize = offset; + /* * Header */ @@ -243,3 +373,15 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr) intChecksum = -intChecksum; port->writeBlob(addr + 0x15, (uint8_t *)(&intChecksum), 1); } + +X86ISA::SMBios::BiosInformation * +X86SMBiosBiosInformationParams::create() +{ + return new X86ISA::SMBios::BiosInformation(this); +} + +X86ISA::SMBios::SMBiosTable * +X86SMBiosSMBiosTableParams::create() +{ + return new X86ISA::SMBios::SMBiosTable(this); +} diff --git a/src/arch/x86/smbios.hh b/src/arch/x86/bios/smbios.hh index c126de220..1c50d0b48 100644 --- a/src/arch/x86/smbios.hh +++ b/src/arch/x86/bios/smbios.hh @@ -85,16 +85,21 @@ * Authors: Gabe Black */ -#ifndef __ARCH_X86_SMBIOS_HH__ -#define __ARCH_X86_SMBIOS_HH__ +#ifndef __ARCH_X86_BIOS_SMBIOS_HH__ +#define __ARCH_X86_BIOS_SMBIOS_HH__ #include <string> #include <vector> -#include "arch/x86/isa_traits.hh" -#include "mem/port.hh" -#include "sim/byteswap.hh" +#include "enums/Characteristic.hh" +#include "enums/ExtCharacteristic.hh" #include "sim/host.hh" +#include "sim/sim_object.hh" + +class FunctionalPort; +class X86SMBiosBiosInformationParams; +class X86SMBiosSMBiosStructureParams; +class X86SMBiosSMBiosTableParams; namespace X86ISA { @@ -102,8 +107,11 @@ namespace X86ISA namespace SMBios { -class SMBiosStructure +class SMBiosStructure : public SimObject { + protected: + typedef X86SMBiosSMBiosStructureParams Params; + public: virtual @@ -126,73 +134,33 @@ class SMBiosStructure return 4; } - virtual uint16_t - writeOut(FunctionalPort * port, Addr addr) - { - port->writeBlob(addr, (uint8_t *)(&type), 1); - - uint8_t length = getLength(); - port->writeBlob(addr + 1, (uint8_t *)(&length), 1); - - uint16_t handleGuest = X86ISA::htog(handle); - port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2); - - return length + getStringLength(); - } + virtual uint16_t writeOut(FunctionalPort * port, Addr addr); protected: - std::vector<std::string> strings; - - void writeOutStrings(FunctionalPort * port, Addr addr) - { - std::vector<std::string>::iterator it; - Addr offset = 0; - - for (it = strings.begin(); it != strings.end(); it++) { - port->writeBlob(addr + offset, - (uint8_t *)it->c_str(), it->length() + 1); - offset += it->length() + 1; - } + bool stringFields; - const uint8_t nullTerminator = 0; - port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1); - } + SMBiosStructure(Params * p, uint8_t _type); - int getStringLength() - { - int size = 0; - std::vector<std::string>::iterator it; + std::vector<std::string> strings; - for (it = strings.begin(); it != strings.end(); it++) { - size += it->length() + 1; - } + void writeOutStrings(FunctionalPort * port, Addr addr); - return size + 1; - } + int getStringLength(); public: - int addString(std::string & newString) - { - strings.push_back(newString); - return strings.size(); - } - - std::string readString(int n) - { - assert(n > 0 && n <= strings.size()); - return strings[n - 1]; - } - - void setString(int n, std::string & newString) - { - assert(n > 0 && n <= strings.size()); - strings[n - 1] = newString; - } + int addString(std::string & newString); + std::string readString(int n); + void setString(int n, std::string & newString); }; class BiosInformation : public SMBiosStructure { + protected: + const static uint8_t Type = 0; + + typedef X86SMBiosBiosInformationParams Params; + public: // Offset 04h, 1 byte uint8_t vendor; @@ -211,21 +179,25 @@ class BiosInformation : public SMBiosStructure // Offset 12h, 2 bytes uint16_t characteristicExtBytes; // Offset 14h, 1 byte - uint8_t major; + uint8_t majorVer; // Offset 15h, 1 byte - uint8_t minor; + uint8_t minorVer; // Offset 16h, 1 byte uint8_t embContFirmwareMajor; // Offset 17h, 1 byte uint8_t embContFirmwareMinor; + BiosInformation(Params * p); + uint8_t getLength() { return 0x18; } uint16_t writeOut(FunctionalPort * port, Addr addr); }; -class SMBiosTable +class SMBiosTable : public SimObject { - public: + protected: + typedef X86SMBiosSMBiosTableParams Params; + struct SMBiosHeader { SMBiosHeader() @@ -281,9 +253,23 @@ class SMBiosTable } intermediateHeader; } smbiosHeader; - void writeOut(FunctionalPort * port, Addr addr); + std::vector<SMBiosStructure *> structures; + + public: + SMBiosTable(Params * p); + + Addr getTableAddr() + { + return smbiosHeader.intermediateHeader.tableAddr; + } + + void setTableAddr(Addr addr) + { + smbiosHeader.intermediateHeader.tableAddr = addr; + } - std::vector<SMBiosStructure> structures; + void writeOut(FunctionalPort * port, Addr addr, + Addr &headerSize, Addr &structSize); }; } //SMBios diff --git a/src/arch/x86/cpuid.cc b/src/arch/x86/cpuid.cc new file mode 100644 index 000000000..247965df4 --- /dev/null +++ b/src/arch/x86/cpuid.cc @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/cpuid.hh" +#include "base/bitfield.hh" +#include "cpu/thread_context.hh" + +namespace X86ISA { + enum StandardCpuidFunction { + VendorAndLargestStdFunc, + FamilyModelStepping, + NumStandardCpuidFuncs + }; + + enum ExtendedCpuidFunctions { + VendorAndLargestExtFunc, + FamilyModelSteppingBrandFeatures, + NameString1, + NameString2, + NameString3, + L1CacheAndTLB, + L2L3CacheAndL2TLB, + APMInfo, + + /* + * The following are defined by the spec but not yet implemented + */ +/* LongModeAddressSize, + // Function 9 is reserved + SVMInfo = 10, + // Functions 11-24 are reserved + TLB1GBPageInfo = 25, + PerformanceInfo,*/ + + NumExtendedCpuidFuncs + }; + + static const int vendorStringSize = 13; + static const char vendorString[vendorStringSize] = "AuthenticAMD"; + static const int nameStringSize = 48; + static const char nameString[nameStringSize] = "Fake M5 x86_64 CPU"; + + uint64_t + stringToRegister(const char *str) + { + uint64_t reg = 0; + for (int pos = 3; pos >=0; pos--) { + reg <<= 8; + reg |= str[pos]; + } + return reg; + } + + bool + doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result) + { + uint16_t family = bits(function, 31, 16); + uint16_t funcNum = bits(function, 15, 0); + if (family == 0x8000) { + // The extended functions + switch (funcNum) { + case VendorAndLargestExtFunc: + assert(vendorStringSize >= 12); + result = CpuidResult( + NumExtendedCpuidFuncs - 1, + stringToRegister(vendorString), + stringToRegister(vendorString + 4), + stringToRegister(vendorString + 8)); + break; + case FamilyModelSteppingBrandFeatures: + result = CpuidResult(0x00020f51, 0x00000405, + 0xe3d3fbff, 0x00000001); + break; + case NameString1: + case NameString2: + case NameString3: + { + // Zero fill anything beyond the end of the string. This + // should go away once the string is a vetted parameter. + char cleanName[nameStringSize]; + memset(cleanName, '\0', nameStringSize); + strncpy(cleanName, nameString, nameStringSize); + + int offset = (funcNum - NameString1) * 16; + assert(nameStringSize >= offset + 16); + result = CpuidResult( + stringToRegister(cleanName + offset + 0), + stringToRegister(cleanName + offset + 4), + stringToRegister(cleanName + offset + 8), + stringToRegister(cleanName + offset + 12)); + } + break; + case L1CacheAndTLB: + result = CpuidResult(0xff08ff08, 0xff20ff20, + 0x40020140, 0x40020140); + break; + case L2L3CacheAndL2TLB: + result = CpuidResult(0x00000000, 0x42004200, + 0x00000000, 0x04008140); + break; + case APMInfo: + result = CpuidResult(0x80000018, 0x68747541, + 0x69746e65, 0x444d4163); + break; +/* case LongModeAddressSize: + case SVMInfo: + case TLB1GBPageInfo: + case PerformanceInfo:*/ + default: + return false; + } + } else if(family == 0x0000) { + // The standard functions + switch (funcNum) { + case VendorAndLargestStdFunc: + assert(vendorStringSize >= 12); + result = CpuidResult( + NumStandardCpuidFuncs - 1, + stringToRegister(vendorString), + stringToRegister(vendorString + 4), + stringToRegister(vendorString + 8)); + break; + case FamilyModelStepping: + result = CpuidResult(0x00020f51, 0000000405, + 0xe3d3fbff, 0x00000001); + break; + default: + return false; + } + } + return true; + } +} //namespace X86ISA diff --git a/src/arch/x86/cpuid.hh b/src/arch/x86/cpuid.hh new file mode 100644 index 000000000..5cb4c7972 --- /dev/null +++ b/src/arch/x86/cpuid.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_CPUID_HH__ +#define __ARCH_X86_CPUID_HH__ + +#include <inttypes.h> + +class ThreadContext; + +namespace X86ISA +{ + struct CpuidResult + { + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + + // These are not in alphebetical order on purpose. The order reflects + // how the CPUID orders the registers when it returns results. + CpuidResult(uint64_t _rax, uint64_t _rbx, + uint64_t _rdx, uint64_t _rcx) : + rax(_rax), rbx(_rbx), rcx(_rcx), rdx(_rdx) + {} + + CpuidResult() + {} + }; + + bool doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result); +} // namespace X86ISA + +#endif diff --git a/src/arch/x86/emulenv.cc b/src/arch/x86/emulenv.cc index 31b705d79..0d7b32130 100644 --- a/src/arch/x86/emulenv.cc +++ b/src/arch/x86/emulenv.cc @@ -55,6 +55,8 @@ * Authors: Gabe Black */ +#include <cassert> + #include "arch/x86/emulenv.hh" #include "base/misc.hh" @@ -91,7 +93,7 @@ void EmulEnv::doModRM(const ExtMachInst & machInst) //Figure out what segment to use. This won't be entirely accurate since //the presence of a displacement is supposed to make the instruction //default to the data segment. - if (base != INTREG_RBP && base != INTREG_RSP || + if ((base != INTREG_RBP && base != INTREG_RSP) || 0/*Has an immediate offset*/) { seg = SEGMENT_REG_DS; //Handle any segment override that might have been in the instruction @@ -103,3 +105,11 @@ void EmulEnv::doModRM(const ExtMachInst & machInst) } } +void EmulEnv::setSeg(const ExtMachInst & machInst) +{ + seg = SEGMENT_REG_DS; + //Handle any segment override that might have been in the instruction + int segFromInst = machInst.legacy.seg; + if (segFromInst) + seg = (SegmentRegIndex)(segFromInst - 1); +} diff --git a/src/arch/x86/emulenv.hh b/src/arch/x86/emulenv.hh index 1044dbdf9..cdb1bf863 100644 --- a/src/arch/x86/emulenv.hh +++ b/src/arch/x86/emulenv.hh @@ -86,6 +86,7 @@ namespace X86ISA {;} void doModRM(const ExtMachInst & machInst); + void setSeg(const ExtMachInst & machInst); }; }; diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc index 1c94a1251..b81400cc3 100644 --- a/src/arch/x86/faults.cc +++ b/src/arch/x86/faults.cc @@ -85,6 +85,7 @@ * Authors: Gabe Black */ +#include "arch/x86/decoder.hh" #include "arch/x86/faults.hh" #include "base/trace.hh" #include "config/full_system.hh" @@ -100,71 +101,90 @@ namespace X86ISA { #if FULL_SYSTEM - void X86Trap::invoke(ThreadContext * tc) + void X86FaultBase::invoke(ThreadContext * tc) { - panic("X86 faults are not implemented!"); + Addr pc = tc->readPC(); + DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc, vector, describe()); + using namespace X86ISAInst::RomLabels; + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + MicroPC entry; + if (m5reg.mode == LongMode) { + if (isSoft()) { + entry = extern_label_longModeSoftInterrupt; + } else { + entry = extern_label_longModeInterrupt; + } + } else { + entry = extern_label_legacyModeInterrupt; + } + tc->setIntReg(INTREG_MICRO(1), vector); + tc->setIntReg(INTREG_MICRO(7), pc); + if (errorCode != (uint64_t)(-1)) { + if (m5reg.mode == LongMode) { + entry = extern_label_longModeInterruptWithError; + } else { + panic("Legacy mode interrupts with error codes " + "aren't implementde.\n"); + } + // Software interrupts shouldn't have error codes. If one does, + // there would need to be microcode to set it up. + assert(!isSoft()); + tc->setIntReg(INTREG_MICRO(15), errorCode); + } + tc->setMicroPC(romMicroPC(entry)); + tc->setNextMicroPC(romMicroPC(entry) + 1); } - void X86Abort::invoke(ThreadContext * tc) + std::string + X86FaultBase::describe() const { - panic("X86 faults are not implemented!"); - } + std::stringstream ss; + ccprintf(ss, "%s", mnemonic()); + if (errorCode != (uint64_t)(-1)) { + ccprintf(ss, "(%#x)", errorCode); + } - void X86Interrupt::invoke(ThreadContext * tc) - { - panic("X86 faults are not implemented!"); + return ss.str(); } - - void FakeITLBFault::invoke(ThreadContext * tc) + + void X86Trap::invoke(ThreadContext * tc) { - // Start the page table walker. - tc->getITBPtr()->walk(tc, vaddr); + X86FaultBase::invoke(tc); + // This is the same as a fault, but it happens -after- the instruction. + tc->setPC(tc->readNextPC()); + tc->setNextPC(tc->readNextNPC()); + tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst)); } - void FakeDTLBFault::invoke(ThreadContext * tc) + void X86Abort::invoke(ThreadContext * tc) { - // Start the page table walker. - tc->getDTBPtr()->walk(tc, vaddr); + panic("Abort exception!"); } -#else // !FULL_SYSTEM - void FakeITLBFault::invoke(ThreadContext * tc) + void PageFault::invoke(ThreadContext * tc) { - DPRINTF(TLB, "Invoking an ITLB fault for address %#x at pc %#x.\n", - vaddr, tc->readPC()); - Process *p = tc->getProcessPtr(); - TlbEntry entry; - bool success = p->pTable->lookup(vaddr, entry); - if(!success) { - panic("Tried to execute unmapped address %#x.\n", vaddr); + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + X86FaultBase::invoke(tc); + /* + * If something bad happens while trying to enter the page fault + * handler, I'm pretty sure that's a double fault and then all bets are + * off. That means it should be safe to update this state now. + */ + if (m5reg.mode == LongMode) { + tc->setMiscReg(MISCREG_CR2, addr); } else { - Addr alignedVaddr = p->pTable->pageAlign(vaddr); - DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, - entry.pageStart()); - tc->getITBPtr()->insert(alignedVaddr, entry); + tc->setMiscReg(MISCREG_CR2, (uint32_t)addr); } } - void FakeDTLBFault::invoke(ThreadContext * tc) + std::string + PageFault::describe() const { - DPRINTF(TLB, "Invoking an DTLB fault for address %#x at pc %#x.\n", - vaddr, tc->readPC()); - Process *p = tc->getProcessPtr(); - TlbEntry entry; - bool success = p->pTable->lookup(vaddr, entry); - if(!success) { - p->checkAndAllocNextPage(vaddr); - success = p->pTable->lookup(vaddr, entry); - } - if(!success) { - panic("Tried to access unmapped address %#x.\n", vaddr); - } else { - Addr alignedVaddr = p->pTable->pageAlign(vaddr); - DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, - entry.pageStart()); - tc->getDTBPtr()->insert(alignedVaddr, entry); - } + std::stringstream ss; + ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr); + return ss.str(); } + #endif } // namespace X86ISA diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh index 78a55d0e1..fe5132994 100644 --- a/src/arch/x86/faults.hh +++ b/src/arch/x86/faults.hh @@ -58,9 +58,12 @@ #ifndef __ARCH_X86_FAULTS_HH__ #define __ARCH_X86_FAULTS_HH__ +#include "base/bitunion.hh" #include "base/misc.hh" #include "sim/faults.hh" +#include <string> + namespace X86ISA { // Base class for all x86 "faults" where faults is in the m5 sense @@ -69,11 +72,13 @@ namespace X86ISA protected: const char * faultName; const char * mnem; + uint8_t vector; uint64_t errorCode; X86FaultBase(const char * _faultName, const char * _mnem, - uint64_t _errorCode = 0) : - faultName(_faultName), mnem(_mnem), errorCode(_errorCode) + const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) + : faultName(_faultName), mnem(_mnem), + vector(_vector), errorCode(_errorCode) { } @@ -91,6 +96,17 @@ namespace X86ISA { return mnem; } + + virtual bool isSoft() + { + return false; + } + +#if FULL_SYSTEM + void invoke(ThreadContext * tc); + + virtual std::string describe() const; +#endif }; // Base class for x86 faults which behave as if the underlying instruction @@ -99,8 +115,8 @@ namespace X86ISA { protected: X86Fault(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} }; @@ -110,8 +126,8 @@ namespace X86ISA { protected: X86Trap(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} #if FULL_SYSTEM @@ -124,8 +140,8 @@ namespace X86ISA { protected: X86Abort(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, vector, _errorCode) {} #if FULL_SYSTEM @@ -138,13 +154,9 @@ namespace X86ISA { protected: X86Interrupt(const char * name, const char * mnem, - uint64_t _errorCode = 0) : - X86FaultBase(name, mnem, _errorCode) + const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) + : X86FaultBase(name, mnem, _vector, _errorCode) {} - -#if FULL_SYSTEM - void invoke(ThreadContext * tc); -#endif }; class UnimpInstFault : public FaultBase @@ -201,7 +213,7 @@ namespace X86ISA { public: DivideByZero() : - X86Fault("Divide-by-Zero-Error", "#DE") + X86Fault("Divide-by-Zero-Error", "#DE", 0) {} }; @@ -209,15 +221,15 @@ namespace X86ISA { public: DebugException() : - X86FaultBase("Debug", "#DB") + X86FaultBase("Debug", "#DB", 1) {} }; class NonMaskableInterrupt : public X86Interrupt { public: - NonMaskableInterrupt() : - X86Interrupt("Non-Maskable-Interrupt", "#NMI") + NonMaskableInterrupt(uint8_t _vector) : + X86Interrupt("Non Maskable Interrupt", "#NMI", 2, _vector) {} }; @@ -225,7 +237,7 @@ namespace X86ISA { public: Breakpoint() : - X86Trap("Breakpoint", "#BP") + X86Trap("Breakpoint", "#BP", 3) {} }; @@ -233,7 +245,7 @@ namespace X86ISA { public: OverflowTrap() : - X86Trap("Overflow", "#OF") + X86Trap("Overflow", "#OF", 4) {} }; @@ -241,7 +253,7 @@ namespace X86ISA { public: BoundRange() : - X86Fault("Bound-Range", "#BR") + X86Fault("Bound-Range", "#BR", 5) {} }; @@ -249,7 +261,7 @@ namespace X86ISA { public: InvalidOpcode() : - X86Fault("Invalid-Opcode", "#UD") + X86Fault("Invalid-Opcode", "#UD", 6) {} }; @@ -257,7 +269,7 @@ namespace X86ISA { public: DeviceNotAvailable() : - X86Fault("Device-Not-Available", "#NM") + X86Fault("Device-Not-Available", "#NM", 7) {} }; @@ -265,132 +277,156 @@ namespace X86ISA { public: DoubleFault() : - X86Abort("Double-Fault", "#DF") + X86Abort("Double-Fault", "#DF", 8, 0) {} }; class InvalidTSS : public X86Fault { public: - InvalidTSS() : - X86Fault("Invalid-TSS", "#TS") + InvalidTSS(uint32_t _errorCode) : + X86Fault("Invalid-TSS", "#TS", 10, _errorCode) {} }; class SegmentNotPresent : public X86Fault { public: - SegmentNotPresent() : - X86Fault("Segment-Not-Present", "#NP") + SegmentNotPresent(uint32_t _errorCode) : + X86Fault("Segment-Not-Present", "#NP", 11, _errorCode) {} }; class StackFault : public X86Fault { public: - StackFault() : - X86Fault("Stack", "#SS") + StackFault(uint32_t _errorCode) : + X86Fault("Stack", "#SS", 12, _errorCode) {} }; class GeneralProtection : public X86Fault { public: - GeneralProtection(uint64_t _errorCode) : - X86Fault("General-Protection", "#GP", _errorCode) + GeneralProtection(uint32_t _errorCode) : + X86Fault("General-Protection", "#GP", 13, _errorCode) {} }; class PageFault : public X86Fault { + protected: + BitUnion32(PageFaultErrorCode) + Bitfield<0> present; + Bitfield<1> write; + Bitfield<2> user; + Bitfield<3> reserved; + Bitfield<4> fetch; + EndBitUnion(PageFaultErrorCode) + + Addr addr; + public: - PageFault() : - X86Fault("Page-Fault", "#PF") + PageFault(Addr _addr, uint32_t _errorCode) : + X86Fault("Page-Fault", "#PF", 14, _errorCode), addr(_addr) {} + + PageFault(Addr _addr, bool present, bool write, + bool user, bool reserved, bool fetch) : + X86Fault("Page-Fault", "#PF", 14, 0), addr(_addr) + { + PageFaultErrorCode code = 0; + code.present = present; + code.write = write; + code.user = user; + code.reserved = reserved; + code.fetch = fetch; + errorCode = code; + } + +#if FULL_SYSTEM + void invoke(ThreadContext * tc); + + virtual std::string describe() const; +#endif }; class X87FpExceptionPending : public X86Fault { public: X87FpExceptionPending() : - X86Fault("x87 Floating-Point Exception Pending", "#MF") + X86Fault("x87 Floating-Point Exception Pending", "#MF", 16) {} }; - class AlignmentCheck : X86Fault + class AlignmentCheck : public X86Fault { public: AlignmentCheck() : - X86Fault("Alignment-Check", "#AC") + X86Fault("Alignment-Check", "#AC", 17, 0) {} }; - class MachineCheck : X86Abort + class MachineCheck : public X86Abort { public: MachineCheck() : - X86Abort("Machine-Check", "#MC") + X86Abort("Machine-Check", "#MC", 18) {} }; - class SIMDFloatingPointFault : X86Fault + class SIMDFloatingPointFault : public X86Fault { public: SIMDFloatingPointFault() : - X86Fault("SIMD Floating-Point", "#XF") + X86Fault("SIMD Floating-Point", "#XF", 19) {} }; - class SecurityException : X86FaultBase + class SecurityException : public X86FaultBase { public: SecurityException() : - X86FaultBase("Security Exception", "#SX") + X86FaultBase("Security Exception", "#SX", 30) {} }; - class ExternalInterrupt : X86Interrupt + class ExternalInterrupt : public X86Interrupt { public: - ExternalInterrupt() : - X86Interrupt("External Interrupt", "#INTR") + ExternalInterrupt(uint8_t _vector) : + X86Interrupt("External Interrupt", "#INTR", _vector) {} }; - class SoftwareInterrupt : X86Interrupt + class SystemManagementInterrupt : public X86Interrupt { public: - SoftwareInterrupt() : - X86Interrupt("Software Interrupt", "INTn") + SystemManagementInterrupt() : + X86Interrupt("System Management Interrupt", "#SMI", 0) {} }; - // These faults aren't part of the ISA definition. They trigger filling - // the tlb on a miss and are to take the place of a hardware table walker. - class FakeITLBFault : public X86Fault + class InitInterrupt : public X86Interrupt { - protected: - Addr vaddr; + uint8_t vector; public: - FakeITLBFault(Addr _vaddr) : - X86Fault("fake instruction tlb fault", "itlb"), - vaddr(_vaddr) + InitInterrupt(uint8_t _vector) : + X86Interrupt("INIT Interrupt", "#INIT", _vector) {} - - void invoke(ThreadContext * tc); }; - class FakeDTLBFault : public X86Fault + class SoftwareInterrupt : public X86Interrupt { - protected: - Addr vaddr; public: - FakeDTLBFault(Addr _vaddr) : - X86Fault("fake data tlb fault", "dtlb"), - vaddr(_vaddr) + SoftwareInterrupt(uint8_t _vector) : + X86Interrupt("Software Interrupt", "#INTR", _vector) {} - void invoke(ThreadContext * tc); + bool isSoft() + { + return true; + } }; }; diff --git a/src/arch/x86/floatregfile.cc b/src/arch/x86/floatregfile.cc index 1c49ea9c6..fce7f4868 100644 --- a/src/arch/x86/floatregfile.cc +++ b/src/arch/x86/floatregfile.cc @@ -96,15 +96,6 @@ using namespace std; class Checkpoint; -string X86ISA::getFloatRegName(RegIndex index) -{ - static std::string floatRegName[NumFloatRegs] = - {"mmx0", "mmx1", "mmx2", "mmx3", "mmx4", "mmx5", "mmx6", "mmx7", - "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", - "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; - return floatRegName[index]; -} - void FloatRegFile::clear() { memset(q, 0, sizeof(FloatReg) * NumFloatRegs); @@ -113,27 +104,27 @@ void FloatRegFile::clear() FloatReg FloatRegFile::readReg(int floatReg, int width) { FloatReg reg = d[floatReg]; - DPRINTF(X86, "Reading %f from register %d.\n", reg, floatReg); + DPRINTF(FloatRegs, "Reading %f from register %d.\n", reg, floatReg); return reg; } FloatRegBits FloatRegFile::readRegBits(int floatReg, int width) { FloatRegBits reg = q[floatReg]; - DPRINTF(X86, "Reading %#x from register %d.\n", reg, floatReg); + DPRINTF(FloatRegs, "Reading %#x from register %d.\n", reg, floatReg); return reg; } Fault FloatRegFile::setReg(int floatReg, const FloatReg &val, int width) { - DPRINTF(X86, "Writing %f to register %d.\n", val, floatReg); + DPRINTF(FloatRegs, "Writing %f to register %d.\n", val, floatReg); d[floatReg] = val; return NoFault; } Fault FloatRegFile::setRegBits(int floatReg, const FloatRegBits &val, int width) { - DPRINTF(X86, "Writing bits %#x to register %d.\n", val, floatReg); + DPRINTF(FloatRegs, "Writing bits %#x to register %d.\n", val, floatReg); q[floatReg] = val; return NoFault; } diff --git a/src/arch/x86/floatregfile.hh b/src/arch/x86/floatregfile.hh index b77ddb0eb..ab239dd7d 100644 --- a/src/arch/x86/floatregfile.hh +++ b/src/arch/x86/floatregfile.hh @@ -98,8 +98,6 @@ class Checkpoint; namespace X86ISA { - std::string getFloatRegName(RegIndex); - //Each 128 bit xmm register is broken into two effective 64 bit registers. const int NumFloatRegs = NumMMXRegs + 2 * NumXMMRegs + NumMicroFpRegs; diff --git a/src/arch/x86/insts/macroop.hh b/src/arch/x86/insts/macroop.hh new file mode 100644 index 000000000..d6925a1a5 --- /dev/null +++ b/src/arch/x86/insts/macroop.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INSTS_MACROOP_HH__ +#define __ARCH_X86_INSTS_MACROOP_HH__ + +#include "arch/x86/emulenv.hh" +#include "arch/x86/types.hh" +#include "arch/x86/insts/static_inst.hh" + +namespace X86ISA +{ +// Base class for combinationally generated macroops +class MacroopBase : public X86StaticInst +{ + protected: + const char *macrocodeBlock; + + const uint32_t numMicroops; + X86ISA::EmulEnv env; + + //Constructor. + MacroopBase(const char *mnem, ExtMachInst _machInst, + uint32_t _numMicroops, X86ISA::EmulEnv _env) : + X86StaticInst(mnem, _machInst, No_OpClass), + numMicroops(_numMicroops), env(_env) + { + assert(numMicroops); + microops = new StaticInstPtr[numMicroops]; + flags[IsMacroop] = true; + } + + ~MacroopBase() + { + delete [] microops; + } + + StaticInstPtr * microops; + + StaticInstPtr fetchMicroop(MicroPC microPC) + { + assert(microPC < numMicroops); + return microops[microPC]; + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return mnemonic; + } + + public: + ExtMachInst + getExtMachInst() + { + return machInst; + } + + X86ISA::EmulEnv + getEmulEnv() + { + return env; + } +}; +} + +#endif //__ARCH_X86_INSTS_MACROOP_HH__ diff --git a/src/arch/x86/insts/microldstop.cc b/src/arch/x86/insts/microldstop.cc index 9638a2ae3..7cc6a330f 100644 --- a/src/arch/x86/insts/microldstop.cc +++ b/src/arch/x86/insts/microldstop.cc @@ -64,7 +64,6 @@ namespace X86ISA const SymbolTable *symtab) const { std::stringstream response; - bool someAddr = false; printMnemonic(response, instMnem, mnemonic); if(flags[IsLoad]) @@ -72,32 +71,8 @@ namespace X86ISA else printSrcReg(response, 2, dataSize); response << ", "; - printSegment(response, segment); - response << ":["; - if(scale != 0 && _srcRegIdx[0] != ZeroReg) - { - if(scale != 1) - ccprintf(response, "%d*", scale); - printSrcReg(response, 0, addressSize); - someAddr = true; - } - if(_srcRegIdx[1] != ZeroReg) - { - if(someAddr) - response << " + "; - printSrcReg(response, 1, addressSize); - someAddr = true; - } - if(disp != 0) - { - if(someAddr) - response << " + "; - ccprintf(response, "%#x", disp); - someAddr = true; - } - if(!someAddr) - response << "0"; - response << "]"; + printMem(response, segment, scale, index, base, disp, + addressSize, false); return response.str(); } } diff --git a/src/arch/x86/insts/microldstop.hh b/src/arch/x86/insts/microldstop.hh index 5b1210d69..1774454c3 100644 --- a/src/arch/x86/insts/microldstop.hh +++ b/src/arch/x86/insts/microldstop.hh @@ -59,9 +59,18 @@ #define __ARCH_X86_INSTS_MICROLDSTOP_HH__ #include "arch/x86/insts/microop.hh" +#include "mem/packet.hh" +#include "mem/request.hh" namespace X86ISA { + static const Request::FlagsType SegmentFlagMask = mask(4); + static const int FlagShift = 4; + enum FlagBit { + CPL0FlagBit = 1, + AddrSizeFlagBit = 2 + }; + /** * Base class for load and store ops */ @@ -76,6 +85,7 @@ namespace X86ISA const RegIndex data; const uint8_t dataSize; const uint8_t addressSize; + const Request::FlagsType memFlags; RegIndex foldOBit, foldABit; //Constructor @@ -86,13 +96,15 @@ namespace X86ISA uint64_t _disp, uint8_t _segment, RegIndex _data, uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags, OpClass __opClass) : X86MicroopBase(machInst, mnem, _instMnem, isMicro, isDelayed, isFirst, isLast, __opClass), scale(_scale), index(_index), base(_base), disp(_disp), segment(_segment), data(_data), - dataSize(_dataSize), addressSize(_addressSize) + dataSize(_dataSize), addressSize(_addressSize), + memFlags(_memFlags | _segment) { foldOBit = (dataSize == 1 && !_machInst.rex.present) ? 1 << 6 : 0; foldABit = @@ -149,6 +161,25 @@ namespace X86ISA } return fault; } + + uint64_t + get(PacketPtr pkt) const + { + switch(dataSize) + { + case 1: + return pkt->get<uint8_t>(); + case 2: + return pkt->get<uint16_t>(); + case 4: + return pkt->get<uint32_t>(); + case 8: + return pkt->get<uint64_t>(); + default: + panic("Bad operand size %d for read at %#x.\n", + dataSize, pkt->getAddr()); + } + } }; } diff --git a/src/arch/x86/insts/microop.cc b/src/arch/x86/insts/microop.cc index 494c0b303..c7bfc3703 100644 --- a/src/arch/x86/insts/microop.cc +++ b/src/arch/x86/insts/microop.cc @@ -98,7 +98,7 @@ namespace X86ISA case ConditionTests::SxOF: return ccflags.sf ^ ccflags.of; case ConditionTests::SxOvZF: - return ccflags.sf ^ ccflags.of | ccflags.zf; + return (ccflags.sf ^ ccflags.of) | ccflags.zf; case ConditionTests::False: return false; case ConditionTests::NotECF: @@ -131,7 +131,7 @@ namespace X86ISA case ConditionTests::NotSxOF: return !(ccflags.sf ^ ccflags.of); case ConditionTests::NotSxOvZF: - return !(ccflags.sf ^ ccflags.of | ccflags.zf); + return !((ccflags.sf ^ ccflags.of) | ccflags.zf); } panic("Unknown condition: %d\n", condition); return true; diff --git a/src/arch/x86/insts/microregop.cc b/src/arch/x86/insts/microregop.cc index 080926627..2ea975746 100644 --- a/src/arch/x86/insts/microregop.cc +++ b/src/arch/x86/insts/microregop.cc @@ -67,6 +67,9 @@ namespace X86ISA bool subtract) const { DPRINTF(X86, "flagMask = %#x\n", flagMask); + if (_destRegIdx[0] & (1 << 6)) { + _dest >>= 8; + } uint64_t flags = oldFlags & ~flagMask; if(flagMask & (ECFBit | CFBit)) { diff --git a/src/arch/x86/insts/static_inst.cc b/src/arch/x86/insts/static_inst.cc index 0c1508d5a..f4ed44603 100644 --- a/src/arch/x86/insts/static_inst.cc +++ b/src/arch/x86/insts/static_inst.cc @@ -63,13 +63,13 @@ namespace X86ISA void X86StaticInst::printMnemonic(std::ostream &os, const char * mnemonic) const { - ccprintf(os, "\t%s ", mnemonic); + ccprintf(os, " %s ", mnemonic); } void X86StaticInst::printMnemonic(std::ostream &os, const char * instMnemonic, const char * mnemonic) const { - ccprintf(os, "\t%s : %s ", instMnemonic, mnemonic); + ccprintf(os, " %s : %s ", instMnemonic, mnemonic); } void X86StaticInst::printSegment(std::ostream &os, int segment) const @@ -240,6 +240,44 @@ namespace X86ISA } } + void X86StaticInst::printMem(std::ostream &os, uint8_t segment, + uint8_t scale, RegIndex index, RegIndex base, + uint64_t disp, uint8_t addressSize, bool rip) const + { + bool someAddr = false; + printSegment(os, segment); + os << ":["; + if (rip) { + os << "rip"; + someAddr = true; + } else { + if (scale != 0 && index != ZeroReg) + { + if(scale != 1) + ccprintf(os, "%d*", scale); + printReg(os, index, addressSize); + someAddr = true; + } + if (base != ZeroReg) + { + if(someAddr) + os << " + "; + printReg(os, base, addressSize); + someAddr = true; + } + } + if (disp != 0) + { + if(someAddr) + os << " + "; + ccprintf(os, "%#x", disp); + someAddr = true; + } + if (!someAddr) + os << "0"; + os << "]"; + } + std::string X86StaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const { diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh index e5c333e75..8480f2713 100644 --- a/src/arch/x86/insts/static_inst.hh +++ b/src/arch/x86/insts/static_inst.hh @@ -89,6 +89,9 @@ namespace X86ISA void printReg(std::ostream &os, int reg, int size) const; void printSrcReg(std::ostream &os, int reg, int size) const; void printDestReg(std::ostream &os, int reg, int size) const; + void printMem(std::ostream &os, uint8_t segment, + uint8_t scale, RegIndex index, RegIndex base, + uint64_t disp, uint8_t addressSize, bool rip) const; inline uint64_t merge(uint64_t into, uint64_t val, int size) const { diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc new file mode 100644 index 000000000..30c532c2b --- /dev/null +++ b/src/arch/x86/interrupts.cc @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/apicregs.hh" +#include "arch/x86/interrupts.hh" +#include "arch/x86/intmessage.hh" +#include "cpu/base.hh" +#include "mem/packet_access.hh" + +int +divideFromConf(uint32_t conf) +{ + // This figures out what division we want from the division configuration + // register in the local APIC. The encoding is a little odd but it can + // be deciphered fairly easily. + int shift = ((conf & 0x8) >> 1) | (conf & 0x3); + shift = (shift + 1) % 8; + return 1 << shift; +} + +namespace X86ISA +{ + +ApicRegIndex +decodeAddr(Addr paddr) +{ + ApicRegIndex regNum; + paddr &= ~mask(3); + switch (paddr) + { + case 0x20: + regNum = APIC_ID; + break; + case 0x30: + regNum = APIC_VERSION; + break; + case 0x80: + regNum = APIC_TASK_PRIORITY; + break; + case 0x90: + regNum = APIC_ARBITRATION_PRIORITY; + break; + case 0xA0: + regNum = APIC_PROCESSOR_PRIORITY; + break; + case 0xB0: + regNum = APIC_EOI; + break; + case 0xD0: + regNum = APIC_LOGICAL_DESTINATION; + break; + case 0xE0: + regNum = APIC_DESTINATION_FORMAT; + break; + case 0xF0: + regNum = APIC_SPURIOUS_INTERRUPT_VECTOR; + break; + case 0x100: + case 0x108: + case 0x110: + case 0x118: + case 0x120: + case 0x128: + case 0x130: + case 0x138: + case 0x140: + case 0x148: + case 0x150: + case 0x158: + case 0x160: + case 0x168: + case 0x170: + case 0x178: + regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8); + break; + case 0x180: + case 0x188: + case 0x190: + case 0x198: + case 0x1A0: + case 0x1A8: + case 0x1B0: + case 0x1B8: + case 0x1C0: + case 0x1C8: + case 0x1D0: + case 0x1D8: + case 0x1E0: + case 0x1E8: + case 0x1F0: + case 0x1F8: + regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8); + break; + case 0x200: + case 0x208: + case 0x210: + case 0x218: + case 0x220: + case 0x228: + case 0x230: + case 0x238: + case 0x240: + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: + regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8); + break; + case 0x280: + regNum = APIC_ERROR_STATUS; + break; + case 0x300: + regNum = APIC_INTERRUPT_COMMAND_LOW; + break; + case 0x310: + regNum = APIC_INTERRUPT_COMMAND_HIGH; + break; + case 0x320: + regNum = APIC_LVT_TIMER; + break; + case 0x330: + regNum = APIC_LVT_THERMAL_SENSOR; + break; + case 0x340: + regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; + break; + case 0x350: + regNum = APIC_LVT_LINT0; + break; + case 0x360: + regNum = APIC_LVT_LINT1; + break; + case 0x370: + regNum = APIC_LVT_ERROR; + break; + case 0x380: + regNum = APIC_INITIAL_COUNT; + break; + case 0x390: + regNum = APIC_CURRENT_COUNT; + break; + case 0x3E0: + regNum = APIC_DIVIDE_CONFIGURATION; + break; + default: + // A reserved register field. + panic("Accessed reserved register field %#x.\n", paddr); + break; + } + return regNum; +} +} + +Tick +X86ISA::Interrupts::read(PacketPtr pkt) +{ + Addr offset = pkt->getAddr() - pioAddr; + //Make sure we're at least only accessing one register. + if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) + panic("Accessed more than one register at a time in the APIC!\n"); + ApicRegIndex reg = decodeAddr(offset); + uint32_t val = htog(readReg(reg)); + DPRINTF(LocalApic, + "Reading Local APIC register %d at offset %#x as %#x.\n", + reg, offset, val); + pkt->setData(((uint8_t *)&val) + (offset & mask(3))); + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::Interrupts::write(PacketPtr pkt) +{ + Addr offset = pkt->getAddr() - pioAddr; + //Make sure we're at least only accessing one register. + if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) + panic("Accessed more than one register at a time in the APIC!\n"); + ApicRegIndex reg = decodeAddr(offset); + uint32_t val = regs[reg]; + pkt->writeData(((uint8_t *)&val) + (offset & mask(3))); + DPRINTF(LocalApic, + "Writing Local APIC register %d at offset %#x as %#x.\n", + reg, offset, gtoh(val)); + setReg(reg, gtoh(val)); + pkt->makeAtomicResponse(); + return latency; +} +void +X86ISA::Interrupts::requestInterrupt(uint8_t vector, + uint8_t deliveryMode, bool level) +{ + /* + * Fixed and lowest-priority delivery mode interrupts are handled + * using the IRR/ISR registers, checking against the TPR, etc. + * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through. + */ + if (deliveryMode == DeliveryMode::Fixed || + deliveryMode == DeliveryMode::LowestPriority) { + DPRINTF(LocalApic, "Interrupt is an %s.\n", + DeliveryMode::names[deliveryMode]); + // Queue up the interrupt in the IRR. + if (vector > IRRV) + IRRV = vector; + if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) { + setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector); + if (level) { + setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } else { + clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector); + } + } + } else if (!DeliveryMode::isReserved(deliveryMode)) { + DPRINTF(LocalApic, "Interrupt is an %s.\n", + DeliveryMode::names[deliveryMode]); + if (deliveryMode == DeliveryMode::SMI && !pendingSmi) { + pendingUnmaskableInt = pendingSmi = true; + smiVector = vector; + } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) { + pendingUnmaskableInt = pendingNmi = true; + nmiVector = vector; + } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) { + pendingExtInt = true; + extIntVector = vector; + } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) { + pendingUnmaskableInt = pendingInit = true; + initVector = vector; + } + } + cpu->wakeup(); +} + +Tick +X86ISA::Interrupts::recvMessage(PacketPtr pkt) +{ + uint8_t id = 0; + Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0); + assert(pkt->cmd == MemCmd::MessageReq); + switch(offset) + { + case 0: + { + TriggerIntMessage message = pkt->get<TriggerIntMessage>(); + DPRINTF(LocalApic, + "Got Trigger Interrupt message with vector %#x.\n", + message.vector); + // Make sure we're really supposed to get this. + assert((message.destMode == 0 && message.destination == id) || + (bits((int)message.destination, id))); + + requestInterrupt(message.vector, + message.deliveryMode, message.trigger); + } + break; + default: + panic("Local apic got unknown interrupt message at offset %#x.\n", + offset); + break; + } + delete pkt->req; + delete pkt; + return latency; +} + + +uint32_t +X86ISA::Interrupts::readReg(ApicRegIndex reg) +{ + if (reg >= APIC_TRIGGER_MODE(0) && + reg <= APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + switch (reg) { + case APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case APIC_ERROR_STATUS: + regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); + break; + case APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case APIC_CURRENT_COUNT: + { + if (apicTimerEvent.scheduled()) { + assert(clock); + // Compute how many m5 ticks happen per count. + uint64_t ticksPerCount = clock * + divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]); + // Compute how many m5 ticks are left. + uint64_t val = apicTimerEvent.when() - curTick; + // Turn that into a count. + val = (val + ticksPerCount - 1) / ticksPerCount; + return val; + } else { + return 0; + } + } + default: + break; + } + return regs[reg]; +} + +void +X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) +{ + uint32_t newVal = val; + if (reg >= APIC_IN_SERVICE(0) && + reg <= APIC_IN_SERVICE(15)) { + panic("Local APIC In-Service registers are unimplemented.\n"); + } + if (reg >= APIC_TRIGGER_MODE(0) && + reg <= APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + if (reg >= APIC_INTERRUPT_REQUEST(0) && + reg <= APIC_INTERRUPT_REQUEST(15)) { + panic("Local APIC Interrupt Request registers " + "are unimplemented.\n"); + } + switch (reg) { + case APIC_ID: + newVal = val & 0xFF; + break; + case APIC_VERSION: + // The Local APIC Version register is read only. + return; + case APIC_TASK_PRIORITY: + newVal = val & 0xFF; + break; + case APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case APIC_EOI: + // Remove the interrupt that just completed from the local apic state. + clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); + updateISRV(); + return; + case APIC_LOGICAL_DESTINATION: + newVal = val & 0xFF000000; + break; + case APIC_DESTINATION_FORMAT: + newVal = val | 0x0FFFFFFF; + break; + case APIC_SPURIOUS_INTERRUPT_VECTOR: + regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1); + regs[APIC_INTERNAL_STATE] |= val & (1 << 8); + if (val & (1 << 9)) + warn("Focus processor checking not implemented.\n"); + break; + case APIC_ERROR_STATUS: + { + if (regs[APIC_INTERNAL_STATE] & 0x1) { + regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); + newVal = 0; + } else { + regs[APIC_INTERNAL_STATE] |= ULL(0x1); + return; + } + + } + break; + case APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case APIC_LVT_TIMER: + case APIC_LVT_THERMAL_SENSOR: + case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: + case APIC_LVT_LINT0: + case APIC_LVT_LINT1: + case APIC_LVT_ERROR: + { + uint64_t readOnlyMask = (1 << 12) | (1 << 14); + newVal = (val & ~readOnlyMask) | + (regs[reg] & readOnlyMask); + } + break; + case APIC_INITIAL_COUNT: + { + assert(clock); + newVal = bits(val, 31, 0); + // Compute how many timer ticks we're being programmed for. + uint64_t newCount = newVal * + (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); + // Schedule on the edge of the next tick plus the new count. + Tick offset = curTick % clock; + if (offset) { + reschedule(apicTimerEvent, + curTick + (newCount + 1) * clock - offset, true); + } else { + reschedule(apicTimerEvent, + curTick + newCount * clock, true); + } + } + break; + case APIC_CURRENT_COUNT: + //Local APIC Current Count register is read only. + return; + case APIC_DIVIDE_CONFIGURATION: + newVal = val & 0xB; + break; + default: + break; + } + regs[reg] = newVal; + return; +} + +bool +X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const +{ + RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS); + if (pendingUnmaskableInt) { + DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n"); + return true; + } + if (rflags.intf) { + if (pendingExtInt) { + DPRINTF(LocalApic, "Reported pending external interrupt.\n"); + return true; + } + if (IRRV > ISRV && bits(IRRV, 7, 4) > + bits(regs[APIC_TASK_PRIORITY], 7, 4)) { + DPRINTF(LocalApic, "Reported pending regular interrupt.\n"); + return true; + } + } + return false; +} + +Fault +X86ISA::Interrupts::getInterrupt(ThreadContext *tc) +{ + assert(checkInterrupts(tc)); + // These are all probably fairly uncommon, so we'll make them easier to + // check for. + if (pendingUnmaskableInt) { + if (pendingSmi) { + DPRINTF(LocalApic, "Generated SMI fault object.\n"); + return new SystemManagementInterrupt(); + } else if (pendingNmi) { + DPRINTF(LocalApic, "Generated NMI fault object.\n"); + return new NonMaskableInterrupt(nmiVector); + } else if (pendingInit) { + DPRINTF(LocalApic, "Generated INIT fault object.\n"); + return new InitInterrupt(initVector); + } else { + panic("pendingUnmaskableInt set, but no unmaskable " + "ints were pending.\n"); + return NoFault; + } + } else if (pendingExtInt) { + DPRINTF(LocalApic, "Generated external interrupt fault object.\n"); + return new ExternalInterrupt(extIntVector); + } else { + DPRINTF(LocalApic, "Generated regular interrupt fault object.\n"); + // The only thing left are fixed and lowest priority interrupts. + return new ExternalInterrupt(IRRV); + } +} + +void +X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc) +{ + assert(checkInterrupts(tc)); + if (pendingUnmaskableInt) { + if (pendingSmi) { + DPRINTF(LocalApic, "SMI sent to core.\n"); + pendingSmi = false; + } else if (pendingNmi) { + DPRINTF(LocalApic, "NMI sent to core.\n"); + pendingNmi = false; + } else if (pendingInit) { + DPRINTF(LocalApic, "Init sent to core.\n"); + pendingInit = false; + } + if (!(pendingSmi || pendingNmi || pendingInit)) + pendingUnmaskableInt = false; + } else if (pendingExtInt) { + pendingExtInt = false; + } else { + DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV); + // Mark the interrupt as "in service". + ISRV = IRRV; + setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV); + // Clear it out of the IRR. + clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV); + updateIRRV(); + } +} + +X86ISA::Interrupts * +X86LocalApicParams::create() +{ + return new X86ISA::Interrupts(this); +} diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh index cf9109e22..c5e3bde0d 100644 --- a/src/arch/x86/interrupts.hh +++ b/src/arch/x86/interrupts.hh @@ -58,73 +58,274 @@ #ifndef __ARCH_X86_INTERRUPTS_HH__ #define __ARCH_X86_INTERRUPTS_HH__ +#include "arch/x86/apicregs.hh" #include "arch/x86/faults.hh" +#include "arch/x86/intmessage.hh" +#include "base/bitfield.hh" #include "cpu/thread_context.hh" +#include "dev/io_device.hh" +#include "dev/x86/intdev.hh" +#include "params/X86LocalApic.hh" +#include "sim/eventq.hh" -namespace X86ISA -{ +class ThreadContext; +class BaseCPU; + +namespace X86ISA { -class Interrupts +class Interrupts : public BasicPioDevice, IntDev { + protected: + // Storage for the APIC registers + uint32_t regs[NUM_APIC_REGS]; + + BitUnion32(LVTEntry) + Bitfield<7, 0> vector; + Bitfield<10, 8> deliveryMode; + Bitfield<12> status; + Bitfield<13> polarity; + Bitfield<14> remoteIRR; + Bitfield<15> trigger; + Bitfield<16> masked; + Bitfield<17> periodic; + EndBitUnion(LVTEntry) + + /* + * Timing related stuff. + */ + Tick latency; + Tick clock; + + class ApicTimerEvent : public Event + { + private: + Interrupts *localApic; + public: + ApicTimerEvent(Interrupts *_localApic) : + Event(), localApic(_localApic) + {} + + void process() + { + assert(localApic); + if (localApic->triggerTimerInterrupt()) { + localApic->setReg(APIC_INITIAL_COUNT, + localApic->readReg(APIC_INITIAL_COUNT)); + } + } + }; + + ApicTimerEvent apicTimerEvent; + + /* + * A set of variables to keep track of interrupts that don't go through + * the IRR. + */ + bool pendingSmi; + uint8_t smiVector; + bool pendingNmi; + uint8_t nmiVector; + bool pendingExtInt; + uint8_t extIntVector; + bool pendingInit; + uint8_t initVector; + + // This is a quick check whether any of the above (except ExtInt) are set. + bool pendingUnmaskableInt; + + /* + * IRR and ISR maintenance. + */ + uint8_t IRRV; + uint8_t ISRV; + + int + findRegArrayMSB(ApicRegIndex base) + { + int offset = 7; + do { + if (regs[base + offset] != 0) { + return offset * 32 + findMsbSet(regs[base + offset]); + } + } while (offset--); + return 0; + } + + void + updateIRRV() + { + IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE); + } + + void + updateISRV() + { + ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE); + } + + void + setRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] |= (1 << (vector >> 5)); + } + + void + clearRegArrayBit(ApicRegIndex base, uint8_t vector) + { + regs[base + (vector % 32)] &= ~(1 << (vector >> 5)); + } + + bool + getRegArrayBit(ApicRegIndex base, uint8_t vector) + { + return bits(regs[base + (vector % 32)], vector >> 5); + } + + void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level); + + BaseCPU *cpu; + public: - Interrupts() + /* + * Params stuff. + */ + typedef X86LocalApicParams Params; + + void + setCPU(BaseCPU * newCPU) { - clear_all(); + cpu = newCPU; } - int InterruptLevel(uint64_t softint) + void + setClock(Tick newClock) { - panic("Interrupts::InterruptLevel unimplemented!\n"); - return 0; + clock = newClock; } - void post(int int_num, int index) + const Params * + params() const { - panic("Interrupts::post unimplemented!\n"); + return dynamic_cast<const Params *>(_params); } - void clear(int int_num, int index) + /* + * Functions to interact with the interrupt port from IntDev. + */ + Tick read(PacketPtr pkt); + Tick write(PacketPtr pkt); + Tick recvMessage(PacketPtr pkt); + + bool + triggerTimerInterrupt() { - warn("Interrupts::clear unimplemented!\n"); + LVTEntry entry = regs[APIC_LVT_TIMER]; + if (!entry.masked) + requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger); + return entry.periodic; } - void clear_all() + void addressRanges(AddrRangeList &range_list) { - warn("Interrupts::clear_all unimplemented!\n"); + range_list.clear(); + range_list.push_back(RangeEx(x86LocalAPICAddress(0, 0), + x86LocalAPICAddress(0, 0) + PageBytes)); } - bool check_interrupts(ThreadContext * tc) const + void getIntAddrRange(AddrRangeList &range_list) { - return false; + range_list.clear(); + range_list.push_back(RangeEx(x86InterruptAddress(0, 0), + x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize)); } - Fault getInterrupt(ThreadContext * tc) + Port *getPort(const std::string &if_name, int idx = -1) { - return NoFault; + if (if_name == "int_port") + return intPort; + return BasicPioDevice::getPort(if_name, idx); } - void updateIntrInfo(ThreadContext * tc) + /* + * Functions to access and manipulate the APIC's registers. + */ + + uint32_t readReg(ApicRegIndex miscReg); + void setReg(ApicRegIndex reg, uint32_t val); + void + setRegNoEffect(ApicRegIndex reg, uint32_t val) { - panic("Interrupts::updateIntrInfo unimplemented!\n"); + regs[reg] = val; } - uint64_t get_vec(int int_num) + /* + * Constructor. + */ + + Interrupts(Params * p) + : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0), + apicTimerEvent(this), + pendingSmi(false), smiVector(0), + pendingNmi(false), nmiVector(0), + pendingExtInt(false), extIntVector(0), + pendingInit(false), initVector(0), + pendingUnmaskableInt(false) { - panic("Interrupts::get_vec unimplemented!\n"); - return 0; + pioSize = PageBytes; + memset(regs, 0, sizeof(regs)); + //Set the local apic DFR to the flat model. + regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1); + ISRV = 0; + IRRV = 0; } - void serialize(std::ostream & os) + /* + * Functions for retrieving interrupts for the CPU to handle. + */ + + bool checkInterrupts(ThreadContext *tc) const; + Fault getInterrupt(ThreadContext *tc); + void updateIntrInfo(ThreadContext *tc); + + /* + * Serialization. + */ + + void + serialize(std::ostream &os) { panic("Interrupts::serialize unimplemented!\n"); } - void unserialize(Checkpoint * cp, const std::string & section) + void + unserialize(Checkpoint *cp, const std::string §ion) { panic("Interrupts::unserialize unimplemented!\n"); } -}; + /* + * Old functions needed for compatability but which will be phased out + * eventually. + */ + void + post(int int_num, int index) + { + panic("Interrupts::post unimplemented!\n"); + } + + void + clear(int int_num, int index) + { + panic("Interrupts::clear unimplemented!\n"); + } + + void + clearAll() + { + panic("Interrupts::clearAll unimplemented!\n"); + } }; +} // namespace X86ISA + #endif // __ARCH_X86_INTERRUPTS_HH__ diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh new file mode 100644 index 000000000..f5f8519e2 --- /dev/null +++ b/src/arch/x86/intmessage.hh @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INTMESSAGE_HH__ +#define __ARCH_X86_INTMESSAGE_HH__ + +#include "arch/x86/x86_traits.hh" +#include "base/bitunion.hh" +#include "mem/packet.hh" +#include "mem/request.hh" +#include "sim/host.hh" + +namespace X86ISA +{ + BitUnion32(TriggerIntMessage) + Bitfield<7, 0> destination; + Bitfield<15, 8> vector; + Bitfield<18, 16> deliveryMode; + Bitfield<19> destMode; + Bitfield<20> level; + Bitfield<21> trigger; + EndBitUnion(TriggerIntMessage) + + namespace DeliveryMode + { + enum IntDeliveryMode { + Fixed = 0, + LowestPriority = 1, + SMI = 2, + NMI = 4, + INIT = 5, + ExtInt = 7, + NumModes + }; + + static const char * const names[NumModes] = { + "Fixed", "LowestPriority", "SMI", "Reserved", + "NMI", "INIT", "Reserved", "ExtInt" + }; + + static inline bool + isReserved(int mode) + { + return mode == 3 || mode == 6; + } + } + + static const Addr TriggerIntOffset = 0; + + static inline PacketPtr + prepIntRequest(const uint8_t id, Addr offset, Addr size) + { + RequestPtr req = new Request(x86InterruptAddress(id, offset), + size, Request::UNCACHEABLE); + PacketPtr pkt = new Packet(req, MemCmd::MessageReq, Packet::Broadcast); + pkt->allocate(); + return pkt; + } + + template<class T> + PacketPtr + buildIntRequest(const uint8_t id, T payload, Addr offset, Addr size) + { + PacketPtr pkt = prepIntRequest(id, offset, size); + pkt->set<T>(payload); + return pkt; + } + + static inline PacketPtr + buildIntRequest(const uint8_t id, TriggerIntMessage payload) + { + return buildIntRequest(id, payload, TriggerIntOffset, + sizeof(TriggerIntMessage)); + } + + static inline PacketPtr + buildIntResponse() + { + panic("buildIntResponse not implemented.\n"); + } +} + +#endif diff --git a/src/arch/x86/intregfile.cc b/src/arch/x86/intregfile.cc index 9c9ea134e..58a37cb9e 100644 --- a/src/arch/x86/intregfile.cc +++ b/src/arch/x86/intregfile.cc @@ -97,17 +97,6 @@ using namespace std; class Checkpoint; -string X86ISA::getIntRegName(RegIndex index) -{ - //These might appear to be out of order, but they match - //the encoding for the registers. Who knows why the indexes - //are out of order - static std::string intRegName[NumIntArchRegs] = - {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; - return intRegName[index]; -} - int IntRegFile::flattenIndex(int reg) { return reg; @@ -120,13 +109,15 @@ void IntRegFile::clear() IntReg IntRegFile::readReg(int intReg) { - DPRINTF(X86, "Read int reg %d and got value %#x\n", intReg, regs[intReg]); + DPRINTF(IntRegs, "Read int reg %d and got value %#x\n", + intReg, regs[intReg]); return regs[intReg]; } void IntRegFile::setReg(int intReg, const IntReg &val) { - DPRINTF(X86, "Setting int reg %d to value %#x\n", intReg, val); + DPRINTF(IntRegs, "Setting int reg %d to value %#x\n", + intReg, val); regs[intReg] = val; } diff --git a/src/arch/x86/intregfile.hh b/src/arch/x86/intregfile.hh index b4d256a04..131245352 100644 --- a/src/arch/x86/intregfile.hh +++ b/src/arch/x86/intregfile.hh @@ -100,9 +100,6 @@ namespace X86ISA { class Regfile; - //This function translates integer register file indices into names - std::string getIntRegName(RegIndex); - const int NumIntArchRegs = NUM_INTREGS; const int NumIntRegs = NumIntArchRegs + NumMicroIntRegs + diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index 332ae1641..817986232 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -418,12 +418,27 @@ default: Inst::RET_FAR(); } 0x4: int3(); +#if FULL_SYSTEM 0x5: int_Ib(); +#else + // Really only the LSB matters, but the predecoder will sign + // extend it, and there's no easy way to specify only checking + // the first byte. + 0x5: decode IMMEDIATE { + 0xffffffffffffff80: + SyscallInst::int80('xc->syscall(Rax)', IsSyscall); + default: int_Ib(); + } +#endif 0x6: decode MODE_SUBMODE { 0x0: Inst::UD2(); default: into(); } - 0x7: iret(); + 0x7: decode MODE_SUBMODE { + 0x4: Inst::IRET_REAL(); + 0x3: Inst::IRET_VIRT(); + default: Inst::IRET_PROT(); + } } } 0x1A: decode OPCODE_OP_BOTTOM3 { @@ -549,8 +564,8 @@ 0x1F: decode OPCODE_OP_BOTTOM3 { 0x0: CLC(); 0x1: STC(); - 0x2: WarnUnimpl::cli(); - 0x3: WarnUnimpl::sti(); + 0x2: CLI(); + 0x3: STI(); 0x4: CLD(); 0x5: STD(); //0x6: group4(); diff --git a/src/arch/x86/isa/decoder/two_byte_opcodes.isa b/src/arch/x86/isa/decoder/two_byte_opcodes.isa index 8135a1fdb..1ee62142a 100644 --- a/src/arch/x86/isa/decoder/two_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/two_byte_opcodes.isa @@ -93,8 +93,8 @@ 0x00: decode MODRM_REG { 0x0: sldt_Mw_or_Rv(); 0x1: str_Mw_or_Rv(); - 0x2: lldt_Mw_or_Rv(); - 0x3: ltr_Mw_or_Rv(); + 0x2: Inst::LLDT(Ew); + 0x3: Inst::LTR(Ew); 0x4: verr_Mw_or_Rv(); 0x5: verw_Mw_or_Rv(); //0x6: jmpe_Ev(); // IA-64 @@ -128,7 +128,7 @@ 0x4: smsw_Rv(); 0x6: lmsw_Rv(); 0x7: decode MODRM_RM { - 0x0: swapgs(); + 0x0: Inst::SWAPGS(); 0x1: rdtscp(); default: Inst::UD2(); } @@ -163,17 +163,117 @@ } 0x02: lar_Gv_Ew(); 0x03: lsl_Gv_Ew(); - //sandpile.org doesn't seem to know what this is... ? - 0x04: loadall_or_reset_or_hang(); + // sandpile.org doesn't seem to know what this is...? We'll + // use it for pseudo instructions. We've got 16 bits of space + // to play with so there can be quite a few pseudo + // instructions. + //0x04: loadall_or_reset_or_hang(); + 0x4: decode IMMEDIATE { + format BasicOperate { #if FULL_SYSTEM - 0x05: syscall(); + 0x00: m5arm({{ + PseudoInst::arm(xc->tcBase()); + }}, IsNonSpeculative); + 0x01: m5quiesce({{ + PseudoInst::quiesce(xc->tcBase()); + }}, IsNonSpeculative); + 0x02: m5quiesceNs({{ + PseudoInst::quiesceNs(xc->tcBase(), Rdi); + }}, IsNonSpeculative); + 0x03: m5quiesceCycle({{ + PseudoInst::quiesceCycles(xc->tcBase(), Rdi); + }}, IsNonSpeculative); + 0x04: m5quiesceTime({{ + Rax = PseudoInst::quiesceTime(xc->tcBase()); + }}, IsNonSpeculative); +#endif + 0x07: m5rpns({{ + Rax = PseudoInst::rpns(xc->tcBase()); + }}, IsNonSpeculative); + 0x21: m5exit({{ + PseudoInst::m5exit(xc->tcBase(), Rdi); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x30: m5initparam({{ + Rax = xc->tcBase()->getCpuPtr()-> + system->init_param; + }}, IsNonSpeculative); + 0x31: m5loadsymbol({{ + PseudoInst::loadsymbol(xc->tcBase()); + }}, IsNonSpeculative); +#endif + 0x40: m5resetstats({{ + PseudoInst::resetstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x41: m5dumpstats({{ + PseudoInst::dumpstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x42: m5dumpresetstats({{ + PseudoInst::dumpresetstats(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); + 0x43: m5checkpoint({{ + PseudoInst::m5checkpoint(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x50: m5readfile({{ + Rax = PseudoInst::readfile( + xc->tcBase(), Rdi, Rsi, Rdx); + }}, IsNonSpeculative); +#endif + 0x51: m5debugbreak({{ + PseudoInst::debugbreak(xc->tcBase()); + }}, IsNonSpeculative); + 0x52: m5switchcpu({{ + PseudoInst::switchcpu(xc->tcBase()); + }}, IsNonSpeculative); +#if FULL_SYSTEM + 0x53: m5addsymbol({{ + PseudoInst::addsymbol(xc->tcBase(), Rdi, Rsi); + }}, IsNonSpeculative); +#endif + 0x54: m5panic({{ + panic("M5 panic instruction called at pc=%#x.\n", + xc->readPC()); + }}, IsNonSpeculative); + 0x55: m5reserved1({{ + warn("M5 reserved opcode 1 ignored.\n"); + }}, IsNonSpeculative); + 0x56: m5reserved2({{ + warn("M5 reserved opcode 2 ignored.\n"); + }}, IsNonSpeculative); + 0x57: m5reserved3({{ + warn("M5 reserved opcode 3 ignored.\n"); + }}, IsNonSpeculative); + 0x58: m5reserved4({{ + warn("M5 reserved opcode 4 ignored.\n"); + }}, IsNonSpeculative); + 0x59: m5reserved5({{ + warn("M5 reserved opcode 5 ignored.\n"); + }}, IsNonSpeculative); + default: Inst::UD2(); + } + } +#if FULL_SYSTEM + 0x05: decode MODE_MODE { + 0x0: decode MODE_SUBMODE { + 0x0: Inst::SYSCALL_64(); + 0x1: Inst::SYSCALL_COMPAT(); + } + 0x1: Inst::SYSCALL_LEGACY(); + } #else - 0x05: SyscallInst::syscall('xc->syscall(rax)', IsSyscall); + 0x05: SyscallInst::syscall('xc->syscall(Rax)', IsSyscall); #endif - 0x06: clts(); - //sandpile.org says (AMD) after sysret, so I might want to check - //if that means amd64 or AMD machines - 0x07: loadall_or_sysret(); + 0x06: Inst::CLTS(); + 0x07: decode MODE_SUBMODE { + 0x0: decode OPSIZE { + // Return to 64 bit mode. + 0x8: Inst::SYSRET_TO_64(); + // Return to compatibility mode. + default: Inst::SYSRET_TO_COMPAT(); + } + default: Inst::SYSRET_NON_64(); + } } 0x01: decode OPCODE_OP_BOTTOM3 { 0x0: invd(); @@ -181,9 +281,9 @@ 0x2: Inst::UD2(); 0x3: Inst::UD2(); 0x4: Inst::UD2(); - 0x5: threednow(); - 0x6: threednow(); - 0x7: threednow(); + 0x5: Inst::PREFETCH(Mb); + 0x6: FailUnimpl::femms(); + 0x7: FailUnimpl::threednow(); } 0x02: decode LEGACY_DECODEVAL { // no prefix @@ -235,7 +335,7 @@ //group17(); 0x0: decode MODRM_REG { 0x0: prefetch_nta(); - 0x1: prefetch_t0(); + 0x1: Inst::PREFETCH_T0(Mb); 0x2: prefetch_t1(); 0x3: prefetch_t2(); default: Inst::HINT_NOP(); @@ -252,9 +352,9 @@ // no prefix 0x0: decode OPCODE_OP_BOTTOM3 { 0x0: Inst::MOV(Rd,Cd); - 0x1: mov_Rd_Dd(); + 0x1: Inst::MOV(Rd,Dd); 0x2: Inst::MOV(Cd,Rd); - 0x3: mov_Dd_Rd(); + 0x3: Inst::MOV(Dd,Rd); 0x4: mov_Rd_Td(); 0x6: mov_Td_Rd(); default: Inst::UD2(); @@ -317,10 +417,14 @@ } 0x06: decode OPCODE_OP_BOTTOM3 { 0x0: Inst::WRMSR(); - 0x1: rdtsc(); + 0x1: Inst::RDTSC(); 0x2: Inst::RDMSR(); 0x3: rdpmc(); +#if FULL_SYSTEM 0x4: sysenter(); +#else + 0x4: SyscallInst::sysenter('xc->syscall(Rax)', IsSyscall); +#endif 0x5: sysexit(); 0x6: Inst::UD2(); 0x7: getsec(); @@ -707,7 +811,14 @@ 0x14: decode OPCODE_OP_BOTTOM3 { 0x0: push_fs(); 0x1: pop_fs(); - 0x2: Inst::CPUID(rAd); + 0x2: CPUIDInst::CPUID({{ + CpuidResult result; + success = doCpuid(xc->tcBase(), Rax, result); + Rax = result.rax; + Rbx = result.rbx; + Rcx = result.rcx; + Rdx = result.rdx; + }}); 0x3: Inst::BT(Ev,Gv); 0x4: shld_Ev_Gv_Ib(); 0x5: shld_Ev_Gv_rCl(); @@ -719,20 +830,28 @@ 0x1: pop_gs(); 0x2: rsm_smm(); 0x3: Inst::BTS(Ev,Gv); - 0x4: shrd_Ev_Gv_Ib(); + 0x4: Inst::SHRD(Ev,Gv,Ib); 0x5: shrd_Ev_Gv_rCl(); //0x6: group16(); - 0x6: decode MODRM_MOD { - 0x3: decode MODRM_REG { - 0x5: lfence(); - 0x6: mfence(); - 0x7: sfence(); + 0x6: decode MODRM_REG { + 0x0: fxsave(); + 0x1: fxrstor(); + 0x2: ldmxcsr(); + 0x3: stmxcsr(); + 0x4: Inst::UD2(); + 0x5: decode MODRM_MOD { + 0x3: BasicOperate::LFENCE( + {{/*Nothing*/}}, IsReadBarrier); default: Inst::UD2(); } - default: decode MODRM_REG { - 0x0: fxsave(); - 0x1: fxrstor(); - 0x7: clflush(); + 0x6: decode MODRM_MOD { + 0x3: BasicOperate::MFENCE( + {{/*Nothing*/}}, IsMemBarrier); + default: Inst::UD2(); + } + 0x7: decode MODRM_MOD { + 0x3: BasicOperate::SFENCE( + {{/*Nothing*/}}, IsWriteBarrier); default: Inst::UD2(); } } @@ -775,8 +894,8 @@ 0x7: Inst::MOVSX_W(Gv,Ev); } 0x18: decode OPCODE_OP_BOTTOM3 { - 0x0: xadd_Eb_Gb(); - 0x1: xadd_Ev_Gv(); + 0x0: Inst::XADD(Eb,Gb); + 0x1: Inst::XADD(Ev,Gv); //0x7: group9(); 0x7: decode MODRM_REG { 0x1: cmpxchg_Mq(); @@ -820,7 +939,11 @@ default: Inst::UD2(); } } - 0x19: bswap_B(); + 0x19: decode OPSIZE { + 4: Inst::BSWAP_D(Bd); + 8: Inst::BSWAP_Q(Bq); + default: Inst::UD2(); + } 0x1A: decode LEGACY_DECODEVAL { // no prefix 0x0: decode OPCODE_OP_BOTTOM3 { diff --git a/src/arch/x86/isa/formats/basic.isa b/src/arch/x86/isa/formats/basic.isa index 7aea7085f..b96bae238 100644 --- a/src/arch/x86/isa/formats/basic.isa +++ b/src/arch/x86/isa/formats/basic.isa @@ -147,3 +147,11 @@ def template BasicDecode {{ def template BasicDecodeWithMnemonic {{ return new %(class_name)s("%(mnemonic)s", machInst); }}; + +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'X86ISA::X86StaticInst', code, flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/x86/isa/formats/cpuid.isa b/src/arch/x86/isa/formats/cpuid.isa new file mode 100644 index 000000000..204270556 --- /dev/null +++ b/src/arch/x86/isa/formats/cpuid.isa @@ -0,0 +1,110 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +output header {{ + class CPUIDInst : public X86ISA::X86StaticInst + { + public: + static const RegIndex foldOBit = 0; + /// Constructor + CPUIDInst(const char *_mnemonic, ExtMachInst _machInst, + OpClass __opClass) : + X86ISA::X86StaticInst(_mnemonic, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string CPUIDInst::generateDisassembly(Addr PC, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + ccprintf(response, " "); + printReg(response, _srcRegIdx[0], machInst.opSize); + return response.str(); + } +}}; + +def template CPUIDExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + // If the CPUID instruction used a valid function number, this will + // be set to true. Otherwise, the instruction does nothing. + bool success; + %(op_decl)s; + %(op_rd)s; + %(code)s; + if (success) { + %(op_wb)s; + } + return NoFault; + } +}}; + +def format CPUIDInst(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'CPUIDInst', code, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = CPUIDExecute.subst(iop) +}}; + diff --git a/src/arch/x86/isa/formats/formats.isa b/src/arch/x86/isa/formats/formats.isa index 6906413c0..81179ab45 100644 --- a/src/arch/x86/isa/formats/formats.isa +++ b/src/arch/x86/isa/formats/formats.isa @@ -85,6 +85,9 @@ //Templates from this format are used later ##include "basic.isa" +//Include a format to generate a CPUID instruction. +##include "cpuid.isa" + //Include the "unknown" format ##include "unknown.isa" diff --git a/src/arch/x86/isa/includes.isa b/src/arch/x86/isa/includes.isa index 6724ea9b0..8626f117a 100644 --- a/src/arch/x86/isa/includes.isa +++ b/src/arch/x86/isa/includes.isa @@ -26,7 +26,7 @@ // // Authors: Gabe Black -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -97,6 +97,7 @@ output header {{ #include <iostream> #include "arch/x86/emulenv.hh" +#include "arch/x86/insts/macroop.hh" #include "arch/x86/insts/microfpop.hh" #include "arch/x86/insts/microldstop.hh" #include "arch/x86/insts/microregop.hh" @@ -113,10 +114,13 @@ output header {{ output decoder {{ #include "arch/x86/faults.hh" #include "arch/x86/floatregs.hh" +#include "arch/x86/microcode_rom.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/segmentregs.hh" +#include "arch/x86/tlb.hh" #include "base/cprintf.hh" #include "base/loader/symtab.hh" +#include "base/misc.hh" #include "cpu/thread_context.hh" // for Jump::branchTarget() #include "mem/packet.hh" @@ -144,6 +148,7 @@ output exec {{ #include <limits> #include <cmath> +#include "arch/x86/cpuid.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/tlb.hh" #include "base/bigint.hh" @@ -152,6 +157,8 @@ output exec {{ #include "sim/sim_exit.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +#include "mem/request.hh" +#include "sim/pseudo_inst.hh" using namespace X86ISA; using namespace std; diff --git a/src/arch/x86/isa/insts/__init__.py b/src/arch/x86/isa/insts/__init__.py index 0ef617a87..d7a8bde19 100644 --- a/src/arch/x86/isa/insts/__init__.py +++ b/src/arch/x86/isa/insts/__init__.py @@ -53,7 +53,8 @@ # # Authors: Gabe Black -categories = ["general_purpose", +categories = ["romutil", + "general_purpose", "simd128", "simd64", "system", diff --git a/src/arch/x86/isa/insts/general_purpose/__init__.py b/src/arch/x86/isa/insts/general_purpose/__init__.py index 4f77cb233..23f955f08 100644 --- a/src/arch/x86/isa/insts/general_purpose/__init__.py +++ b/src/arch/x86/isa/insts/general_purpose/__init__.py @@ -65,7 +65,6 @@ categories = ["arithmetic", "load_segment_registers", "logical", "no_operation", - "processor_information", "rotate_and_shift", "semaphores", "string", diff --git a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py index a9b53acac..19d1c7789 100644 --- a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py +++ b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py @@ -246,7 +246,7 @@ def macroop DIV_B_R divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -269,7 +269,7 @@ def macroop DIV_B_M divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -293,7 +293,7 @@ def macroop DIV_B_P divLoopTop: div2 t1, rax, t1, dataSize=1 div2 t1, rax, t1, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax, dataSize=1 @@ -321,7 +321,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -347,7 +347,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -374,7 +374,7 @@ divLoopTop: div2 t1, rax, t1 div2 t1, rax, t1 div2 t1, rax, t1, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq rax @@ -422,7 +422,7 @@ def macroop IDIV_B_R divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -495,7 +495,7 @@ def macroop IDIV_B_M divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -569,7 +569,7 @@ def macroop IDIV_B_P divLoopTop: div2 t4, t1, t4, dataSize=1 div2 t4, t1, t4, flags=(EZF,), dataSize=1 - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5, dataSize=1 @@ -646,7 +646,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 @@ -721,7 +721,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 @@ -797,7 +797,7 @@ divLoopTop: div2 t4, t1, t4 div2 t4, t1, t4 div2 t4, t1, t4, flags=(EZF,) - bri t0, label("divLoopTop"), flags=(nCEZF,) + br label("divLoopTop"), flags=(nCEZF,) #Unload the answer divq t5 diff --git a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py index b5fc43fcd..dbd2d8b84 100644 --- a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py +++ b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py @@ -53,20 +53,42 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop PREFETCH_M +{ + ld t0, seg, sib, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_P +{ + rdip t7 + ld t0, seg, riprel, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_T0_M +{ + ld t0, seg, sib, disp, dataSize=1, prefetch=True +}; + +def macroop PREFETCH_T0_P +{ + rdip t7 + ld t0, seg, riprel, disp, dataSize=1, prefetch=True +}; + +''' + #let {{ # class LFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class SFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MFENCE(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class PREFETCHlevel(Inst): -# "GenFault ${new UnimpInstFault}" -# class PREFETCH(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class PREFETCHW(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class CLFLUSH(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py index 71059e80d..22364e038 100644 --- a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py +++ b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py @@ -82,11 +82,11 @@ # Authors: Gabe Black microcode = ''' -def macroop BSF_R_R { +def macroop BSR_R_R { # Determine if the input was zero, and also move it to a temp reg. movi t1, t1, t0, dataSize=8 and t1, regm, regm, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -125,20 +125,19 @@ def macroop BSF_R_R { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSF_R_M { +def macroop BSR_R_M { movi t1, t1, t0, dataSize=8 ld t1, seg, sib, disp # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -177,13 +176,12 @@ def macroop BSF_R_M { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSF_R_P { +def macroop BSR_R_P { rdip t7 movi t1, t1, t0, dataSize=8 @@ -191,7 +189,7 @@ def macroop BSF_R_P { # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0x0 @@ -230,17 +228,16 @@ def macroop BSF_R_P { srli t3, t1, 1, dataSize=8, flags=(EZF,) ori t4, reg, 0x1 mov reg, reg, t4, flags=(nCEZF,) - mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_R { +def macroop BSF_R_R { # Determine if the input was zero, and also move it to a temp reg. mov t1, t1, t0, dataSize=8 and t1, regm, regm, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register movi reg, reg, 0 @@ -248,48 +245,54 @@ def macroop BSR_R_R { subi t2, t1, 1 xor t1, t2, t1 + # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_M { +def macroop BSF_R_M { mov t1, t1, t0, dataSize=8 ld t1, seg, sib, disp # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register mov reg, reg, t0 @@ -298,40 +301,46 @@ def macroop BSR_R_M { xor t1, t2, t1 # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" }; -def macroop BSR_R_P { +def macroop BSF_R_P { rdip t7 mov t1, t1, t0, dataSize=8 @@ -339,7 +348,7 @@ def macroop BSR_R_P { # Determine if the input was zero, and also move it to a temp reg. and t1, t1, t1, flags=(ZF,) - bri t0, label("end"), flags=(CZF,) + br label("end"), flags=(CZF,) # Zero out the result register mov reg, reg, t0 @@ -348,34 +357,40 @@ def macroop BSR_R_P { xor t1, t2, t1 # Bit 6 - srli t3, t1, 32, dataSize=8 - andi t3, t3, 32 - or reg, reg, t3 + srli t3, t1, 32, dataSize=8, flags=(EZF,) + ori t4, reg, 32 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 5 - srli t3, t1, 16, dataSize=8 - andi t3, t3, 16 - or reg, reg, t3 + srli t3, t1, 16, dataSize=8, flags=(EZF,) + ori t4, reg, 16 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 4 - srli t3, t1, 8, dataSize=8 - andi t3, t3, 8 - or reg, reg, t3 + srli t3, t1, 8, dataSize=8, flags=(EZF,) + ori t4, reg, 8 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 3 - srli t3, t1, 4, dataSize=8 - andi t3, t3, 4 - or reg, reg, t3 + srli t3, t1, 4, dataSize=8, flags=(EZF,) + ori t4, reg, 4 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 2 - srli t3, t1, 2, dataSize=8 - andi t3, t3, 2 - or reg, reg, t3 + srli t3, t1, 2, dataSize=8, flags=(EZF,) + ori t4, reg, 2 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) # Bit 1 - srli t3, t1, 1, dataSize=8 - andi t3, t3, 1 - or reg, reg, t3 + srli t3, t1, 1, dataSize=8, flags=(EZF,) + ori t4, reg, 1 + mov reg, reg, t4, flags=(nCEZF,) + mov t1, t1, t3, flags=(nCEZF,) end: fault "NoFault" diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py index 45a7822fb..7abafe253 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py @@ -103,5 +103,5 @@ def macroop CALL_NEAR_P ''' #let {{ # class CALL(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py index 7039b4b5c..8203f7c2c 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -53,16 +53,194 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop IRET_REAL { + panic "Real mode iret isn't implemented!" +}; + +def macroop IRET_PROT { + .adjust_env oszIn64Override + + # Check for a nested task. This isn't supported at the moment. + rflag t1, NT + panic "Task switching with iret is unimplemented!", flags=(nCEZF,) + + #t1 = temp_RIP + #t2 = temp_CS + #t3 = temp_RFLAGS + #t4 = handy m5 register + + # Pop temp_RIP, temp_CS, and temp_RFLAGS + ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz + ld t2, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz + ld t3, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz + + # Read the handy m5 register for use later + rdm5reg t4 + + +### +### Handle if we're returning to virtual 8086 mode. +### + + #IF ((temp_RFLAGS.VM=1) && (CPL=0) && (LEGACY_MODE)) + # IRET_FROM_PROTECTED_TO_VIRTUAL + + #temp_RFLAGS.VM != 1 + rcri t0, t3, 18, flags=(ECF,) + br label("protToVirtFallThrough"), flags=(nCECF,) + + #CPL=0 + andi t0, t4, 0x30, flags=(EZF,) + br label("protToVirtFallThrough"), flags=(nCEZF,) + + #(LEGACY_MODE) + rcri t0, t4, 1, flags=(ECF,) + br label("protToVirtFallThrough"), flags=(nCECF,) + + panic "iret to virtual mode not supported" + +protToVirtFallThrough: + + + + #temp_CPL = temp_CS.rpl + andi t5, t2, 0x3 + + +### +### Read in the info for the new CS segment. +### + + #CS = READ_DESCRIPTOR (temp_CS, iret_chk) + andi t0, t2, 0xFC, flags=(EZF,), dataSize=2 + br label("processCSDescriptor"), flags=(CEZF,) + andi t6, t2, 0xF8, dataSize=8 + andi t0, t2, 0x4, flags=(EZF,), dataSize=2 + br label("globalCSDescriptor"), flags=(CEZF,) + ld t8, tsl, [1, t0, t6], dataSize=8 + br label("processCSDescriptor") +globalCSDescriptor: + ld t8, tsg, [1, t0, t6], dataSize=8 +processCSDescriptor: + chks t2, t6, dataSize=8 + + +### +### Get the new stack pointer and stack segment off the old stack if necessary, +### and piggyback on the logic to check the new RIP value. +### + #IF ((64BIT_MODE) || (temp_CPL!=CPL)) + #{ + + #(64BIT_MODE) + andi t0, t4, 0xE, flags=(EZF,) + # Since we just found out we're in 64 bit mode, take advantage and + # do the appropriate RIP checks. + br label("doPopStackStuffAndCheckRIP"), flags=(CEZF,) + + # Here, we know we're -not- in 64 bit mode, so we should do the + # appropriate/other RIP checks. + # if temp_RIP > CS.limit throw #GP(0) + rdlimit t6, cs, dataSize=8 + subi t0, t1, t6, flags=(ECF,) + fault "new GeneralProtection(0)", flags=(CECF,) + + #(temp_CPL!=CPL) + srli t7, t4, 4 + xor t7, t7, t5 + andi t0, t7, 0x3, flags=(EZF,) + br label("doPopStackStuff"), flags=(nCEZF,) + # We can modify user visible state here because we're know + # we're done with things that can fault. + addi rsp, rsp, "3 * env.stackSize" + br label("fallThroughPopStackStuff") + +doPopStackStuffAndCheckRIP: + # Check if the RIP is canonical. + sra t7, t1, 47, flags=(EZF,), dataSize=ssz + # if t7 isn't 0 or -1, it wasn't canonical. + br label("doPopStackStuff"), flags=(CEZF,) + addi t0, t7, 1, flags=(EZF,), dataSize=ssz + fault "new GeneralProtection(0)", flags=(nCEZF,) + +doPopStackStuff: + # POP.v temp_RSP + ld t6, ss, [1, t0, rsp], "3 * env.dataSize", dataSize=ssz + # POP.v temp_SS + ld t9, ss, [1, t0, rsp], "4 * env.dataSize", dataSize=ssz + # SS = READ_DESCRIPTOR (temp_SS, ss_chk) + andi t0, t9, 0xFC, flags=(EZF,), dataSize=2 + br label("processSSDescriptor"), flags=(CEZF,) + andi t7, t9, 0xF8, dataSize=8 + andi t0, t9, 0x4, flags=(EZF,), dataSize=2 + br label("globalSSDescriptor"), flags=(CEZF,) + ld t7, tsl, [1, t0, t7], dataSize=8 + br label("processSSDescriptor") +globalSSDescriptor: + ld t7, tsg, [1, t0, t7], dataSize=8 +processSSDescriptor: + chks t9, t7, dataSize=8 + + # This actually updates state which is wrong. It should wait until we know + # we're not going to fault. Unfortunately, that's hard to do. + wrdl ss, t7, t9 + wrsel ss, t9 + +### +### From this point downwards, we can't fault. We can update user visible state. +### + # RSP.s = temp_RSP + mov rsp, rsp, t6, dataSize=ssz + + #} + +fallThroughPopStackStuff: + + # Update CS + wrdl cs, t8, t2 + wrsel cs, t2 + + #CPL = temp_CPL + + #IF (changing CPL) + #{ + srli t7, t4, 4 + xor t7, t7, t5 + andi t0, t7, 0x3, flags=(EZF,) + br label("skipSegmentSquashing"), flags=(CEZF,) + + # The attribute register needs to keep track of more info before this will + # work the way it needs to. + # FOR (seg = ES, DS, FS, GS) + # IF ((seg.attr.dpl < cpl && ((seg.attr.type = 'data') + # || (seg.attr.type = 'non-conforming-code'))) + # { + # seg = NULL + # } + #} + +skipSegmentSquashing: + + # Ignore this for now. + #RFLAGS.v = temp_RFLAGS + wrflags t0, t3 + # VIF,VIP,IOPL only changed if (old_CPL = 0) + # IF only changed if (old_CPL <= old_RFLAGS.IOPL) + # VM unchanged + # RF cleared + + #RIP = temp_RIP + wrip t0, t1, dataSize=ssz +}; + +def macroop IRET_VIRT { + panic "Virtual mode iret isn't implemented!" +}; +''' #let {{ # class INT(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class INTO(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRET(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRETD(Inst): -# "GenFault ${new UnimpInstFault}" -# class IRETQ(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py index 0b2e81cbd..57ec9da26 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -85,7 +85,7 @@ def macroop RET_FAR { ld t1, ss, [1, t0, rsp] # Get the return CS - ld t2, ss, [1, t0, rsp], dsz + ld t2, ss, [1, t0, rsp], ssz # Get the rpl andi t3, t2, 0x3 @@ -96,14 +96,23 @@ def macroop RET_FAR { # that doesn't happen yet. # Do stuff if they're equal - chks t4, t2, flags=(EZF,) - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t3, flatseg, [1, t0, t4], addressSize=8, dataSize=8 - wrdl cs, t3, t2 + andi t0, t2, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t3, t2, 0xF8, dataSize=8 + andi t0, t2, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t3], dataSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t3], dataSize=8 +processDescriptor: + chks t2, t3, IretCheck, dataSize=8 # There should be validity checks on the RIP checks here, but I'll do # that later. + wrdl cs, t3, t2 + wrsel cs, t2 wrip t0, t1 - bri t0, label("end") + br label("end") # Do other stuff if they're not. end: diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py index a1e322e56..2cbdd1ad8 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py @@ -56,11 +56,11 @@ microcode = "" #let {{ # class AAA(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAM(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class AAS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py index 213724768..d220fdeb6 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py @@ -56,7 +56,7 @@ microcode = "" #let {{ # class DAA(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class DAS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py index b98d09816..ac2343462 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py @@ -53,8 +53,26 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop BSWAP_D_R +{ + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 +}; + +def macroop BSWAP_Q_R +{ + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 + roli reg, reg, 32, dataSize=8 + roli reg, reg, 8, dataSize=2 + roli reg, reg, 16, dataSize=4 + roli reg, reg, 8, dataSize=2 +}; +''' #let {{ # class BSWAP(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py index 1e0810594..01fa280fc 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py @@ -56,7 +56,7 @@ microcode = "" #let {{ # class MOVMSKPS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOVMSKPD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py index d6ae7885a..c334693e5 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py +++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py @@ -55,7 +55,7 @@ microcode = ''' def macroop XLAT { - zexti t1, rax, 7 + zexti t1, rax, 7, dataSize=8 # Here, t1 can be used directly. The value of al is supposed to be treated # as unsigned. Since we zero extended it from 8 bits above and the address # size has to be at least 16 bits, t1 will not be sign extended. diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py index 3b8608c48..60c046d04 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py +++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -126,18 +126,19 @@ def macroop MOVSXD_R_P { }; def macroop MOVSX_B_R_R { - sexti reg, regm, 7 + mov t1, t1, regm, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_B_R_M { - ld reg, seg, sib, disp, dataSize=1 - sexti reg, reg, 7 + ld t1, seg, sib, disp, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_B_R_P { rdip t7 - ld reg, seg, riprel, disp, dataSize=1 - sexti reg, reg, 7 + ld t1, seg, riprel, disp, dataSize=1 + sexti reg, t1, 7 }; def macroop MOVSX_W_R_R { @@ -160,7 +161,8 @@ def macroop MOVSX_W_R_P { # def macroop MOVZX_B_R_R { - zexti reg, regm, 7 + mov t1, t1, regm, dataSize=1 + zexti reg, t1, 7 }; def macroop MOVZX_B_R_M { @@ -190,13 +192,25 @@ def macroop MOVZX_W_R_P { }; def macroop MOV_C_R { + .adjust_env maxOsz wrcr reg, regm }; def macroop MOV_R_C { + .adjust_env maxOsz rdcr reg, regm }; +def macroop MOV_D_R { + .adjust_env maxOsz + wrdr reg, regm +}; + +def macroop MOV_R_D { + .adjust_env maxOsz + rddr reg, regm +}; + def macroop MOV_R_S { rdsel reg, regm }; @@ -213,7 +227,7 @@ def macroop MOV_P_S { }; def macroop MOV_REAL_S_R { - zext t2, regm, 15 + zexti t2, regm, 15, dataSize=8 slli t3, t2, 2, dataSize=8 wrsel reg, regm wrbase reg, t3 @@ -221,87 +235,121 @@ def macroop MOV_REAL_S_R { def macroop MOV_REAL_S_M { ld t1, seg, sib, disp, dataSize=2 - zext t2, t1, 15 + zexti t2, t1, 15, dataSize=8 slli t3, t2, 2, dataSize=8 wrsel reg, t1 wrbase reg, t3 }; def macroop MOV_REAL_S_P { - rdip t7 - ld t1, seg, riprel, disp, dataSize=2 - zext t2, t1, 15 - slli t3, t2, 2, dataSize=8 - wrsel reg, t1 - wrbase reg, t3 + panic "RIP relative addressing shouldn't happen in real mode" }; def macroop MOV_S_R { - chks t1, regm, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, regm -end: + andi t0, regm, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, regm, 0xF8, dataSize=8 + andi t0, regm, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks regm, t3, dataSize=8 + wrdl reg, t3, regm wrsel reg, regm }; def macroop MOV_S_M { ld t1, seg, sib, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 -end: + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOV_S_P { rdip t7 ld t1, seg, riprel, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - bri t0, label("end"), flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 -end: + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOVSS_S_R { - chks t1, regm, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, regm + andi t0, regm, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, regm, 0xF8, dataSize=8 + andi t0, regm, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks regm, t3, SSCheck, dataSize=8 + wrdl reg, t3, regm wrsel reg, regm }; def macroop MOVSS_S_M { ld t1, seg, sib, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, SSCheck, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; def macroop MOVSS_S_P { rdip t7 ld t1, seg, riprel, disp, dataSize=2 - chks t2, t1, flags=(EZF,), dataSize=8 - # This actually needs to use the selector as the error code, but it would - # be hard to get that information into the instruction at the moment. - fault "new GeneralProtection(0)", flags=(CEZF,) - ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8 - wrdl reg, t2, t1 + andi t0, t1, 0xFC, flags=(EZF,), dataSize=2 + br label("processDescriptor"), flags=(CEZF,) + andi t2, t1, 0xF8, dataSize=8 + andi t0, t1, 0x4, flags=(EZF,), dataSize=2 + br label("globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8 + br label("processDescriptor") +globalDescriptor: + ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8 +processDescriptor: + chks t1, t3, SSCheck, dataSize=8 + wrdl reg, t3, t1 wrsel reg, t1 }; ''' #let {{ # class MOVD(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOVNTI(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py index 6c51f3171..82fdffc63 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py +++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -58,8 +58,8 @@ def macroop POP_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - addi rsp, rsp, dsz + ld t1, ss, [1, t0, rsp], dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz mov reg, reg, t1 }; @@ -67,10 +67,10 @@ def macroop POP_M { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - cda seg, sib, disp - addi rsp, rsp, dsz - st t1, seg, sib, disp + ld t1, ss, [1, t0, rsp], dataSize=ssz + cda seg, sib, disp, dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz + st t1, seg, sib, disp, dataSize=ssz }; def macroop POP_P { @@ -78,17 +78,17 @@ def macroop POP_P { .adjust_env oszIn64Override rdip t7 - ld t1, ss, [1, t0, rsp] - cda seg, sib, disp - addi rsp, rsp, dsz - st t1, seg, riprel, disp + ld t1, ss, [1, t0, rsp], dataSize=ssz + cda seg, sib, disp, dataSize=ssz + addi rsp, rsp, ssz, dataSize=asz + st t1, seg, riprel, disp, dataSize=ssz }; def macroop PUSH_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - stupd reg, ss, [1, t0, rsp], "-env.dataSize" + stupd reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_I { @@ -96,15 +96,15 @@ def macroop PUSH_I { .adjust_env oszIn64Override limm t1, imm - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_M { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - ld t1, seg, sib, disp - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + ld t1, seg, sib, disp, dataSize=ssz + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSH_P { @@ -112,48 +112,48 @@ def macroop PUSH_P { .adjust_env oszIn64Override rdip t7 - ld t1, seg, riprel, disp - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + ld t1, seg, riprel, disp, dataSize=ssz + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop PUSHA { # Check all the stack addresses. We'll assume that if the beginning and # end are ok, then the stuff in the middle should be as well. - cda ss, [1, t0, rsp], "-env.dataSize" - cda ss, [1, t0, rsp], "-8 * env.dataSize" - stupd rax, ss, [1, t0, rsp], "-env.dataSize" - stupd rcx, ss, [1, t0, rsp], "-env.dataSize" - stupd rdx, ss, [1, t0, rsp], "-env.dataSize" - stupd rbx, ss, [1, t0, rsp], "-env.dataSize" - stupd rsp, ss, [1, t0, rsp], "-env.dataSize" - stupd rbp, ss, [1, t0, rsp], "-env.dataSize" - stupd rsi, ss, [1, t0, rsp], "-env.dataSize" - stupd rdi, ss, [1, t0, rsp], "-env.dataSize" + cda ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + cda ss, [1, t0, rsp], "-8 * env.stackSize", dataSize=ssz + stupd rax, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rcx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rdx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rbx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rsp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rsi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz + stupd rdi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop POPA { # Check all the stack addresses. We'll assume that if the beginning and # end are ok, then the stuff in the middle should be as well. - ld t1, ss, [1, t0, rsp], "0 * env.dataSize" - ld t2, ss, [1, t0, rsp], "7 * env.dataSize" - mov rdi, rdi, t1 - ld rsi, ss, [1, t0, rsp], "1 * env.dataSize" - ld rbp, ss, [1, t0, rsp], "2 * env.dataSize" - ld rbx, ss, [1, t0, rsp], "4 * env.dataSize" - ld rdx, ss, [1, t0, rsp], "5 * env.dataSize" - ld rcx, ss, [1, t0, rsp], "6 * env.dataSize" - mov rax, rax, t2 - addi rsp, rsp, "8 * env.dataSize" + ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz + ld t2, ss, [1, t0, rsp], "7 * env.stackSize", dataSize=ssz + mov rdi, rdi, t1, dataSize=ssz + ld rsi, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz + ld rbp, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz + ld rbx, ss, [1, t0, rsp], "4 * env.stackSize", dataSize=ssz + ld rdx, ss, [1, t0, rsp], "5 * env.stackSize", dataSize=ssz + ld rcx, ss, [1, t0, rsp], "6 * env.stackSize", dataSize=ssz + mov rax, rax, t2, dataSize=ssz + addi rsp, rsp, "8 * env.stackSize", dataSize=asz }; def macroop LEAVE { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override - mov t1, t1, rbp - ld rbp, ss, [1, t0, t1] - mov rsp, rsp, t1 - addi rsp, rsp, dsz + mov t1, t1, rbp, dataSize=asz + ld rbp, ss, [1, t0, t1], dataSize=ssz + mov rsp, rsp, t1, dataSize=asz + addi rsp, rsp, ssz, dataSize=asz }; def macroop ENTER_I_I { @@ -162,41 +162,41 @@ def macroop ENTER_I_I { # Pull the different components out of the immediate limm t1, imm - zexti t2, t1, 15, dataSize=2 + zexti t2, t1, 15, dataSize=8 srl t1, t1, 16 - zexti t1, t1, 5 + zexti t1, t1, 5, dataSize=8 # t1 is now the masked nesting level, and t2 is the amount of storage. # Push rbp. - stupd rbp, ss, [1, t0, rsp], "-env.dataSize" + stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz # Save the stack pointer for later - mov t6, t6, rsp + mov t6, t6, rsp, dataSize=asz # If the nesting level is zero, skip all this stuff. subi t0, t1, t0, flags=(EZF,), dataSize=2 - bri t0, label("skipLoop"), flags=(CEZF,) + br label("skipLoop"), flags=(CEZF,) # If the level was 1, only push the saved rbp subi t0, t1, 1, flags=(EZF,) - bri t0, label("bottomOfLoop"), flags=(CEZF,) + br label("bottomOfLoop"), flags=(CEZF,) limm t4, "ULL(-1)", dataSize=8 topOfLoop: - ld t5, ss, [dsz, t4, rbp] - stupd t5, ss, [1, t0, rsp], "-env.dataSize" + ld t5, ss, [ssz, t4, rbp], dataSize=ssz + stupd t5, ss, [1, t0, rsp], "-env.stackSize" # If we're not done yet, loop subi t4, t4, 1, dataSize=8 add t0, t4, t1, flags=(EZF,) - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) bottomOfLoop: # Push the old rbp onto the stack - stupd t6, ss, [1, t0, rsp], "-env.dataSize" + stupd t6, ss, [1, t0, rsp], "-env.stackSize" skipLoop: - sub rsp, rsp, t2 - mov rbp, rbp, t6 + sub rsp, rsp, t2, dataSize=asz + mov rbp, rbp, t6, dataSize=asz }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py index fe60350c1..59f6aaec2 100644 --- a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py +++ b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -57,17 +57,15 @@ microcode = ''' def macroop PUSHF { .adjust_env oszIn64Override - # This should really read the whole flags register, not just user flags. - ruflags t1 - stupd t1, ss, [1, t0, rsp], "-env.dataSize" + rflags t1 + stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz }; def macroop POPF { .adjust_env oszIn64Override - ld t1, ss, [1, t0, rsp] - addi rsp, rsp, dsz - # This should really write the whole flags register, not just user flags. - wruflags t1, t0 + ld t1, ss, [1, t0, rsp], dataSize=ssz + addi rsp, rsp, ssz + wrflags t1, t0 }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py index 4c655e0b2..e151dc61d 100644 --- a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py +++ b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -84,10 +84,18 @@ def macroop CMC { ruflags t1 wruflagsi t1, "CFBit" }; + +def macroop STI { + rflags t1 + limm t2, "IFBit" + or t1, t1, t2 + wrflags t1, t0 +}; + +def macroop CLI { + rflags t1 + limm t2, "~IFBit" + and t1, t1, t2 + wrflags t1, t0 +}; ''' -#let {{ -# class CLI(Inst): -# "GenFault ${new UnimpInstFault}" -# class STI(Inst): -# "GenFault ${new UnimpInstFault}" -#}}; diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py index 1986a322e..4e3c9b316 100644 --- a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py +++ b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py @@ -84,25 +84,23 @@ microcode = ''' def macroop IN_R_I { .adjust_imm trimImm(8) - limm t1, "IntAddrPrefixIO", dataSize=8 - ld reg, intseg, [1, t1, t0], imm, addressSize=8 + limm t1, imm, dataSize=asz + ld reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop IN_R_R { - limm t1, "IntAddrPrefixIO", dataSize=8 - zexti t2, regm, 15, dataSize=2 - ld reg, intseg, [1, t1, t2], addressSize=8 + zexti t2, regm, 15, dataSize=8 + ld reg, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop OUT_I_R { .adjust_imm trimImm(8) - limm t1, "IntAddrPrefixIO", dataSize=8 - st reg, intseg, [1, t1, t0], imm, addressSize=8 + limm t1, imm, dataSize=8 + st reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8 }; def macroop OUT_R_R { - limm t1, "IntAddrPrefixIO", dataSize=8 - zexti t2, reg, 15, dataSize=2 - st regm, intseg, [1, t1, t2], addressSize=8 + zexti t2, reg, 15, dataSize=8 + st regm, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py index b44203d9c..b3bc5ab67 100644 --- a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py +++ b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -61,32 +61,33 @@ def macroop INS_M_R { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 - ld t6, intseg, [1, t1, t2], addressSize=8 + ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 st t6, es, [1, t0, rdi] add rdi, rdi, t3, dataSize=asz }; def macroop INS_E_M_R { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 topOfLoop: - ld t6, intseg, [1, t1, t2], addressSize=8 + ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 st t6, es, [1, t0, rdi] subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; @@ -97,32 +98,33 @@ def macroop OUTS_R_M { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 ld t6, ds, [1, t0, rsi] - st t6, intseg, [1, t1, t2], addressSize=8 + st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 add rsi, rsi, t3, dataSize=asz }; def macroop OUTS_E_R_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - limm t1, "IntAddrPrefixIO" - zexti t2, reg, 15, dataSize=2 + zexti t2, reg, 15, dataSize=8 topOfLoop: ld t6, ds, [1, t0, rsi] - st t6, intseg, [1, t1, t2], addressSize=8 + st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8 subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py index 8aec4b99e..e6633ee1a 100644 --- a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py +++ b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py @@ -56,17 +56,17 @@ microcode = "" #let {{ # class LDS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LES(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LFS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LGS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class LSS(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class MOV_SEG(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class POP(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/processor_information.py b/src/arch/x86/isa/insts/general_purpose/processor_information.py deleted file mode 100644 index 6070169ac..000000000 --- a/src/arch/x86/isa/insts/general_purpose/processor_information.py +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company -# All rights reserved. -# -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the -# following conditions are met: -# -# The software must be used only for Non-Commercial Use which means any -# use which is NOT directed to receiving any direct monetary -# compensation for, or commercial advantage from such use. Illustrative -# examples of non-commercial use are academic research, personal study, -# teaching, education and corporate research & development. -# Illustrative examples of commercial use are distributing products for -# commercial advantage and providing services using the software for -# commercial advantage. -# -# If you wish to use this software or functionality therein that may be -# covered by patents for commercial use, please contact: -# Director of Intellectual Property Licensing -# Office of Strategy and Technology -# Hewlett-Packard Company -# 1501 Page Mill Road -# Palo Alto, California 94304 -# -# Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. Redistributions -# in binary form must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. Neither the name of -# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. No right of -# sublicense is granted herewith. Derivatives of the software and -# output created using the software may be prepared, but only for -# Non-Commercial Uses. Derivatives of the software may be shared with -# others provided: (i) the others agree to abide by the list of -# conditions herein which includes the Non-Commercial Use restrictions; -# and (ii) such Derivatives of the software include the above copyright -# notice to acknowledge the contribution from this software where -# applicable, this list of conditions and the disclaimer below. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Gabe Black - -microcode = ''' -def macroop CPUID_R { - -# -# Find which type of cpuid function it is by checking bit 31. Also clear that -# bit to form an offset into the functions of that type. -# - limm t1, 0x80000000, dataSize=4 - and t2, t1, rax, flags=(EZF,) - # clear the bit - xor t1, t2, rax - -# -# Do range checking on the offset -# - # If EZF is set, the function is standard and the max is 0x1. - movi t2, t2, 0x1, flags=(CEZF,) - # If EZF is cleared, the function is extended and the max is 0x18. - movi t2, t2, 0x18, flags=(nCEZF,) - subi t0, t1, t2, flags=(ECF,) - # ECF will be set if the offset is too large. - bri t0, label("end"), flags=(nCECF,) - - -# -# Jump to the right portion -# - movi t2, t2, label("standardStart"), flags=(CEZF,) - movi t2, t2, label("extendedStart"), flags=(nCEZF,) - # This gives each function 8 microops to use. It's wasteful because only - # 5 will be needed, but a multiply would be expensive. In the system - # described in the RISC86 patent, the fifth instruction would really be - # the sequencing field on an op quad, so each function would be implemented - # by -exactly- one op quad. Since we're approximating, this should be ok. - slli t1, t1, 3 - br t2, t1 - -############################################################################# -############################################################################# - -# -# Standard functions. -# - -standardStart: - -# 0x00000000 -- Processor Vendor and Largest Standard Function Number - limm rax, 0x00000001, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x00000001 -- Family, Model, Stepping Identifiers - limm rax, 0x00020f51, dataSize=4 - limm rbx, 0x00000405, dataSize=4 - limm rdx, 0xe3d3fbff, dataSize=4 - limm rcx, 0x00000001, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# -# Extended functions. -# - -extendedStart: - -# 0x80000000 -- Processor Vendor and Largest Extended Function Number - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000001 -- EAX: AMD Family, Model, Stepping -# EBX: BrandId Identifier -# ECX: Feature Identifiers -# EDX: Feature Identifiers - limm rax, 0x00020f51, dataSize=4 - limm rbx, 0x00000405, dataSize=4 - limm rdx, 0xe3d3fbff, dataSize=4 - limm rcx, 0x00000001, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000002 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000003 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000004 -- Processor Name String Identifier - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000005 -- L1 Cache and TLB Identifiers - limm rax, 0xff08ff08, dataSize=4 - limm rbx, 0xff20ff20, dataSize=4 - limm rdx, 0x40020140, dataSize=4 - limm rcx, 0x40020140, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000006 -- L2/L3 Cache and L2 TLB Identifiers - limm rax, 0x00000000, dataSize=4 - limm rbx, 0x42004200, dataSize=4 - limm rdx, 0x00000000, dataSize=4 - limm rcx, 0x04008140, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000007 -- Advanced Power Management Information - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000008 -- Long Mode Address Size Identification - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000009 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000A -- SVM Revision and Feature Identification - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000B -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000C -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000D -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000E -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x8000000F -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000010 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000011 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000012 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000013 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000014 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000015 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000016 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000017 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -# 0x80000018 -- Reserved - # JUNK VALUES - limm rax, 0x80000018, dataSize=4 - limm rbx, 0x68747541, dataSize=4 - limm rdx, 0x69746e65, dataSize=4 - limm rcx, 0x444d4163, dataSize=4 - bri t0, label("end") - fault "NoFault" - fault "NoFault" - fault "NoFault" - -end: - fault "NoFault" -}; -''' diff --git a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py index ed7d761b8..caaeca974 100644 --- a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py +++ b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py @@ -56,13 +56,13 @@ microcode = ''' def macroop SAL_R_I { - slli reg, reg, imm, flags=(SF,ZF,PF) + slli reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_M_I { ldst t1, seg, sib, disp - slli t1, t1, imm, flags=(SF,ZF,PF) + slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -70,19 +70,19 @@ def macroop SAL_P_I { rdip t7 ldst t1, seg, riprel, disp - slli t1, t1, imm, flags=(SF,ZF,PF) + slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAL_1_R { - slli reg, reg, 1, flags=(SF,ZF,PF) + slli reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_1_M { ldst t1, seg, sib, disp - slli t1, t1, 1, flags=(SF,ZF,PF) + slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -90,19 +90,19 @@ def macroop SAL_1_P { rdip t7 ldst t1, seg, riprel, disp - slli t1, t1, 1, flags=(SF,ZF,PF) + slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAL_R_R { - sll reg, reg, regm, flags=(SF,ZF,PF) + sll reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAL_M_R { ldst t1, seg, sib, disp - sll t1, t1, reg, flags=(SF,ZF,PF) + sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -110,19 +110,19 @@ def macroop SAL_P_R { rdip t7 ldst t1, seg, riprel, disp - sll t1, t1, reg, flags=(SF,ZF,PF) + sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_R_I { - srli reg, reg, imm, flags=(SF,ZF,PF) + srli reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_M_I { ldst t1, seg, sib, disp - srli t1, t1, imm, flags=(SF,ZF,PF) + srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -130,19 +130,19 @@ def macroop SHR_P_I { rdip t7 ldst t1, seg, riprel, disp - srli t1, t1, imm, flags=(SF,ZF,PF) + srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_1_R { - srli reg, reg, 1, flags=(SF,ZF,PF) + srli reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_1_M { ldst t1, seg, sib, disp - srli t1, t1, 1, flags=(SF,ZF,PF) + srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -150,19 +150,19 @@ def macroop SHR_1_P { rdip t7 ldst t1, seg, riprel, disp - srli t1, t1, 1, flags=(SF,ZF,PF) + srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SHR_R_R { - srl reg, reg, regm, flags=(SF,ZF,PF) + srl reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SHR_M_R { ldst t1, seg, sib, disp - srl t1, t1, reg, flags=(SF,ZF,PF) + srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -170,19 +170,54 @@ def macroop SHR_P_R { rdip t7 ldst t1, seg, riprel, disp - srl t1, t1, reg, flags=(SF,ZF,PF) + srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF) + st t1, seg, riprel, disp +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_R_R_I +{ + srli t1, reg, imm, flags=(CF,) + rori t2, regm, imm + srli t3, regm, imm + xor t2, t2, t3 + or reg, t1, t2 +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_M_R_I +{ + ldst t1, seg, sib, disp + srli t1, t1, imm, flags=(CF,) + rori t2, reg, imm + srli t3, reg, imm + xor t2, t2, t3 + or t1, t1, t2 + st t1, seg, sib, disp +}; + +# SHRD will not set OF correctly when the shift count is 1. +def macroop SHRD_P_R_I +{ + rdip t7 + ldst t1, seg, riprel, disp + srli t1, t1, imm, flags=(CF,) + rori t2, reg, imm + srli t3, reg, imm + xor t2, t2, t3 + or t1, t1, t2 st t1, seg, riprel, disp }; def macroop SAR_R_I { - srai reg, reg, imm, flags=(SF,ZF,PF) + srai reg, reg, imm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_M_I { ldst t1, seg, sib, disp - srai t1, t1, imm, flags=(SF,ZF,PF) + srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -190,19 +225,19 @@ def macroop SAR_P_I { rdip t7 ldst t1, seg, riprel, disp - srai t1, t1, imm, flags=(SF,ZF,PF) + srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAR_1_R { - srai reg, reg, 1, flags=(SF,ZF,PF) + srai reg, reg, 1, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_1_M { ldst t1, seg, sib, disp - srai t1, t1, 1, flags=(SF,ZF,PF) + srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -210,19 +245,19 @@ def macroop SAR_1_P { rdip t7 ldst t1, seg, riprel, disp - srai t1, t1, 1, flags=(SF,ZF,PF) + srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; def macroop SAR_R_R { - sra reg, reg, regm, flags=(SF,ZF,PF) + sra reg, reg, regm, flags=(CF,OF,SF,ZF,PF) }; def macroop SAR_M_R { ldst t1, seg, sib, disp - sra t1, t1, reg, flags=(SF,ZF,PF) + sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, sib, disp }; @@ -230,7 +265,7 @@ def macroop SAR_P_R { rdip t7 ldst t1, seg, riprel, disp - sra t1, t1, reg, flags=(SF,ZF,PF) + sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF) st t1, seg, riprel, disp }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/semaphores.py b/src/arch/x86/isa/insts/general_purpose/semaphores.py index 27a31dbd9..f23241863 100644 --- a/src/arch/x86/isa/insts/general_purpose/semaphores.py +++ b/src/arch/x86/isa/insts/general_purpose/semaphores.py @@ -78,10 +78,30 @@ def macroop CMPXCHG_P_R { st t1, seg, riprel, disp mov rax, rax, t1, flags=(nCZF,) }; + +def macroop XADD_M_R { + ldst t1, seg, sib, disp + add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF) + st t2, seg, sib, disp + mov reg, reg, t1 +}; + +def macroop XADD_P_R { + rdip t7 + ldst t1, seg, riprel, disp + add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF) + st t2, seg, riprel, disp + mov reg, reg, t1 +}; + +def macroop XADD_R_R { + add t2, regm, reg, flags=(OF,SF,ZF,AF,PF,CF) + mov regm, regm, reg + mov reg, reg, t2 +}; + ''' #let {{ -# class XADD(Inst): -# "GenFault ${new UnimpInstFault}" # class XCHG(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py index 71b8511b4..561b8a415 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py +++ b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -75,12 +75,16 @@ def macroop CMPS_M_M { # def macroop CMPS_E_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, seg, [1, t0, rsi] ld t2, es, [1, t0, rdi] sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF) @@ -88,17 +92,22 @@ def macroop CMPS_E_M_M { subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, 4, flags=(CSTRZnEZF,) + br label("topOfLoop"), flags=(CSTRZnEZF,) +end: fault "NoFault" }; def macroop CMPS_N_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, seg, [1, t0, rsi] ld t2, es, [1, t0, rdi] sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF) @@ -106,7 +115,8 @@ def macroop CMPS_N_M_M { subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, 4, flags=(CSTRnZnEZF,) + br label("topOfLoop"), flags=(CSTRnZnEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/load_string.py b/src/arch/x86/isa/insts/general_purpose/string/load_string.py index 61525c2f2..14198701a 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/load_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/load_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -61,12 +61,14 @@ def macroop LODS_M { subi t4, t0, dsz, dataSize=asz mov t3, t3, t4, flags=(nCEZF,), dataSize=asz - ld rax, seg, [1, t0, rdi] + ld rax, seg, [1, t0, rsi] - add rdi, rdi, t3, dataSize=asz + add rsi, rsi, t3, dataSize=asz }; def macroop LODS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -74,11 +76,12 @@ def macroop LODS_E_M { mov t3, t3, t4, flags=(nCEZF,), dataSize=asz topOfLoop: - ld rax, seg, [1, t0, rdi] + ld rax, seg, [1, t0, rsi] subi rcx, rcx, 1, flags=(EZF,), dataSize=asz - add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + add rsi, rsi, t3, dataSize=asz + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/move_string.py b/src/arch/x86/isa/insts/general_purpose/string/move_string.py index b64acfdc2..18faa38e2 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/move_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/move_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -69,6 +69,8 @@ def macroop MOVS_M_M { }; def macroop MOVS_E_M_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -82,7 +84,8 @@ topOfLoop: subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz add rsi, rsi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py index b038cc00a..5b0e74aad 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -73,34 +73,44 @@ def macroop SCAS_M { # def macroop SCAS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t2, t2, dsz, flags=(CEZF,), dataSize=asz subi t3, t0, dsz, dataSize=asz mov t2, t2, t3, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, es, [1, t0, rdi] sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF) subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t2, dataSize=asz - bri t0, 4, flags=(CSTRZnEZF,) + br label("topOfLoop"), flags=(CSTRZnEZF,) +end: fault "NoFault" }; def macroop SCAS_N_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) + # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t2, t2, dsz, flags=(CEZF,), dataSize=asz subi t3, t0, dsz, dataSize=asz mov t2, t2, t3, flags=(nCEZF,), dataSize=asz +topOfLoop: ld t1, es, [1, t0, rdi] sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF) subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t2, dataSize=asz - bri t0, 4, flags=(CSTRnZnEZF,) + br label("topOfLoop"), flags=(CSTRnZnEZF,) +end: fault "NoFault" }; diff --git a/src/arch/x86/isa/insts/general_purpose/string/store_string.py b/src/arch/x86/isa/insts/general_purpose/string/store_string.py index a8d558929..fe9917ce6 100644 --- a/src/arch/x86/isa/insts/general_purpose/string/store_string.py +++ b/src/arch/x86/isa/insts/general_purpose/string/store_string.py @@ -1,4 +1,4 @@ -# Copyright (c) 2007 The Hewlett-Packard Development Company +# Copyright (c) 2007-2008 The Hewlett-Packard Development Company # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -67,6 +67,8 @@ def macroop STOS_M { }; def macroop STOS_E_M { + and t0, rcx, rcx, flags=(EZF,), dataSize=asz + br label("end"), flags=(CEZF,) # Find the constant we need to either add or subtract from rdi ruflag t0, 10 movi t3, t3, dsz, flags=(CEZF,), dataSize=asz @@ -78,7 +80,8 @@ topOfLoop: subi rcx, rcx, 1, flags=(EZF,), dataSize=asz add rdi, rdi, t3, dataSize=asz - bri t0, label("topOfLoop"), flags=(nCEZF,) + br label("topOfLoop"), flags=(nCEZF,) +end: fault "NoFault" }; ''' diff --git a/src/arch/x86/isa/insts/general_purpose/system_calls.py b/src/arch/x86/isa/insts/general_purpose/system_calls.py index e056bea84..67607d5f8 100644 --- a/src/arch/x86/isa/insts/general_purpose/system_calls.py +++ b/src/arch/x86/isa/insts/general_purpose/system_calls.py @@ -53,14 +53,183 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop SYSCALL_64 +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + # Save the next RIP. + rdip rcx + + # Stick rflags with RF masked into r11. + rflags t2 + limm t3, "~RFBit" + andi r11, t2, t3, dataSize=8 + + rdval t3, star + srli t3, t3, 32, dataSize=8 + andi t3, t3, 0xFC, dataSize=1 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=0, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Set up SS. + addi t3, t3, 8 + wrsel ss, t3 + wrbase ss, t0, dataSize=8 + wrlimit ss, t1, dataSize=4 + # Writable, readable, not expandDown, + # dpl=0, defaultSize=0, not long mode + limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (0 << 6)) + wrattr ss, t4 + + # Set the new rip. + rdval t7, lstar + wrip t0, t7 + + # Mask the flags against sf_mask and leave RF turned off. + rdval t3, sf_mask, dataSize=8 + xor t3, t3, t1, dataSize=8 + and t3, t3, r11, dataSize=8 + wrflags t3, t0 +}; + +def macroop SYSCALL_COMPAT +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + # Save the next RIP. + rdip rcx + + # Stick rflags with RF masked into r11. + rflags t2 + limm t3, "~RFBit" + andi r11, t2, t3, dataSize=8 + + rdval t3, star + srli t3, t3, 32, dataSize=8 + andi t3, t3, 0xFC, dataSize=1 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=0, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Set up SS. + addi t3, t3, 8 + wrsel ss, t3 + wrbase ss, t0, dataSize=8 + wrlimit ss, t1, dataSize=4 + # Writable, readable, not expandDown, + # dpl=0, defaultSize=0, not long mode + limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \ + (0 << 3) | (0 << 5) | (0 << 6)) + wrattr ss, t4 + + # Set the new rip. + rdval t7, cstar + wrip t0, t7 + + # Mask the flags against sf_mask and leave RF turned off. + rdval t3, sf_mask, dataSize=8 + xor t3, t3, t1, dataSize=8 + and t3, t3, r11, dataSize=8 + wrflags t3, t0 +}; + +def macroop SYSCALL_LEGACY +{ + panic "The syscall instruction isn't implemented in legacy mode." +}; + +def macroop SYSRET_TO_64 +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + rdval t3, star + srli t3, t3, 48, dataSize=8 + ori t3, t3, 3, dataSize=1 + + # Set rflags to r11 with RF and VM cleared. + limm t4, "~(RFBit | VMBit)" + and t4, t4, r11, dataSize=8 + wrflags t4, t0 + + # Set up CS. + addi t4, t3, 16, dataSize=8 + wrsel cs, t4 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=3, defaultSize=0, long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (3 << 3) | (0 << 5) | (1 << 6)) + wrattr cs, t4 + + # Only the selector is changed for SS. + addi t4, t3, 8, dataSize=8 + wrsel ss, t4 + + # Set the RIP back. + wrip rcx, t0, dataSize=8 +}; + +def macroop SYSRET_TO_COMPAT +{ + # All 1s. + limm t1, "(uint64_t)(-1)" + + rdval t3, star + srli t3, t3, 48, dataSize=8 + ori t3, t3, 3, dataSize=1 + + # Set rflags to r11 with RF and VM cleared. + limm t4, "~(RFBit | VMBit)" + and t4, t4, r11, dataSize=8 + wrflags t4, t0 + + # Set up CS. + wrsel cs, t3 + wrbase cs, t0, dataSize=8 + wrlimit cs, t1, dataSize=4 + # Not writable, read/execute-able, not expandDown, + # dpl=3, defaultSize=1, not long mode + limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \ + (3 << 3) | (1 << 5) | (0 << 6)) + wrattr cs, t4 + + # Only the selector is changed for SS. + addi t4, t3, 8, dataSize=8 + wrsel ss, t4 + + # Set the RIP back. + wrip rcx, t0, dataSize=8 +}; + +def macroop SYSRET_NON_64 +{ + panic "The sysret instruction isn't implemented in legacy mode." +}; +''' #let {{ # class SYSENTER(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" # class SYSEXIT(Inst): -# "GenFault ${new UnimpInstFault}" -# class SYSCALL(Inst): -# "GenFault ${new UnimpInstFault}" -# class SYSRET(Inst): -# "GenFault ${new UnimpInstFault}" +# "GenFault ${new UnimpInstFault}" #}}; diff --git a/src/arch/x86/isa/insts/romutil.py b/src/arch/x86/isa/insts/romutil.py new file mode 100644 index 000000000..e47259eb3 --- /dev/null +++ b/src/arch/x86/isa/insts/romutil.py @@ -0,0 +1,212 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +intCodeTemplate = ''' +def rom +{ + # This vectors the CPU into an interrupt handler in long mode. + # On entry, t1 is set to the vector of the interrupt and t7 is the current + # ip. We need that because rdip returns the next ip. + extern %(startLabel)s: + + # + # Get the 64 bit interrupt or trap gate descriptor from the IDT + # + + # Load the gate descriptor from the IDT + slli t4, t1, 4, dataSize=8 + ld t2, idtr, [1, t0, t4], 8, dataSize=8, addressSize=8, atCPL0=True + ld t4, idtr, [1, t0, t4], dataSize=8, addressSize=8, atCPL0=True + + # Make sure the descriptor is a legal gate. + chks t1, t4, %(gateCheckType)s + + # + # Get the target CS descriptor using the selector in the gate + # descriptor. + # + srli t10, t4, 16, dataSize=8 + andi t5, t10, 0xF8, dataSize=8 + andi t0, t10, 0x4, flags=(EZF,), dataSize=2 + br rom_local_label("%(startLabel)s_globalDescriptor"), flags=(CEZF,) + ld t3, tsl, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True + br rom_local_label("%(startLabel)s_processDescriptor") +%(startLabel)s_globalDescriptor: + ld t3, tsg, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True +%(startLabel)s_processDescriptor: + chks t10, t3, IntCSCheck, dataSize=8 + wrdl hs, t3, t10, dataSize=8 + + # Stick the target offset in t9. + wrdh t9, t4, t2, dataSize=8 + + + # + # Figure out where the stack should be + # + + # Record what we might set the stack selector to. + rdsel t11, ss + + # Check if we're changing privelege level. At this point we can assume + # we're going to a DPL that's less than or equal to the CPL. + rdattr t10, hs, dataSize=8 + srli t10, t10, 3, dataSize=8 + andi t10, t10, 3, dataSize=8 + rdattr t5, cs, dataSize=8 + srli t5, t5, 3, dataSize=8 + andi t5, t5, 0x3, dataSize=8 + sub t0, t5, t10, flags=(EZF,), dataSize=8 + # We're going to change priviledge, so zero out the stack selector. We + # need to let the IST have priority so we don't branch yet. + wrsel t11, t0, flags=(nCEZF,) + + # Check the IST field of the gate descriptor + srli t12, t4, 32, dataSize=8 + andi t12, t12, 0x7, dataSize=8 + subi t0, t12, 1, flags=(ECF,), dataSize=8 + br rom_local_label("%(startLabel)s_istStackSwitch"), flags=(nCECF,) + br rom_local_label("%(startLabel)s_cplStackSwitch"), flags=(nCEZF,) + + # If we're here, it's because the stack isn't being switched. + # Set t6 to the new aligned rsp. + mov t6, t6, rsp, dataSize=8 + br rom_local_label("%(startLabel)s_stackSwitched") + +%(startLabel)s_istStackSwitch: + ld t6, tr, [8, t12, t0], 0x1c, dataSize=8, addressSize=8, atCPL0=True + br rom_local_label("%(startLabel)s_stackSwitched") + +%(startLabel)s_cplStackSwitch: + # Get the new rsp from the TSS + ld t6, tr, [8, t10, t0], 4, dataSize=8, addressSize=8, atCPL0=True + +%(startLabel)s_stackSwitched: + + andi t6, t6, 0xF0, dataSize=1 + subi t6, t6, 40 + %(errorCodeSize)d, dataSize=8 + + ## + ## Point of no return. + ## We're now going to irrevocably modify visible state. + ## Anything bad that's going to happen should have happened by now or will + ## happen right now. + ## + wrip t0, t9, dataSize=8 + + # + # Set up the target code segment. Do this now so we have the right + # permissions when setting up the stack frame. + # + srli t5, t4, 16, dataSize=8 + andi t5, t5, 0xFF, dataSize=8 + wrdl cs, t3, t5, dataSize=8 + # Tuck away the old CS for use below + limm t10, 0, dataSize=8 + rdsel t10, cs, dataSize=2 + wrsel cs, t5, dataSize=2 + + # Check that we can access everything we need to on the stack + ldst t0, hs, [1, t0, t6], dataSize=8, addressSize=8 + ldst t0, hs, [1, t0, t6], \ + 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 + + + # + # Build up the interrupt stack frame + # + + + # Write out the contents of memory + %(errorCodeCode)s + st t7, hs, [1, t0, t6], %(errorCodeSize)d, dataSize=8, addressSize=8 + st t10, hs, [1, t0, t6], 8 + %(errorCodeSize)d, dataSize=8, addressSize=8 + rflags t10, dataSize=8 + st t10, hs, [1, t0, t6], 16 + %(errorCodeSize)d, dataSize=8, addressSize=8 + st rsp, hs, [1, t0, t6], 24 + %(errorCodeSize)d, dataSize=8, addressSize=8 + rdsel t5, ss, dataSize=2 + st t5, hs, [1, t0, t6], 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 + + # Set the stack segment + mov rsp, rsp, t6, dataSize=8 + wrsel ss, t11, dataSize=2 + + # + # Adjust rflags which is still in t10 from above + # + + # Set IF to the lowest bit of the original gate type. + # The type field of the original gate starts at bit 40. + + # Set the TF, NT, and RF bits. We'll flip them at the end. + limm t6, (1 << 8) | (1 << 14) | (1 << 16) + or t10, t10, t6 + srli t5, t4, 40, dataSize=8 + srli t7, t10, 9, dataSize=8 + xor t5, t7, t5, dataSize=8 + andi t5, t5, 1, dataSize=8 + slli t5, t5, 9, dataSize=8 + or t6, t5, t6, dataSize=8 + + # Put the results into rflags + wrflags t6, t10 + + eret +}; +''' + +microcode = \ +intCodeTemplate % {\ + "startLabel" : "longModeInterrupt", + "gateCheckType" : "IntGateCheck", + "errorCodeSize" : 0, + "errorCodeCode" : "" +} + \ +intCodeTemplate % {\ + "startLabel" : "longModeSoftInterrupt", + "gateCheckType" : "SoftIntGateCheck", + "errorCodeSize" : 0, + "errorCodeCode" : "" +} + \ +intCodeTemplate % {\ + "startLabel" : "longModeInterruptWithError", + "gateCheckType" : "IntGateCheck", + "errorCodeSize" : 8, + "errorCodeCode" : ''' + st t15, hs, [1, t0, t6], dataSize=8, addressSize=8 + ''' +} + \ +''' +def rom +{ + # This vectors the CPU into an interrupt handler in legacy mode. + extern legacyModeInterrupt: + panic "Legacy mode interrupts not implemented (in microcode)" + eret +}; +''' diff --git a/src/arch/x86/isa/insts/system/__init__.py b/src/arch/x86/isa/insts/system/__init__.py index 409a929f5..0dec9ebda 100644 --- a/src/arch/x86/isa/insts/system/__init__.py +++ b/src/arch/x86/isa/insts/system/__init__.py @@ -81,7 +81,8 @@ # # Authors: Gabe Black -categories = ["halt", +categories = ["control_registers", + "halt", "invlpg", "undefined_operation", "msrs", diff --git a/src/arch/x86/isa/insts/system/control_registers.py b/src/arch/x86/isa/insts/system/control_registers.py new file mode 100644 index 000000000..902c01abb --- /dev/null +++ b/src/arch/x86/isa/insts/system/control_registers.py @@ -0,0 +1,35 @@ +# Copyright (c) 2009 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +microcode = ''' +def macroop CLTS { + rdcr t1, 0, dataSize=8 + andi t1, t1, 0xF7, dataSize=1 + wrcr 0, t1, dataSize=8 +}; +''' diff --git a/src/arch/x86/isa/insts/system/msrs.py b/src/arch/x86/isa/insts/system/msrs.py index 1acb4c792..7f283c8c1 100644 --- a/src/arch/x86/isa/insts/system/msrs.py +++ b/src/arch/x86/isa/insts/system/msrs.py @@ -84,8 +84,8 @@ microcode = ''' def macroop RDMSR { - limm t1, "IntAddrPrefixMSR >> 3" - ld t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4 + ld t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \ + dataSize=8, addressSize=8 mov rax, rax, t2, dataSize=4 srli t2, t2, 32, dataSize=8 mov rdx, rdx, t2, dataSize=4 @@ -93,10 +93,18 @@ def macroop RDMSR def macroop WRMSR { - limm t1, "IntAddrPrefixMSR >> 3" mov t2, t2, rax, dataSize=4 slli t3, rdx, 32, dataSize=8 or t2, t2, t3, dataSize=8 - st t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4 + st t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \ + dataSize=8, addressSize=8 +}; + +def macroop RDTSC +{ + rdtsc t1 + mov rax, rax, t1, dataSize=4 + srli t1, t1, 32, dataSize=8 + mov rdx, rdx, t1, dataSize=4 }; ''' diff --git a/src/arch/x86/isa/insts/system/segmentation.py b/src/arch/x86/isa/insts/system/segmentation.py index 97846f79c..acbca9f6e 100644 --- a/src/arch/x86/isa/insts/system/segmentation.py +++ b/src/arch/x86/isa/insts/system/segmentation.py @@ -56,7 +56,7 @@ microcode = ''' def macroop LGDT_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 @@ -68,7 +68,7 @@ def macroop LGDT_M def macroop LGDT_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit @@ -86,34 +86,34 @@ def macroop LGDT_P def macroop LGDT_16_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 # Get the base ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase tsg, t2 wrlimit tsg, t1 }; def macroop LGDT_16_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit ld t1, seg, riprel, disp, dataSize=2 # Get the base ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase tsg, t2 wrlimit tsg, t1 }; def macroop LIDT_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 @@ -125,7 +125,7 @@ def macroop LIDT_M def macroop LIDT_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit @@ -143,28 +143,135 @@ def macroop LIDT_P def macroop LIDT_16_M { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz # Get the limit ld t1, seg, sib, disp, dataSize=2 # Get the base ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase idtr, t2 wrlimit idtr, t1 }; def macroop LIDT_16_P { - .adjust_env oszForPseudoDesc + .adjust_env maxOsz rdip t7 # Get the limit ld t1, seg, riprel, disp, dataSize=2 # Get the base ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4 - zexti t2, t2, 23 + zexti t2, t2, 23, dataSize=8 wrbase idtr, t2 wrlimit idtr, t1 }; + +def macroop LTR_R +{ + chks reg, t0, TRCheck + limm t4, 0 + srli t4, reg, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks reg, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, reg + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LTR_M +{ + ld t5, seg, sib, disp, dataSize=2 + chks t5, t0, TRCheck + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LTR_P +{ + rdip t7 + ld t5, seg, riprel, disp, dataSize=2 + chks t5, t0, TRCheck + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, TSSCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 + ori t1, t1, (1 << 9) + st t1, tsg, [8, t4, t0], dataSize=8 +}; + +def macroop LLDT_R +{ + chks reg, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, reg, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks reg, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, reg + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop LLDT_M +{ + ld t5, seg, sib, disp, dataSize=2 + chks t5, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop LLDT_P +{ + rdip t7 + ld t5, seg, riprel, disp, dataSize=2 + chks t5, t0, InGDTCheck, flags=(EZF,) + br label("end"), flags=(CEZF,) + limm t4, 0 + srli t4, t5, 3, dataSize=2 + ldst t1, tsg, [8, t4, t0], dataSize=8 + ld t2, tsg, [8, t4, t0], 8, dataSize=8 + chks t5, t1, LDTCheck + wrdh t3, t1, t2 + wrdl tr, t1, t5 + wrbase tr, t3, dataSize=8 +end: + fault "NoFault" +}; + +def macroop SWAPGS +{ + rdval t1, kernel_gs_base, dataSize=8 + rdbase t2, gs, dataSize=8 + wrbase gs, t1, dataSize=8 + wrval kernel_gs_base, t2, dataSize=8 +}; ''' diff --git a/src/arch/x86/isa/macroop.isa b/src/arch/x86/isa/macroop.isa index 4818b926c..3a836ff68 100644 --- a/src/arch/x86/isa/macroop.isa +++ b/src/arch/x86/isa/macroop.isa @@ -72,41 +72,13 @@ def template MacroExecPanic {{ output header {{ // Base class for combinationally generated macroops - class Macroop : public StaticInst + class Macroop : public X86ISA::MacroopBase { - protected: - const uint32_t numMicroops; - - //Constructor. + public: Macroop(const char *mnem, ExtMachInst _machInst, - uint32_t _numMicroops) - : StaticInst(mnem, _machInst, No_OpClass), - numMicroops(_numMicroops) - { - assert(numMicroops); - microops = new StaticInstPtr[numMicroops]; - flags[IsMacroop] = true; - } - - ~Macroop() - { - delete [] microops; - } - - StaticInstPtr * microops; - - StaticInstPtr fetchMicroop(MicroPC microPC) - { - assert(microPC < numMicroops); - return microops[microPC]; - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return mnemonic; - } - + uint32_t _numMicroops, X86ISA::EmulEnv _env) + : MacroopBase(mnem, _machInst, _numMicroops, _env) + {} %(MacroExecPanic)s }; }}; @@ -130,22 +102,42 @@ def template MacroDeclare {{ %(declareLabels)s public: // Constructor. - %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env); + %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; }; }; }}; +def template MacroDisassembly {{ + std::string + X86Macroop::%(class_name)s::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream out; + out << mnemonic << "\t"; + + int regSize = %(regSize)s; + %(disassembly)s + // Shut up gcc. + regSize = regSize; + return out.str(); + } +}}; + // Basic instruction class constructor template. def template MacroConstructor {{ inline X86Macroop::%(class_name)s::%(class_name)s( - ExtMachInst machInst, EmulEnv env) - : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s) + ExtMachInst machInst, EmulEnv _env) + : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env) { %(adjust_env)s; %(adjust_imm)s; %(adjust_disp)s; - %(do_modrm)s; + %(init_env)s; %(constructor)s; + const char *macrocodeBlock = "%(class_name)s"; //alloc_microops is the code that sets up the microops //array in the parent class. %(alloc_microops)s; @@ -174,7 +166,7 @@ let {{ } self.declared = False self.adjust_env = "" - self.doModRM = "" + self.init_env = "" self.adjust_imm = ''' uint64_t adjustedImm = IMMEDIATE; //This is to pacify gcc in case the immediate isn't used. @@ -186,7 +178,12 @@ let {{ adjustedDisp = adjustedDisp; ''' def getAllocator(self, env): - return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator()) + return "new X86Macroop::%s(machInst, %s)" % \ + (self.name, env.getAllocator()) + def getMnemonic(self): + mnemonic = self.name.lower() + mnemonic = re.match(r'[^_]*', mnemonic).group(0) + return mnemonic def getDeclaration(self): #FIXME This first parameter should be the mnemonic. I need to #write some code which pulls that out @@ -194,32 +191,46 @@ let {{ for (label, microop) in self.labels.items(): declareLabels += "const static uint64_t label_%s = %d;\n" \ % (label, microop.micropc) - iop = InstObjParams(self.name, self.name, "Macroop", + iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", {"code" : "", "declareLabels" : declareLabels }) return MacroDeclare.subst(iop); - def getDefinition(self): + def getDefinition(self, env): #FIXME This first parameter should be the mnemonic. I need to #write some code which pulls that out numMicroops = len(self.microops) allocMicroops = '' micropc = 0 for op in self.microops: + isLast = (micropc == numMicroops - 1) allocMicroops += \ "microops[%d] = %s;\n" % \ - (micropc, op.getAllocator(True, False, - micropc == 0, - micropc == numMicroops - 1)) + (micropc, op.getAllocator(True, not isLast, + micropc == 0, isLast)) micropc += 1 - iop = InstObjParams(self.name, self.name, "Macroop", + if env.useStackSize: + useStackSize = "true" + else: + useStackSize = "false" + if env.memoryInst: + memoryInst = "true" + else: + memoryInst = "false" + regSize = '''(%s || (env.base == INTREG_RSP && %s) ? + env.stackSize : + env.dataSize)''' % (useStackSize, memoryInst) + iop = InstObjParams(self.getMnemonic(), self.name, "Macroop", {"code" : "", "num_microops" : numMicroops, "alloc_microops" : allocMicroops, "adjust_env" : self.adjust_env, "adjust_imm" : self.adjust_imm, "adjust_disp" : self.adjust_disp, - "do_modrm" : self.doModRM}) - return MacroConstructor.subst(iop); + "disassembly" : env.disassembly, + "regSize" : regSize, + "init_env" : self.initEnv}) + return MacroConstructor.subst(iop) + \ + MacroDisassembly.subst(iop); }}; let {{ @@ -235,6 +246,16 @@ let {{ self.dataSize = "OPSIZE" self.stackSize = "STACKSIZE" self.doModRM = False + self.disassembly = "" + self.firstArgument = True + self.useStackSize = False + self.memoryInst = False + + def addToDisassembly(self, code): + if not self.firstArgument: + self.disassembly += "out << \", \";\n" + self.firstArgument = False + self.disassembly += code def getAllocator(self): if self.size == 'b': @@ -283,6 +304,7 @@ let {{ let {{ doModRMString = "env.doModRM(machInst);\n" + noModRMString = "env.setSeg(machInst);\n" def genMacroop(Name, env): blocks = OutputBlocks() if not macroopDict.has_key(Name): @@ -290,9 +312,11 @@ let {{ macroop = macroopDict[Name] if not macroop.declared: if env.doModRM: - macroop.doModRM = doModRMString + macroop.initEnv = doModRMString + else: + macroop.initEnv = noModRMString blocks.header_output = macroop.getDeclaration() - blocks.decoder_output = macroop.getDefinition() + blocks.decoder_output = macroop.getDefinition(env) macroop.declared = True blocks.decode_block = "return %s;\n" % macroop.getAllocator(env) return blocks diff --git a/src/arch/x86/isa/microasm.isa b/src/arch/x86/isa/microasm.isa index 78ae34f52..c7c6dae2e 100644 --- a/src/arch/x86/isa/microasm.isa +++ b/src/arch/x86/isa/microasm.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -64,23 +64,32 @@ //Include code to build macroops in both C++ and python. ##include "macroop.isa" +//Include code to fill out the microcode ROM in both C++ and python. +##include "rom.isa" + let {{ import sys sys.path[0:0] = ["src/arch/x86/isa/"] from insts import microcode # print microcode - from micro_asm import MicroAssembler, Rom_Macroop, Rom - mainRom = Rom('main ROM') + from micro_asm import MicroAssembler, Rom_Macroop + mainRom = X86MicrocodeRom('main ROM') assembler = MicroAssembler(X86Macroop, microopClasses, mainRom, Rom_Macroop) # Add in symbols for the microcode registers - for num in range(15): + for num in range(16): assembler.symbols["t%d" % num] = "NUM_INTREGS+%d" % num - for num in range(7): + for num in range(8): assembler.symbols["ufp%d" % num] = "FLOATREG_MICROFP(%d)" % num # Add in symbols for the segment descriptor registers - for letter in ("C", "D", "E", "F", "G", "S"): + for letter in ("C", "D", "E", "F", "G", "H", "S"): assembler.symbols["%ss" % letter.lower()] = "SEGMENT_REG_%sS" % letter + # Add in symbols for the various checks of segment selectors. + for check in ("NoCheck", "CSCheck", "CallGateCheck", "IntGateCheck", + "SoftIntGateCheck", "SSCheck", "IretCheck", "IntCSCheck", + "TRCheck", "TSSCheck", "InGDTCheck", "LDTCheck"): + assembler.symbols[check] = "Seg%s" % check + for reg in ("TR", "IDTR"): assembler.symbols[reg.lower()] = "SYS_SEGMENT_REG_%s" % reg @@ -129,13 +138,15 @@ let {{ # like the internal segment above assembler.symbols["flatseg"] = "SEGMENT_REG_LS" - for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di'): + for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di', \ + '8', '9', '10', '11', '12', '13', '14', '15'): assembler.symbols["r%s" % reg] = "INTREG_R%s" % reg.upper() - for reg in range(15): + for reg in range(16): assembler.symbols["cr%d" % reg] = "MISCREG_CR%d" % reg - for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF'): + for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF', \ + 'TF', 'IF', 'NT', 'RF', 'VM', 'AC', 'VIF', 'VIP', 'ID'): assembler.symbols[flag] = flag + "Bit" for cond in ('True', 'False', 'ECF', 'EZF', 'SZnZF', @@ -150,6 +161,11 @@ let {{ assembler.symbols["CTrue"] = "ConditionTests::True" assembler.symbols["CFalse"] = "ConditionTests::False" + for reg in ('sysenter_cs', 'sysenter_esp', 'sysenter_eip', + 'star', 'lstar', 'cstar', 'sf_mask', + 'kernel_gs_base'): + assembler.symbols[reg] = "MISCREG_%s" % reg.upper() + # Code literal which forces a default 64 bit operand size in 64 bit mode. assembler.symbols["oszIn64Override"] = ''' if (machInst.mode.submode == SixtyFourBitMode && @@ -157,7 +173,7 @@ let {{ env.dataSize = 8; ''' - assembler.symbols["oszForPseudoDesc"] = ''' + assembler.symbols["maxOsz"] = ''' if (machInst.mode.submode == SixtyFourBitMode) env.dataSize = 8; else @@ -174,10 +190,23 @@ let {{ assembler.symbols["label"] = labeler + def rom_labeler(labelStr): + return "romMicroPC(RomLabels::extern_label_%s)" % labelStr + + assembler.symbols["rom_label"] = rom_labeler + + def rom_local_labeler(labelStr): + return "romMicroPC(RomLabels::label_%s)" % labelStr + + assembler.symbols["rom_local_label"] = rom_local_labeler + def stack_index(index): return "(NUM_FLOATREGS + (((%s) + 8) %% 8))" % index assembler.symbols["st"] = stack_index macroopDict = assembler.assemble(microcode) + + decoder_output += mainRom.getDefinition() + header_output += mainRom.getDeclaration() }}; diff --git a/src/arch/x86/isa/microops/base.isa b/src/arch/x86/isa/microops/base.isa index 75658a26c..f1007bf71 100644 --- a/src/arch/x86/isa/microops/base.isa +++ b/src/arch/x86/isa/microops/base.isa @@ -69,6 +69,29 @@ let {{ let {{ class X86Microop(object): + + generatorNameTemplate = "generate_%s_%d" + + generatorTemplate = ''' + StaticInstPtr + ''' + generatorNameTemplate + '''(StaticInstPtr curMacroop) + { + static const char *macrocodeBlock = romMnemonic; + static const ExtMachInst dummyExtMachInst; + static const EmulEnv dummyEmulEnv(0, 0, 1, 1, 1); + + Macroop * macroop = dynamic_cast<Macroop *>(curMacroop.get()); + const ExtMachInst &machInst = + macroop ? macroop->getExtMachInst() : dummyExtMachInst; + const EmulEnv &env = + macroop ? macroop->getEmulEnv() : dummyEmulEnv; + // env may not be used in the microop's constructor. + RegIndex reg = env.reg; + reg = reg; + using namespace RomLabels; + return %s; + } + ''' def __init__(self, name): self.name = name @@ -91,4 +114,12 @@ let {{ def getAllocator(self, mnemonic, *microFlags): return 'new %s(machInst, %s)' % \ (self.className, mnemonic, self.microFlagsText(microFlags)) + + def getGeneratorDef(self, micropc): + return self.generatorTemplate % \ + (self.className, micropc, \ + self.getAllocator(True, True, False, False)) + + def getGenerator(self, micropc): + return self.generatorNameTemplate % (self.className, micropc) }}; diff --git a/src/arch/x86/isa/microops/debug.isa b/src/arch/x86/isa/microops/debug.isa new file mode 100644 index 000000000..38fee59bb --- /dev/null +++ b/src/arch/x86/isa/microops/debug.isa @@ -0,0 +1,229 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +////////////////////////////////////////////////////////////////////////// +// +// Debug Microops +// +////////////////////////////////////////////////////////////////////////// + +output header {{ + class MicroDebugBase : public X86ISA::X86MicroopBase + { + protected: + std::string message; + uint8_t cc; + + public: + MicroDebugBase(ExtMachInst _machInst, const char * mnem, + const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc); + + MicroDebugBase(ExtMachInst _machInst, const char * mnem, + const char * instMnem, std::string _message, uint8_t _cc); + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template MicroDebugDeclare {{ + class %(class_name)s : public %(base_class)s + { + private: + void buildMe(); + public: + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc); + + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + std::string _message, uint8_t _cc); + + %(BasicExecDeclare)s + }; +}}; + +def template MicroDebugExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s + %(op_rd)s + if (%(cond_test)s) { + %(func)s("%s\n", message); + } + return NoFault; + } +}}; + +output decoder {{ + inline MicroDebugBase::MicroDebugBase( + ExtMachInst machInst, const char * mnem, const char * instMnem, + std::string _message, uint8_t _cc) : + X86MicroopBase(machInst, mnem, instMnem, + false, false, false, false, No_OpClass), + message(_message), cc(_cc) + { + } + + inline MicroDebugBase::MicroDebugBase( + ExtMachInst machInst, const char * mnem, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc) : + X86MicroopBase(machInst, mnem, instMnem, + isMicro, isDelayed, isFirst, isLast, No_OpClass), + message(_message), cc(_cc) + { + } +}}; + +def template MicroDebugConstructor {{ + + inline void %(class_name)s::buildMe() + { + %(constructor)s; + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + std::string _message, uint8_t _cc) : + %(base_class)s(machInst, "%(func)s", instMnem, _message, _cc) + { + buildMe(); + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + std::string _message, uint8_t _cc) : + %(base_class)s(machInst, "%(func)s", instMnem, + isMicro, isDelayed, isFirst, isLast, _message, _cc) + { + buildMe(); + } +}}; + +output decoder {{ + std::string MicroDebugBase::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + response << "\"" << message << "\""; + + return response.str(); + } +}}; + +let {{ + class MicroDebug(X86Microop): + def __init__(self, message, flags=None): + self.message = message + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + allocator = '''new %(class_name)s(machInst, macrocodeBlock + %(flags)s, "%(message)s", %(cc)s)''' % { + "class_name" : self.className, + "flags" : self.microFlagsText(microFlags), + "message" : self.message, + "cc" : self.cond} + return allocator + + exec_output = "" + header_output = "" + decoder_output = "" + + def buildDebugMicro(func): + global exec_output, header_output, decoder_output + + iop = InstObjParams(func, "Micro%sFlags" % func.capitalize(), + "MicroDebugBase", + {"code": "", + "func": func, + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += MicroDebugExecute.subst(iop) + header_output += MicroDebugDeclare.subst(iop) + decoder_output += MicroDebugConstructor.subst(iop) + + iop = InstObjParams(func, "Micro%s" % func.capitalize(), + "MicroDebugBase", + {"code": "", + "func": func, + "cond_test": "true"}) + exec_output += MicroDebugExecute.subst(iop) + header_output += MicroDebugDeclare.subst(iop) + decoder_output += MicroDebugConstructor.subst(iop) + + class MicroDebugChild(MicroDebug): + className = "Micro%s" % func.capitalize() + + global microopClasses + microopClasses[func] = MicroDebugChild + + buildDebugMicro("panic") + buildDebugMicro("fatal") + buildDebugMicro("warn") + buildDebugMicro("warn_once") +}}; diff --git a/src/arch/x86/isa/microops/fpop.isa b/src/arch/x86/isa/microops/fpop.isa index 2919aa277..d4acfdbf4 100644 --- a/src/arch/x86/isa/microops/fpop.isa +++ b/src/arch/x86/isa/microops/fpop.isa @@ -245,7 +245,7 @@ let {{ self.className += "Top" def getAllocator(self, *microFlags): - return '''new %(class_name)s(machInst, mnemonic + return '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(src1)s, %(src2)s, %(dest)s, %(dataSize)s, %(spm)d)''' % { "class_name" : self.className, diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa index cb63e7cd9..af94cf31e 100644 --- a/src/arch/x86/isa/microops/ldstop.isa +++ b/src/arch/x86/isa/microops/ldstop.isa @@ -124,14 +124,16 @@ def template MicroLeaDeclare {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(class_name)s(ExtMachInst _machInst, const char * instMnem, uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(BasicExecDeclare)s }; @@ -151,11 +153,13 @@ def template MicroLoadExecute {{ %(ea_code)s; DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); - fault = read(xc, EA, Mem, (%(mem_flags)s) | segment); + fault = read(xc, EA, Mem, memFlags); - if(fault == NoFault) - { + if (fault == NoFault) { %(code)s; + } else if (memFlags & Request::PF_EXCLUSIVE) { + // For prefetches, ignore any faults/exceptions. + return NoFault; } if(fault == NoFault) { @@ -178,7 +182,7 @@ def template MicroLoadInitiateAcc {{ %(ea_code)s; DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); - fault = read(xc, EA, Mem, (%(mem_flags)s) | segment); + fault = read(xc, EA, Mem, memFlags); return fault; } @@ -194,7 +198,7 @@ def template MicroLoadCompleteAcc {{ %(op_decl)s; %(op_rd)s; - Mem = pkt->get<typeof(Mem)>(); + Mem = get(pkt); %(code)s; @@ -225,9 +229,10 @@ def template MicroStoreExecute {{ if(fault == NoFault) { - fault = write(xc, Mem, EA, (%(mem_flags)s) | segment); + fault = write(xc, Mem, EA, memFlags); if(fault == NoFault) { + %(post_code)s; %(op_wb)s; } } @@ -252,20 +257,20 @@ def template MicroStoreInitiateAcc {{ if(fault == NoFault) { - fault = write(xc, Mem, EA, (%(mem_flags)s) | segment); - if(fault == NoFault) - { - %(op_wb)s; - } + write(xc, Mem, EA, memFlags); } return fault; } }}; def template MicroStoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc, - Trace::InstRecord * traceData) const + Fault %(class_name)s::completeAcc(PacketPtr pkt, + %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const { + %(op_decl)s; + %(op_rd)s; + %(complete_code)s; + %(op_wb)s; return NoFault; } }}; @@ -295,14 +300,16 @@ def template MicroLdStOpDeclare {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(class_name)s(ExtMachInst _machInst, const char * instMnem, uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize); + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags); %(BasicExecDeclare)s @@ -324,12 +331,13 @@ def template MicroLdStOpConstructor {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize) : + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, false, false, false, false, _scale, _index, _base, _disp, _segment, _data, - _dataSize, _addressSize, %(op_class)s) + _dataSize, _addressSize, _memFlags, %(op_class)s) { buildMe(); } @@ -340,12 +348,13 @@ def template MicroLdStOpConstructor {{ uint8_t _scale, RegIndex _index, RegIndex _base, uint64_t _disp, uint8_t _segment, RegIndex _data, - uint8_t _dataSize, uint8_t _addressSize) : + uint8_t _dataSize, uint8_t _addressSize, + Request::FlagsType _memFlags) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, isMicro, isDelayed, isFirst, isLast, _scale, _index, _base, _disp, _segment, _data, - _dataSize, _addressSize, %(op_class)s) + _dataSize, _addressSize, _memFlags, %(op_class)s) { buildMe(); } @@ -353,26 +362,35 @@ def template MicroLdStOpConstructor {{ let {{ class LdStOp(X86Microop): - def __init__(self, data, segment, addr, disp, dataSize, addressSize): + def __init__(self, data, segment, addr, disp, + dataSize, addressSize, baseFlags, atCPL0, prefetch): self.data = data [self.scale, self.index, self.base] = addr self.disp = disp self.segment = segment self.dataSize = dataSize self.addressSize = addressSize + self.memFlags = baseFlags + if atCPL0: + self.memFlags += " | (CPL0FlagBit << FlagShift)" + if prefetch: + self.memFlags += " | Request::PF_EXCLUSIVE" + self.memFlags += " | (machInst.legacy.addr ? " + \ + "(AddrSizeFlagBit << FlagShift) : 0)" def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(scale)s, %(index)s, %(base)s, %(disp)s, %(segment)s, %(data)s, - %(dataSize)s, %(addressSize)s)''' % { + %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % { "class_name" : self.className, "flags" : self.microFlagsText(microFlags), "scale" : self.scale, "index" : self.index, "base" : self.base, "disp" : self.disp, "segment" : self.segment, "data" : self.data, - "dataSize" : self.dataSize, "addressSize" : self.addressSize} + "dataSize" : self.dataSize, "addressSize" : self.addressSize, + "memFlags" : self.memFlags} return allocator }}; @@ -384,9 +402,11 @@ let {{ decoder_output = "" exec_output = "" - calculateEA = "EA = SegBase + scale * Index + Base + disp;" + calculateEA = ''' + EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0); + ''' - def defineMicroLoadOp(mnemonic, code, mem_flags=0): + def defineMicroLoadOp(mnemonic, code, mem_flags="0"): global header_output global decoder_output global exec_output @@ -397,8 +417,7 @@ let {{ # Build up the all register version of this micro op iop = InstObjParams(name, Name, 'X86ISA::LdStOp', {"code": code, - "ea_code": calculateEA, - "mem_flags": mem_flags}) + "ea_code": calculateEA}) header_output += MicroLdStOpDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLoadExecute.subst(iop) @@ -407,19 +426,24 @@ let {{ class LoadOp(LdStOp): def __init__(self, data, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): - super(LoadOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + dataSize="env.dataSize", + addressSize="env.addressSize", + atCPL0=False, prefetch=False): + super(LoadOp, self).__init__(data, segment, addr, + disp, dataSize, addressSize, mem_flags, + atCPL0, prefetch) self.className = Name self.mnemonic = name microopClasses[name] = LoadOp defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);') - defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', 'StoreCheck') + defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', + 'X86ISA::StoreCheck') defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;') - def defineMicroStoreOp(mnemonic, code, mem_flags=0): + def defineMicroStoreOp(mnemonic, code, \ + postCode="", completeCode="", mem_flags="0"): global header_output global decoder_output global exec_output @@ -430,8 +454,9 @@ let {{ # Build up the all register version of this micro op iop = InstObjParams(name, Name, 'X86ISA::LdStOp', {"code": code, - "ea_code": calculateEA, - "mem_flags": mem_flags}) + "post_code": postCode, + "complete_code": completeCode, + "ea_code": calculateEA}) header_output += MicroLdStOpDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroStoreExecute.subst(iop) @@ -440,26 +465,26 @@ let {{ class StoreOp(LdStOp): def __init__(self, data, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): - super(StoreOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + dataSize="env.dataSize", + addressSize="env.addressSize", + atCPL0=False): + super(StoreOp, self).__init__(data, segment, addr, + disp, dataSize, addressSize, mem_flags, atCPL0, False) self.className = Name self.mnemonic = name microopClasses[name] = StoreOp - defineMicroStoreOp('St', 'Mem = Data;') + defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);') defineMicroStoreOp('Stfp', 'Mem = FpData.uqw;') - defineMicroStoreOp('Stupd', ''' - Mem = Data; - Base = merge(Base, EA - SegBase, addressSize); - '''); - + defineMicroStoreOp('Stupd', 'Mem = pick(Data, 2, dataSize);', + 'Base = merge(Base, EA - SegBase, addressSize);', + 'Base = merge(Base, pkt->req->getVaddr() - SegBase, addressSize);'); + defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS") iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp', {"code": "Data = merge(Data, EA, dataSize);", - "ea_code": calculateEA, - "mem_flags": 0}) + "ea_code": calculateEA}) header_output += MicroLeaDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLeaExecute.subst(iop) @@ -468,7 +493,7 @@ let {{ def __init__(self, data, segment, addr, disp = 0, dataSize="env.dataSize", addressSize="env.addressSize"): super(LeaOp, self).__init__(data, segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", False, False) self.className = "Lea" self.mnemonic = "lea" @@ -477,38 +502,28 @@ let {{ iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp', {"code": "xc->demapPage(EA, 0);", - "ea_code": calculateEA, - "mem_flags": 0}) + "ea_code": calculateEA}) header_output += MicroLeaDeclare.subst(iop) decoder_output += MicroLdStOpConstructor.subst(iop) exec_output += MicroLeaExecute.subst(iop) class TiaOp(LdStOp): def __init__(self, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): + dataSize="env.dataSize", + addressSize="env.addressSize"): super(TiaOp, self).__init__("NUM_INTREGS", segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", False, False) self.className = "Tia" self.mnemonic = "tia" microopClasses["tia"] = TiaOp - iop = InstObjParams("cda", "Cda", 'X86ISA::LdStOp', - {"code": ''' - Addr paddr; - fault = xc->translateDataWriteAddr(EA, paddr, - dataSize, (1 << segment)); - ''', - "ea_code": calculateEA}) - header_output += MicroLeaDeclare.subst(iop) - decoder_output += MicroLdStOpConstructor.subst(iop) - exec_output += MicroLeaExecute.subst(iop) - class CdaOp(LdStOp): def __init__(self, segment, addr, disp = 0, - dataSize="env.dataSize", addressSize="env.addressSize"): + dataSize="env.dataSize", + addressSize="env.addressSize", atCPL0=False): super(CdaOp, self).__init__("NUM_INTREGS", segment, - addr, disp, dataSize, addressSize) + addr, disp, dataSize, addressSize, "0", atCPL0, False) self.className = "Cda" self.mnemonic = "cda" diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index 6686444fd..4e75ab8b0 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -154,7 +154,7 @@ let {{ self.dataSize = dataSize def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(dest)s, %(imm)s, %(dataSize)s)''' % { "class_name" : self.className, "mnemonic" : self.mnemonic, diff --git a/src/arch/x86/isa/microops/microops.isa b/src/arch/x86/isa/microops/microops.isa index 53f34d3f2..19266f6d6 100644 --- a/src/arch/x86/isa/microops/microops.isa +++ b/src/arch/x86/isa/microops/microops.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -68,5 +68,11 @@ //Load/store microop definitions ##include "ldstop.isa" +//Control flow microop definitions +##include "seqop.isa" + //Miscellaneous microop definitions ##include "specop.isa" + +//Microops for printing out debug messages through M5 +##include "debug.isa" diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index e761f0034..f9bc82119 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -231,6 +231,21 @@ output header {{ void divide(uint64_t dividend, uint64_t divisor, uint64_t "ient, uint64_t &remainder); + + enum SegmentSelectorCheck { + SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck, + SegSoftIntGateCheck, SegSSCheck, SegIretCheck, SegIntCSCheck, + SegTRCheck, SegTSSCheck, SegInGDTCheck, SegLDTCheck + }; + + enum LongModeDescriptorType { + LDT64 = 2, + AvailableTSS64 = 9, + BusyTSS64 = 0xb, + CallGate64 = 0xc, + IntGate64 = 0xe, + TrapGate64 = 0xf + }; }}; output decoder {{ @@ -424,7 +439,7 @@ let {{ className = self.className if self.mnemonic == self.base_mnemonic + 'i': className += "Imm" - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(src1)s, %(op2)s, %(dest)s, %(dataSize)s, %(ext)s)''' % { "class_name" : className, @@ -838,19 +853,28 @@ let {{ code = 'RIP = psrc1 + sop2 + CSBase' else_code="RIP = RIP;" - class Br(WrRegOp, CondRegOp): - code = 'nuIP = psrc1 + op2;' - else_code='nuIP = nuIP;' - class Wruflags(WrRegOp): code = 'ccFlagBits = psrc1 ^ op2' + class Wrflags(WrRegOp): + code = ''' + MiscReg newFlags = psrc1 ^ op2; + MiscReg userFlagMask = 0xDD5; + // Get only the user flags + ccFlagBits = newFlags & userFlagMask; + // Get everything else + nccFlagBits = newFlags & ~userFlagMask; + ''' + class Rdip(RdRegOp): code = 'DestReg = RIP - CSBase' class Ruflags(RdRegOp): code = 'DestReg = ccFlagBits' + class Rflags(RdRegOp): + code = 'DestReg = ccFlagBits | nccFlagBits' + class Ruflag(RegOp): code = ''' int flag = bits(ccFlagBits, imm8); @@ -863,6 +887,20 @@ let {{ super(Ruflag, self).__init__(dest, \ "NUM_INTREGS", imm, flags, dataSize) + class Rflag(RegOp): + code = ''' + MiscReg flagMask = 0x3F7FDD5; + MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask; + int flag = bits(flags, imm8); + DestReg = merge(DestReg, flag, dataSize); + ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : + (ccFlagBits & ~EZFBit); + ''' + def __init__(self, dest, imm, flags=None, \ + dataSize="env.dataSize"): + super(Rflag, self).__init__(dest, \ + "NUM_INTREGS", imm, flags, dataSize) + class Sext(RegOp): code = ''' IntReg val = psrc1; @@ -883,17 +921,53 @@ let {{ ''' class Zext(RegOp): - code = 'DestReg = bits(psrc1, op2, 0);' + code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);' + + class Rddr(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Rddr, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + CR4 cr4 = CR4Op; + DR7 dr7 = DR7Op; + if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) { + fault = new InvalidOpcode(); + } else if (dr7.gd) { + fault = new DebugException(); + } else { + DestReg = merge(DestReg, DebugSrc1, dataSize); + } + ''' + + class Wrdr(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Wrdr, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + CR4 cr4 = CR4Op; + DR7 dr7 = DR7Op; + if ((cr4.de == 1 && (dest == 4 || dest == 5)) || dest >= 8) { + fault = new InvalidOpcode(); + } else if ((dest == 6 || dest == 7) && + bits(psrc1, 63, 32) && + machInst.mode.mode == LongMode) { + fault = new GeneralProtection(0); + } else if (dr7.gd) { + fault = new DebugException(); + } else { + DebugDest = psrc1; + } + ''' class Rdcr(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(Rdcr, self).__init__(dest, \ src1, "NUM_INTREGS", flags, dataSize) code = ''' - if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) { + if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) { fault = new InvalidOpcode(); } else { - DestReg = ControlSrc1; + DestReg = merge(DestReg, ControlSrc1, dataSize); } ''' @@ -950,7 +1024,7 @@ let {{ ''' # Microops for manipulating segmentation registers - class SegOp(RegOp): + class SegOp(CondRegOp): abstract = True def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(SegOp, self).__init__(dest, \ @@ -971,74 +1045,223 @@ let {{ SegSelDest = psrc1; ''' + class WrAttr(SegOp): + code = ''' + SegAttrDest = psrc1; + ''' + class Rdbase(SegOp): code = ''' - DestReg = SegBaseDest; + DestReg = merge(DestReg, SegBaseSrc1, dataSize); ''' class Rdlimit(SegOp): code = ''' - DestReg = SegLimitSrc1; + DestReg = merge(DestReg, SegLimitSrc1, dataSize); + ''' + + class RdAttr(SegOp): + code = ''' + DestReg = merge(DestReg, SegAttrSrc1, dataSize); ''' class Rdsel(SegOp): code = ''' - DestReg = SegSelSrc1; + DestReg = merge(DestReg, SegSelSrc1, dataSize); ''' - class Chks(SegOp): + class Rdval(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Rdval, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) code = ''' - // The selector is in source 1. - SegSelector selector = psrc1; - - // Compute the address of the descriptor and set DestReg to it. - if (selector.ti) { - // A descriptor in the LDT - Addr target = (selector.esi << 3) + LDTRBase; - if (!LDTRSel || (selector.esi << 3) + dataSize > LDTRLimit) - fault = new GeneralProtection(selector & mask(16)); - DestReg = target; - } else { - // A descriptor in the GDT - Addr target = (selector.esi << 3) + GDTRBase; - if ((selector.esi << 3) + dataSize > GDTRLimit) - fault = new GeneralProtection(selector & mask(16)); - DestReg = target; + DestReg = MiscRegSrc1; + ''' + + class Wrval(RegOp): + def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): + super(Wrval, self).__init__(dest, \ + src1, "NUM_INTREGS", flags, dataSize) + code = ''' + MiscRegDest = SrcReg1; + ''' + + class Chks(RegOp): + def __init__(self, dest, src1, src2=0, + flags=None, dataSize="env.dataSize"): + super(Chks, self).__init__(dest, + src1, src2, flags, dataSize) + code = ''' + // The selector is in source 1 and can be at most 16 bits. + SegSelector selector = DestReg; + SegDescriptor desc = SrcReg1; + HandyM5Reg m5reg = M5Reg; + + switch (imm8) + { + case SegNoCheck: + break; + case SegCSCheck: + panic("CS checks for far calls/jumps not implemented.\\n"); + break; + case SegCallGateCheck: + panic("CS checks for far calls/jumps through call gates" + "not implemented.\\n"); + break; + case SegSoftIntGateCheck: + // Check permissions. + if (desc.dpl < m5reg.cpl) { + fault = new GeneralProtection(selector); + } + // Fall through on purpose + case SegIntGateCheck: + // Make sure the gate's the right type. + if ((m5reg.mode == LongMode && (desc.type & 0xe) != 0xe) || + ((desc.type & 0x6) != 0x6)) { + fault = new GeneralProtection(0); + } + break; + case SegSSCheck: + if (selector.si || selector.ti) { + if (!desc.p) { + fault = new StackFault(selector); + } + } else { + if ((m5reg.submode != SixtyFourBitMode || + m5reg.cpl == 3) || + !(desc.s == 1 && + desc.type.codeOrData == 0 && desc.type.w) || + (desc.dpl != m5reg.cpl) || + (selector.rpl != m5reg.cpl)) { + fault = new GeneralProtection(selector); + } + } + break; + case SegIretCheck: + { + if ((!selector.si && !selector.ti) || + (selector.rpl < m5reg.cpl) || + !(desc.s == 1 && desc.type.codeOrData == 1) || + (!desc.type.c && desc.dpl != selector.rpl) || + (desc.type.c && desc.dpl > selector.rpl)) { + fault = new GeneralProtection(selector); + } else if (!desc.p) { + fault = new SegmentNotPresent(selector); + } + break; + } + case SegIntCSCheck: + if (m5reg.mode == LongMode) { + if (desc.l != 1 || desc.d != 0) { + fault = new GeneralProtection(selector); + } + } else { + panic("Interrupt CS checks not implemented " + "in legacy mode.\\n"); + } + break; + case SegTRCheck: + if (!selector.si || selector.ti) { + fault = new GeneralProtection(selector); + } + break; + case SegTSSCheck: + if (!desc.p) { + fault = new SegmentNotPresent(selector); + } else if (!(desc.type == 0x9 || + (desc.type == 1 && + m5reg.mode != LongMode))) { + fault = new GeneralProtection(selector); + } + break; + case SegInGDTCheck: + if (selector.ti) { + fault = new GeneralProtection(selector); + } + break; + case SegLDTCheck: + if (!desc.p) { + fault = new SegmentNotPresent(selector); + } else if (desc.type != 0x2) { + fault = new GeneralProtection(selector); + } + break; + default: + panic("Undefined segment check type.\\n"); } ''' flag_code = ''' // Check for a NULL selector and set ZF,EZF appropriately. ccFlagBits = ccFlagBits & ~(ext & (ZFBit | EZFBit)); - if (!selector.esi && !selector.ti) + if (!selector.si && !selector.ti) ccFlagBits = ccFlagBits | (ext & (ZFBit | EZFBit)); ''' class Wrdh(RegOp): code = ''' + SegDescriptor desc = SrcReg1; + + uint64_t target = bits(SrcReg2, 31, 0) << 32; + switch(desc.type) { + case LDT64: + case AvailableTSS64: + case BusyTSS64: + replaceBits(target, 23, 0, desc.baseLow); + replaceBits(target, 31, 24, desc.baseHigh); + break; + case CallGate64: + case IntGate64: + case TrapGate64: + replaceBits(target, 15, 0, bits(desc, 15, 0)); + replaceBits(target, 31, 16, bits(desc, 63, 48)); + break; + default: + panic("Wrdh used with wrong descriptor type!\\n"); + } + DestReg = target; + ''' + + class Wrtsc(WrRegOp): + code = ''' + TscOp = psrc1; + ''' + + class Rdtsc(RdRegOp): + code = ''' + DestReg = TscOp; + ''' + class Rdm5reg(RdRegOp): + code = ''' + DestReg = M5Reg; ''' class Wrdl(RegOp): code = ''' SegDescriptor desc = SrcReg1; - SegAttr attr = 0; - attr.dpl = desc.dpl; - attr.defaultSize = desc.d; - if (!desc.s) { - SegBaseDest = SegBaseDest; - SegLimitDest = SegLimitDest; - SegAttrDest = SegAttrDest; - panic("System segment encountered.\\n"); - } else { - if (!desc.p) - panic("Segment not present.\\n"); - if (desc.type.codeOrData) { - attr.readable = desc.type.r; - attr.longMode = desc.l; - } else { - attr.expandDown = desc.type.e; + SegSelector selector = SrcReg2; + if (selector.si || selector.ti) { + SegAttr attr = 0; + attr.dpl = desc.dpl; + attr.defaultSize = desc.d; + if (!desc.s) { + // The expand down bit happens to be set for gates. + if (desc.type.e) { + panic("Gate descriptor encountered.\\n"); + } attr.readable = 1; - attr.writable = desc.type.w; + attr.writable = 1; + } else { + if (!desc.p) + panic("Segment not present.\\n"); + if (desc.type.codeOrData) { + attr.readable = desc.type.r; + attr.longMode = desc.l; + } else { + attr.expandDown = desc.type.e; + attr.readable = 1; + attr.writable = desc.type.w; + } } Addr base = desc.baseLow | (desc.baseHigh << 24); Addr limit = desc.limitLow | (desc.limitHigh << 16); @@ -1047,6 +1270,10 @@ let {{ SegBaseDest = base; SegLimitDest = limit; SegAttrDest = attr; + } else { + SegBaseDest = SegBaseDest; + SegLimitDest = SegLimitDest; + SegAttrDest = SegAttrDest; } ''' }}; diff --git a/src/arch/x86/isa/microops/seqop.isa b/src/arch/x86/isa/microops/seqop.isa new file mode 100644 index 000000000..332519b87 --- /dev/null +++ b/src/arch/x86/isa/microops/seqop.isa @@ -0,0 +1,251 @@ +// Copyright (c) 2008 The Hewlett-Packard Development Company +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the +// following conditions are met: +// +// The software must be used only for Non-Commercial Use which means any +// use which is NOT directed to receiving any direct monetary +// compensation for, or commercial advantage from such use. Illustrative +// examples of non-commercial use are academic research, personal study, +// teaching, education and corporate research & development. +// Illustrative examples of commercial use are distributing products for +// commercial advantage and providing services using the software for +// commercial advantage. +// +// If you wish to use this software or functionality therein that may be +// covered by patents for commercial use, please contact: +// Director of Intellectual Property Licensing +// Office of Strategy and Technology +// Hewlett-Packard Company +// 1501 Page Mill Road +// Palo Alto, California 94304 +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. Redistributions +// in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. Neither the name of +// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. No right of +// sublicense is granted herewith. Derivatives of the software and +// output created using the software may be prepared, but only for +// Non-Commercial Uses. Derivatives of the software may be shared with +// others provided: (i) the others agree to abide by the list of +// conditions herein which includes the Non-Commercial Use restrictions; +// and (ii) such Derivatives of the software include the above copyright +// notice to acknowledge the contribution from this software where +// applicable, this list of conditions and the disclaimer below. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +output header {{ + class SeqOpBase : public X86ISA::X86MicroopBase + { + protected: + uint16_t target; + uint8_t cc; + + public: + SeqOpBase(ExtMachInst _machInst, const char * instMnem, + const char * mnemonic, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc); + + SeqOpBase(ExtMachInst _machInst, const char * instMnem, + const char * mnemonic, + uint16_t _target, uint8_t _cc); + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template SeqOpDeclare {{ + class %(class_name)s : public %(base_class)s + { + private: + void buildMe(); + public: + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc); + + %(class_name)s(ExtMachInst _machInst, const char * instMnem, + uint16_t _target, uint8_t _cc); + + %(BasicExecDeclare)s + }; +}}; + +def template SeqOpExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s; + %(op_rd)s; + if (%(cond_test)s) { + %(code)s; + } else { + %(else_code)s; + } + %(op_wb)s; + return NoFault; + } +}}; + +output decoder {{ + inline SeqOpBase::SeqOpBase( + ExtMachInst machInst, const char * mnemonic, const char * instMnem, + uint16_t _target, uint8_t _cc) : + X86MicroopBase(machInst, mnemonic, instMnem, + false, false, false, false, No_OpClass), + target(_target), cc(_cc) + { + } + + inline SeqOpBase::SeqOpBase( + ExtMachInst machInst, const char * mnemonic, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc) : + X86MicroopBase(machInst, mnemonic, instMnem, + isMicro, isDelayed, isFirst, isLast, No_OpClass), + target(_target), cc(_cc) + { + } +}}; + +def template SeqOpConstructor {{ + + inline void %(class_name)s::buildMe() + { + %(constructor)s; + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + uint16_t _target, uint8_t _cc) : + %(base_class)s(machInst, "%(mnemonic)s", instMnem, _target, _cc) + { + buildMe(); + } + + inline %(class_name)s::%(class_name)s( + ExtMachInst machInst, const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint16_t _target, uint8_t _cc) : + %(base_class)s(machInst, "%(mnemonic)s", instMnem, + isMicro, isDelayed, isFirst, isLast, _target, _cc) + { + buildMe(); + } +}}; + +output decoder {{ + std::string SeqOpBase::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + ccprintf(response, "%#x", target); + + return response.str(); + } +}}; + +let {{ + class SeqOp(X86Microop): + def __init__(self, target, flags=None): + self.target = target + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + allocator = '''new %(class_name)s(machInst, macrocodeBlock + %(flags)s, %(target)s, %(cc)s)''' % { + "class_name" : self.className, + "flags" : self.microFlagsText(microFlags), + "target" : self.target, + "cc" : self.cond} + return allocator + + class Br(SeqOp): + className = "MicroBranch" + + def getAllocator(self, *microFlags): + (is_micro, is_delayed, is_first, is_last) = microFlags + is_last = False + is_delayed = True + microFlags = (is_micro, is_delayed, is_first, is_last) + return super(Br, self).getAllocator(*microFlags) + + class Eret(SeqOp): + target = "normalMicroPC(0)" + className = "Eret" + + def __init__(self, flags=None): + if flags: + if not isinstance(flags, (list, tuple)): + raise Exception, "flags must be a list or tuple of flags" + self.cond = " | ".join(flags) + self.className += "Flags" + else: + self.cond = "0" + + def getAllocator(self, *microFlags): + (is_micro, is_delayed, is_first, is_last) = microFlags + is_last = True + is_delayed = False + microFlags = (is_micro, is_delayed, is_first, is_last) + return super(Eret, self).getAllocator(*microFlags) + + iop = InstObjParams("br", "MicroBranchFlags", "SeqOpBase", + {"code": "nuIP = target", + "else_code": "nuIP = nuIP", + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + iop = InstObjParams("br", "MicroBranch", "SeqOpBase", + {"code": "nuIP = target", + "else_code": "nuIP = nuIP", + "cond_test": "true"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + microopClasses["br"] = Br + + iop = InstObjParams("eret", "EretFlags", "SeqOpBase", + {"code": "", "else_code": "", + "cond_test": "checkCondition(ccFlagBits, cc)"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + iop = InstObjParams("eret", "Eret", "SeqOpBase", + {"code": "", "else_code": "", + "cond_test": "true"}) + exec_output += SeqOpExecute.subst(iop) + header_output += SeqOpDeclare.subst(iop) + decoder_output += SeqOpConstructor.subst(iop) + microopClasses["eret"] = Eret +}}; diff --git a/src/arch/x86/isa/microops/specop.isa b/src/arch/x86/isa/microops/specop.isa index 6bcc7ff91..c6e172ef1 100644 --- a/src/arch/x86/isa/microops/specop.isa +++ b/src/arch/x86/isa/microops/specop.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -95,6 +95,9 @@ output header {{ } %(BasicExecDeclare)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; }; }}; @@ -201,6 +204,16 @@ output decoder {{ return response.str(); } + + std::string MicroHalt::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + + return response.str(); + } }}; let {{ @@ -217,7 +230,7 @@ let {{ self.cond = "0" def getAllocator(self, *microFlags): - allocator = '''new %(class_name)s(machInst, mnemonic + allocator = '''new %(class_name)s(machInst, macrocodeBlock %(flags)s, %(fault)s, %(cc)s)''' % { "class_name" : self.className, "flags" : self.microFlagsText(microFlags), @@ -244,7 +257,7 @@ let {{ pass def getAllocator(self, *microFlags): - return "new MicroHalt(machInst, mnemonic %s)" % \ + return "new MicroHalt(machInst, macrocodeBlock %s)" % \ self.microFlagsText(microFlags) microopClasses["halt"] = Halt diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa index 9345158e9..ab1e9a851 100644 --- a/src/arch/x86/isa/operands.isa +++ b/src/arch/x86/isa/operands.isa @@ -26,7 +26,7 @@ // // Authors: Gabe Black -// Copyright (c) 2007 The Hewlett-Packard Development Company +// Copyright (c) 2007-2008 The Hewlett-Packard Development Company // All rights reserved. // // Redistribution and use of this software in source and binary forms, @@ -109,7 +109,14 @@ def operands {{ 'Quotient': ('IntReg', 'uqw', 'INTREG_IMPLICIT(2)', 'IsInteger', 9), 'Remainder': ('IntReg', 'uqw', 'INTREG_IMPLICIT(3)', 'IsInteger', 10), 'Divisor': ('IntReg', 'uqw', 'INTREG_IMPLICIT(4)', 'IsInteger', 11), - 'rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12), + 'Rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12), + 'Rbx': ('IntReg', 'uqw', '(INTREG_RBX)', 'IsInteger', 13), + 'Rcx': ('IntReg', 'uqw', '(INTREG_RCX)', 'IsInteger', 14), + 'Rdx': ('IntReg', 'uqw', '(INTREG_RDX)', 'IsInteger', 15), + 'Rsp': ('IntReg', 'uqw', '(INTREG_RSP)', 'IsInteger', 16), + 'Rbp': ('IntReg', 'uqw', '(INTREG_RBP)', 'IsInteger', 17), + 'Rsi': ('IntReg', 'uqw', '(INTREG_RSI)', 'IsInteger', 18), + 'Rdi': ('IntReg', 'uqw', '(INTREG_RDI)', 'IsInteger', 19), 'FpSrcReg1': ('FloatReg', 'df', 'src1', 'IsFloating', 20), 'FpSrcReg2': ('FloatReg', 'df', 'src2', 'IsFloating', 21), 'FpDestReg': ('FloatReg', 'df', 'dest', 'IsFloating', 22), @@ -117,10 +124,13 @@ def operands {{ 'RIP': ('NPC', 'uqw', None, (None, None, 'IsControl'), 50), 'uIP': ('UPC', 'uqw', None, (None, None, 'IsControl'), 51), 'nuIP': ('NUPC', 'uqw', None, (None, None, 'IsControl'), 52), + # This holds the condition code portion of the flag register. The + # nccFlagBits version holds the rest. 'ccFlagBits': ('IntReg', 'uqw', 'INTREG_PSEUDO(0)', None, 60), - # The TOP register should needs to be more protected so that later + # These register should needs to be more protected so that later # instructions don't map their indexes with an old value. - 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 61), + 'nccFlagBits': ('ControlReg', 'uqw', 'MISCREG_RFLAGS', None, 61), + 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 62), # The segment base as used by memory instructions. 'SegBase': ('ControlReg', 'uqw', 'MISCREG_SEG_EFF_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70), @@ -128,23 +138,31 @@ def operands {{ # original instruction. 'ControlDest': ('ControlReg', 'uqw', 'MISCREG_CR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 100), 'ControlSrc1': ('ControlReg', 'uqw', 'MISCREG_CR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 101), - 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102), - 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103), - 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104), - 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105), - 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106), - 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107), - 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108), - 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109), + 'DebugDest': ('ControlReg', 'uqw', 'MISCREG_DR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102), + 'DebugSrc1': ('ControlReg', 'uqw', 'MISCREG_DR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103), + 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104), + 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105), + 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106), + 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107), + 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108), + 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109), + 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 110), + 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 111), # Operands to access specific control registers directly. 'EferOp': ('ControlReg', 'uqw', 'MISCREG_EFER', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 200), 'CR4Op': ('ControlReg', 'uqw', 'MISCREG_CR4', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 201), - 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202), - 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203), - 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204), - 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205), - 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206), - 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207), + 'DR7Op': ('ControlReg', 'uqw', 'MISCREG_DR7', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202), + 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203), + 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204), + 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205), + 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206), + 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207), + 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 208), + 'CSAttr': ('ControlReg', 'udw', 'MISCREG_CS_ATTR', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 209), + 'MiscRegDest': ('ControlReg', 'uqw', 'dest', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 210), + 'MiscRegSrc1': ('ControlReg', 'uqw', 'src1', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 211), + 'TscOp': ('ControlReg', 'uqw', 'MISCREG_TSC', (None, None, ['IsSerializeAfter', 'IsSerializing', 'IsNonSpeculative']), 212), + 'M5Reg': ('ControlReg', 'uqw', 'MISCREG_M5_REG', (None, None, None), 213), 'Mem': ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 300) }}; diff --git a/src/arch/x86/isa/rom.isa b/src/arch/x86/isa/rom.isa new file mode 100644 index 000000000..7d3eb8670 --- /dev/null +++ b/src/arch/x86/isa/rom.isa @@ -0,0 +1,90 @@ +// Copyright (c) 2008 The Regents of The University of Michigan +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Gabe Black + +def template MicroRomConstructor {{ + + %(define_generators)s + const MicroPC X86ISA::MicrocodeRom::numMicroops = %(num_microops)s; + + X86ISA::MicrocodeRom::MicrocodeRom() + { + using namespace RomLabels; + genFuncs = new GenFunc[numMicroops]; + %(alloc_generators)s; + } +}}; + +let {{ + from micro_asm import Rom + + class X86MicrocodeRom(Rom): + def __init__(self, name): + super(X86MicrocodeRom, self).__init__(name) + self.directives = {} + + def add_microop(self, mnemonic, microop): + microop.mnemonic = mnemonic + microop.micropc = len(self.microops) + self.microops.append(microop) + + + def getDeclaration(self): + declareLabels = "namespace RomLabels {\n" + for (label, microop) in self.labels.items(): + declareLabels += "const static uint64_t label_%s = %d;\n" \ + % (label, microop.micropc) + for (label, microop) in self.externs.items(): + declareLabels += \ + "const static MicroPC extern_label_%s = %d;\n" \ + % (label, microop.micropc) + declareLabels += "}\n" + return declareLabels; + + def getDefinition(self): + numMicroops = len(self.microops) + allocGenerators = '' + micropc = 0 + define_generators = ''' + namespace + { + static const char romMnemonic[] = "Microcode_ROM"; + ''' + for op in self.microops: + define_generators += op.getGeneratorDef(micropc) + allocGenerators += "genFuncs[%d] = %s;\n" % \ + (micropc, op.getGenerator(micropc)) + micropc += 1 + define_generators += "}\n" + iop = InstObjParams(self.name, self.name, "MicrocodeRom", + {"code" : "", + "define_generators" : define_generators, + "num_microops" : numMicroops, + "alloc_generators" : allocGenerators + }) + return MicroRomConstructor.subst(iop); +}}; diff --git a/src/arch/x86/isa/specialize.isa b/src/arch/x86/isa/specialize.isa index abf734307..b74363470 100644 --- a/src/arch/x86/isa/specialize.isa +++ b/src/arch/x86/isa/specialize.isa @@ -86,8 +86,17 @@ let {{ let {{ def doRipRelativeDecode(Name, opTypes, env): # print "RIPing %s with opTypes %s" % (Name, opTypes) - normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), copy.copy(env)) - ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), copy.copy(env)) + env.memoryInst = True + normEnv = copy.copy(env) + normEnv.addToDisassembly( + '''printMem(out, env.seg, env.scale, env.index, env.base, + machInst.displacement, env.addressSize, false);''') + normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv) + ripEnv = copy.copy(env) + ripEnv.addToDisassembly( + '''printMem(out, env.seg, 1, 0, 0, + machInst.displacement, env.addressSize, true);''') + ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv) blocks = OutputBlocks() blocks.append(normBlocks) @@ -138,12 +147,17 @@ let {{ #Figure out what to do with fixed register operands #This is the index to use, so we should stick it some place. if opType.reg in ("A", "B", "C", "D"): - env.addReg("INTREG_R%sX" % opType.reg) + regString = "INTREG_R%sX" % opType.reg else: - env.addReg("INTREG_R%s" % opType.reg) + regString = "INTREG_R%s" % opType.reg + env.addReg(regString) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % regString) Name += "_R" elif opType.tag == "B": # This refers to registers whose index is encoded as part of the opcode + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % InstRegIndex) Name += "_R" env.addReg(InstRegIndex) elif opType.tag == "M": @@ -156,24 +170,34 @@ let {{ elif opType.tag == "C": # A control register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex) Name += "_C" elif opType.tag == "D": # A debug register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex) Name += "_D" elif opType.tag == "S": # A segment selector register indexed by the "reg" field env.addReg(ModRMRegIndex) + env.addToDisassembly( + "printSegment(out, %s);\n" % ModRMRegIndex) Name += "_S" elif opType.tag in ("G", "P", "T", "V"): # Use the "reg" field of the ModRM byte to select the register env.addReg(ModRMRegIndex) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRegIndex) Name += "_R" elif opType.tag in ("E", "Q", "W"): # This might refer to memory or to a register. We need to # divide it up farther. regEnv = copy.copy(env) regEnv.addReg(ModRMRMIndex) + regEnv.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRMIndex) # This refers to memory. The macroop constructor should set up # modrm addressing. memEnv = copy.copy(env) @@ -183,6 +207,8 @@ let {{ (doRipRelativeDecode, Name, copy.copy(opTypes), memEnv)) elif opType.tag in ("I", "J"): # Immediates + env.addToDisassembly( + "ccprintf(out, \"%#x\", machInst.immediate);\n") Name += "_I" elif opType.tag == "O": # Immediate containing a memory offset @@ -190,10 +216,22 @@ let {{ elif opType.tag in ("PR", "R", "VR"): # Non register modrm settings should cause an error env.addReg(ModRMRMIndex) + env.addToDisassembly( + "printReg(out, %s, regSize);\n" % ModRMRMIndex) Name += "_R" elif opType.tag in ("X", "Y"): # This type of memory addressing is for string instructions. # They'll use the right index and segment internally. + if opType.tag == "X": + env.addToDisassembly( + '''printMem(out, env.seg, + 1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0, + env.addressSize, false);''') + else: + env.addToDisassembly( + '''printMem(out, SEGMENT_REG_ES, + 1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0, + env.addressSize, false);''') Name += "_M" else: raise Exception, "Unrecognized tag %s." % opType.tag diff --git a/src/arch/x86/isa_traits.hh b/src/arch/x86/isa_traits.hh index abb7694ed..d25e0eb70 100644 --- a/src/arch/x86/isa_traits.hh +++ b/src/arch/x86/isa_traits.hh @@ -106,19 +106,7 @@ namespace X86ISA const int StackPointerReg = INTREG_RSP; //X86 doesn't seem to have a link register const int ReturnAddressReg = 0; - const int ReturnValueReg = INTREG_RAX; const int FramePointerReg = INTREG_RBP; - const int ArgumentReg[] = { - INTREG_RDI, - INTREG_RSI, - INTREG_RDX, - //This argument register is r10 for syscalls and rcx for C. - INTREG_R10W, - //INTREG_RCX, - INTREG_R8W, - INTREG_R9W - }; - const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); // Some OS syscalls use a second register (rdx) to return a second // value diff --git a/src/arch/x86/linux/linux.cc b/src/arch/x86/linux/linux.cc index 5e8d2de16..41855da59 100644 --- a/src/arch/x86/linux/linux.cc +++ b/src/arch/x86/linux/linux.cc @@ -97,3 +97,42 @@ const int X86Linux64::NUM_OPEN_FLAGS = sizeof(X86Linux64::openFlagTable) / sizeof(X86Linux64::openFlagTable[0]); +// open(2) flags translation table +OpenFlagTransTable X86Linux32::openFlagTable[] = { +#ifdef _MSC_VER + { TGT_O_RDONLY, _O_RDONLY }, + { TGT_O_WRONLY, _O_WRONLY }, + { TGT_O_RDWR, _O_RDWR }, + { TGT_O_APPEND, _O_APPEND }, + { TGT_O_CREAT, _O_CREAT }, + { TGT_O_TRUNC, _O_TRUNC }, + { TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { TGT_O_RDONLY, O_RDONLY }, + { TGT_O_WRONLY, O_WRONLY }, + { TGT_O_RDWR, O_RDWR }, + { TGT_O_APPEND, O_APPEND }, + { TGT_O_CREAT, O_CREAT }, + { TGT_O_TRUNC, O_TRUNC }, + { TGT_O_EXCL, O_EXCL }, + { TGT_O_NONBLOCK, O_NONBLOCK }, + { TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int X86Linux32::NUM_OPEN_FLAGS = + sizeof(X86Linux32::openFlagTable) / + sizeof(X86Linux32::openFlagTable[0]); + diff --git a/src/arch/x86/linux/linux.hh b/src/arch/x86/linux/linux.hh index 8a78d5320..c2941c769 100644 --- a/src/arch/x86/linux/linux.hh +++ b/src/arch/x86/linux/linux.hh @@ -82,26 +82,26 @@ class X86Linux64 : public Linux uint64_t st_mtime_nsec; uint64_t st_ctimeX; uint64_t st_ctime_nsec; - int64_t __unused[3]; + int64_t unused0[3]; } tgt_stat64; static OpenFlagTransTable openFlagTable[]; - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00002000; //!< O_APPEND - static const int TGT_O_CREAT = 00000100; //!< O_CREAT - static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC - static const int TGT_O_EXCL = 00000200; //!< O_EXCL - static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY - static const int TGT_O_SYNC = 00010000; //!< O_SYNC -// static const int TGT_O_DRD = 0x00010000; //!< O_DRD -// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO -// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE -// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC -// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00002000; //!< O_APPEND + static const int TGT_O_CREAT = 00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC + static const int TGT_O_EXCL = 00000200; //!< O_EXCL + static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY + static const int TGT_O_SYNC = 00010000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC static const int NUM_OPEN_FLAGS; @@ -113,4 +113,53 @@ class X86Linux64 : public Linux } tgt_iovec; }; +class X86Linux32 : public Linux +{ + public: + + typedef struct { + uint64_t st_dev; + uint8_t __pad0[4]; + uint32_t __st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + int64_t st_size; + uint8_t __pad3[4]; + uint32_t st_blksize; + uint64_t st_blocks; + uint32_t st_atimeX; + uint32_t st_atime_nsec; + uint32_t st_mtimeX; + uint32_t st_mtime_nsec; + uint32_t st_ctimeX; + uint32_t st_ctime_nsec; + uint64_t st_ino; + } tgt_stat64; + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00002000; //!< O_APPEND + static const int TGT_O_CREAT = 00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC + static const int TGT_O_EXCL = 00000200; //!< O_EXCL + static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY + static const int TGT_O_SYNC = 00010000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x20; +}; + #endif diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc index 8beaf150b..da22d9851 100644 --- a/src/arch/x86/linux/process.cc +++ b/src/arch/x86/linux/process.cc @@ -64,34 +64,16 @@ #include "kern/linux/linux.hh" #include "sim/process.hh" -#include "sim/syscall_emul.hh" using namespace std; using namespace X86ISA; -SyscallDesc* -X86LinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} - -X86LinuxProcess::X86LinuxProcess(LiveProcessParams * params, +X86_64LinuxProcess::X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile) - : X86LiveProcess(params, objFile), - Num_Syscall_Descs(273) + : X86_64LiveProcess(params, objFile, syscallDescs, 273) {} -void X86LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) -{ - switch(trapNum) - { - //This implementation is from SPARC - case 0x10: //Linux 32 bit syscall trap - tc->syscall(tc->readIntReg(1)); - break; - default: - X86LiveProcess::handleTrap(trapNum, tc); - } -} +I386LinuxProcess::I386LinuxProcess(LiveProcessParams * params, + ObjectFile *objFile) + : I386LiveProcess(params, objFile, syscallDescs, 324) +{} diff --git a/src/arch/x86/linux/process.hh b/src/arch/x86/linux/process.hh index e224374d4..ca3606ef0 100644 --- a/src/arch/x86/linux/process.hh +++ b/src/arch/x86/linux/process.hh @@ -60,26 +60,30 @@ #include "sim/process.hh" #include "arch/x86/linux/linux.hh" -#include "arch/x86/syscallreturn.hh" #include "arch/x86/process.hh" namespace X86ISA { -/// A process with emulated x86/Linux syscalls. -class X86LinuxProcess : public X86LiveProcess +class X86_64LinuxProcess : public X86_64LiveProcess { + protected: + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + public: /// Constructor. - X86LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); + X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); +}; +class I386LinuxProcess : public I386LiveProcess +{ + protected: /// Array of syscall descriptors, indexed by call number. static SyscallDesc syscallDescs[]; - SyscallDesc* getDesc(int callnum); - - const int Num_Syscall_Descs; - - void handleTrap(int trapNum, ThreadContext *tc); + public: + /// Constructor. + I386LinuxProcess(LiveProcessParams * params, ObjectFile *objFile); }; } // namespace X86ISA diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc index ae2ac243b..09235ec94 100644 --- a/src/arch/x86/linux/syscalls.cc +++ b/src/arch/x86/linux/syscalls.cc @@ -68,7 +68,7 @@ static SyscallReturn unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); @@ -94,8 +94,8 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, }; //First argument is the code, second is the address - int code = tc->getSyscallArg(0); - uint64_t addr = tc->getSyscallArg(1); + int code = process->getSyscallArg(tc, 0); + uint64_t addr = process->getSyscallArg(tc, 1); uint64_t fsBase, gsBase; TranslatingPort *p = tc->getMemPort(); switch(code) @@ -122,7 +122,112 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, } } -SyscallDesc X86LinuxProcess::syscallDescs[] = { +BitUnion32(UserDescFlags) + Bitfield<0> seg_32bit; + Bitfield<2, 1> contents; + Bitfield<3> read_exec_only; + Bitfield<4> limit_in_pages; + Bitfield<5> seg_not_present; + Bitfield<6> useable; +EndBitUnion(UserDescFlags) + +struct UserDesc32 { + uint32_t entry_number; + uint32_t base_addr; + uint32_t limit; + uint32_t flags; +}; + +struct UserDesc64 { + uint32_t entry_number; + uint32_t __padding1; + uint64_t base_addr; + uint32_t limit; + uint32_t flags; +}; + +static SyscallReturn +setThreadArea32Func(SyscallDesc *desc, int callnum, + LiveProcess *process, ThreadContext *tc) +{ + const int minTLSEntry = 6; + const int numTLSEntries = 3; + const int maxTLSEntry = minTLSEntry + numTLSEntries - 1; + + X86LiveProcess *x86lp = dynamic_cast<X86LiveProcess *>(process); + assert(x86lp); + + assert((maxTLSEntry + 1) * sizeof(uint64_t) <= x86lp->gdtSize()); + + TypedBufferArg<UserDesc32> userDesc(process->getSyscallArg(tc, 0)); + TypedBufferArg<uint64_t> + gdt(x86lp->gdtStart() + minTLSEntry * sizeof(uint64_t), + numTLSEntries * sizeof(uint64_t)); + + if (!userDesc.copyIn(tc->getMemPort())) + return -EFAULT; + + if (!gdt.copyIn(tc->getMemPort())) + panic("Failed to copy in GDT for %s.\n", desc->name); + + if (userDesc->entry_number == (uint32_t)(-1)) { + // Find a free TLS entry. + for (int i = 0; i < numTLSEntries; i++) { + if (gdt[i] == 0) { + userDesc->entry_number = i + minTLSEntry; + break; + } + } + // We failed to find one. + if (userDesc->entry_number == (uint32_t)(-1)) + return -ESRCH; + } + + int index = userDesc->entry_number; + + if (index < minTLSEntry || index > maxTLSEntry) + return -EINVAL; + + index -= minTLSEntry; + + // Build the entry we're going to add. + SegDescriptor segDesc = 0; + UserDescFlags flags = userDesc->flags; + + segDesc.limitLow = bits(userDesc->limit, 15, 0); + segDesc.baseLow = bits(userDesc->base_addr, 23, 0); + segDesc.type.a = 1; + if (!flags.read_exec_only) + segDesc.type.w = 1; + if (bits((uint8_t)flags.contents, 0)) + segDesc.type.e = 1; + if (bits((uint8_t)flags.contents, 1)) + segDesc.type.codeOrData = 1; + segDesc.s = 1; + segDesc.dpl = 3; + if (!flags.seg_not_present) + segDesc.p = 1; + segDesc.limitHigh = bits(userDesc->limit, 19, 16); + if (flags.useable) + segDesc.avl = 1; + segDesc.l = 0; + if (flags.seg_32bit) + segDesc.d = 1; + if (flags.limit_in_pages) + segDesc.g = 1; + segDesc.baseHigh = bits(userDesc->base_addr, 31, 24); + + gdt[index] = (uint64_t)segDesc; + + if (!userDesc.copyOut(tc->getMemPort())) + return -EFAULT; + if (!gdt.copyOut(tc->getMemPort())) + panic("Failed to copy out GDT for %s.\n", desc->name); + + return 0; +} + +SyscallDesc X86_64LinuxProcess::syscallDescs[] = { /* 0 */ SyscallDesc("read", readFunc), /* 1 */ SyscallDesc("write", writeFunc), /* 2 */ SyscallDesc("open", openFunc<X86Linux64>), @@ -135,7 +240,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 9 */ SyscallDesc("mmap", mmapFunc<X86Linux64>), /* 10 */ SyscallDesc("mprotect", unimplementedFunc), /* 11 */ SyscallDesc("munmap", munmapFunc), - /* 12 */ SyscallDesc("brk", obreakFunc), + /* 12 */ SyscallDesc("brk", brkFunc), /* 13 */ SyscallDesc("rt_sigaction", unimplementedFunc), /* 14 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), /* 15 */ SyscallDesc("rt_sigreturn", unimplementedFunc), @@ -148,7 +253,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 22 */ SyscallDesc("pipe", unimplementedFunc), /* 23 */ SyscallDesc("select", unimplementedFunc), /* 24 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 25 */ SyscallDesc("mremap", unimplementedFunc), + /* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>), /* 26 */ SyscallDesc("msync", unimplementedFunc), /* 27 */ SyscallDesc("mincore", unimplementedFunc), /* 28 */ SyscallDesc("madvise", unimplementedFunc), @@ -397,3 +502,330 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = { /* 271 */ SyscallDesc("ppoll", unimplementedFunc), /* 272 */ SyscallDesc("unshare", unimplementedFunc) }; + +SyscallDesc I386LinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", unimplementedFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", unimplementedFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<X86Linux64>), + /* 6 */ SyscallDesc("close", unimplementedFunc), + /* 7 */ SyscallDesc("waitpid", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unimplementedFunc), + /* 11 */ SyscallDesc("execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", unimplementedFunc), + /* 16 */ SyscallDesc("lchown", unimplementedFunc), + /* 17 */ SyscallDesc("break", unimplementedFunc), + /* 18 */ SyscallDesc("oldstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", unimplementedFunc), + /* 20 */ SyscallDesc("getpid", unimplementedFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", unimplementedFunc), + /* 24 */ SyscallDesc("getuid", unimplementedFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("oldfstat", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("ftime", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("rename", unimplementedFunc), + /* 39 */ SyscallDesc("mkdir", unimplementedFunc), + /* 40 */ SyscallDesc("rmdir", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("prof", unimplementedFunc), + /* 45 */ SyscallDesc("brk", brkFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", unimplementedFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("geteuid", unimplementedFunc), + /* 50 */ SyscallDesc("getegid", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("umount2", unimplementedFunc), + /* 53 */ SyscallDesc("lock", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("fcntl", unimplementedFunc), + /* 56 */ SyscallDesc("mpx", unimplementedFunc), + /* 57 */ SyscallDesc("setpgid", unimplementedFunc), + /* 58 */ SyscallDesc("ulimit", unimplementedFunc), + /* 59 */ SyscallDesc("oldolduname", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("ustat", unimplementedFunc), + /* 63 */ SyscallDesc("dup2", unimplementedFunc), + /* 64 */ SyscallDesc("getppid", unimplementedFunc), + /* 65 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 66 */ SyscallDesc("setsid", unimplementedFunc), + /* 67 */ SyscallDesc("sigaction", unimplementedFunc), + /* 68 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 69 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 70 */ SyscallDesc("setreuid", unimplementedFunc), + /* 71 */ SyscallDesc("setregid", unimplementedFunc), + /* 72 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 73 */ SyscallDesc("sigpending", unimplementedFunc), + /* 74 */ SyscallDesc("sethostname", unimplementedFunc), + /* 75 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 76 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 77 */ SyscallDesc("getrusage", unimplementedFunc), + /* 78 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 79 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 80 */ SyscallDesc("getgroups", unimplementedFunc), + /* 81 */ SyscallDesc("setgroups", unimplementedFunc), + /* 82 */ SyscallDesc("select", unimplementedFunc), + /* 83 */ SyscallDesc("symlink", unimplementedFunc), + /* 84 */ SyscallDesc("oldlstat", unimplementedFunc), + /* 85 */ SyscallDesc("readlink", unimplementedFunc), + /* 86 */ SyscallDesc("uselib", unimplementedFunc), + /* 87 */ SyscallDesc("swapon", unimplementedFunc), + /* 88 */ SyscallDesc("reboot", unimplementedFunc), + /* 89 */ SyscallDesc("readdir", unimplementedFunc), + /* 90 */ SyscallDesc("mmap", unimplementedFunc), + /* 91 */ SyscallDesc("munmap", unimplementedFunc), + /* 92 */ SyscallDesc("truncate", unimplementedFunc), + /* 93 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 94 */ SyscallDesc("fchmod", unimplementedFunc), + /* 95 */ SyscallDesc("fchown", unimplementedFunc), + /* 96 */ SyscallDesc("getpriority", unimplementedFunc), + /* 97 */ SyscallDesc("setpriority", unimplementedFunc), + /* 98 */ SyscallDesc("profil", unimplementedFunc), + /* 99 */ SyscallDesc("statfs", unimplementedFunc), + /* 100 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 101 */ SyscallDesc("ioperm", unimplementedFunc), + /* 102 */ SyscallDesc("socketcall", unimplementedFunc), + /* 103 */ SyscallDesc("syslog", unimplementedFunc), + /* 104 */ SyscallDesc("setitimer", unimplementedFunc), + /* 105 */ SyscallDesc("getitimer", unimplementedFunc), + /* 106 */ SyscallDesc("stat", unimplementedFunc), + /* 107 */ SyscallDesc("lstat", unimplementedFunc), + /* 108 */ SyscallDesc("fstat", unimplementedFunc), + /* 109 */ SyscallDesc("olduname", unimplementedFunc), + /* 110 */ SyscallDesc("iopl", unimplementedFunc), + /* 111 */ SyscallDesc("vhangup", unimplementedFunc), + /* 112 */ SyscallDesc("idle", unimplementedFunc), + /* 113 */ SyscallDesc("vm86old", unimplementedFunc), + /* 114 */ SyscallDesc("wait4", unimplementedFunc), + /* 115 */ SyscallDesc("swapoff", unimplementedFunc), + /* 116 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 117 */ SyscallDesc("ipc", unimplementedFunc), + /* 118 */ SyscallDesc("fsync", unimplementedFunc), + /* 119 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 120 */ SyscallDesc("clone", unimplementedFunc), + /* 121 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 122 */ SyscallDesc("uname", unameFunc), + /* 123 */ SyscallDesc("modify_ldt", unimplementedFunc), + /* 124 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 125 */ SyscallDesc("mprotect", unimplementedFunc), + /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 127 */ SyscallDesc("create_module", unimplementedFunc), + /* 128 */ SyscallDesc("init_module", unimplementedFunc), + /* 129 */ SyscallDesc("delete_module", unimplementedFunc), + /* 130 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 131 */ SyscallDesc("quotactl", unimplementedFunc), + /* 132 */ SyscallDesc("getpgid", unimplementedFunc), + /* 133 */ SyscallDesc("fchdir", unimplementedFunc), + /* 134 */ SyscallDesc("bdflush", unimplementedFunc), + /* 135 */ SyscallDesc("sysfs", unimplementedFunc), + /* 136 */ SyscallDesc("personality", unimplementedFunc), + /* 137 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 138 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 139 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 140 */ SyscallDesc("_llseek", unimplementedFunc), + /* 141 */ SyscallDesc("getdents", unimplementedFunc), + /* 142 */ SyscallDesc("_newselect", unimplementedFunc), + /* 143 */ SyscallDesc("flock", unimplementedFunc), + /* 144 */ SyscallDesc("msync", unimplementedFunc), + /* 145 */ SyscallDesc("readv", unimplementedFunc), + /* 146 */ SyscallDesc("writev", writevFunc<X86Linux32>), + /* 147 */ SyscallDesc("getsid", unimplementedFunc), + /* 148 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 149 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 150 */ SyscallDesc("mlock", unimplementedFunc), + /* 151 */ SyscallDesc("munlock", unimplementedFunc), + /* 152 */ SyscallDesc("mlockall", unimplementedFunc), + /* 153 */ SyscallDesc("munlockall", unimplementedFunc), + /* 154 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 155 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 156 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 157 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 158 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 159 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 160 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 161 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 162 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 163 */ SyscallDesc("mremap", unimplementedFunc), + /* 164 */ SyscallDesc("setresuid", unimplementedFunc), + /* 165 */ SyscallDesc("getresuid", unimplementedFunc), + /* 166 */ SyscallDesc("vm86", unimplementedFunc), + /* 167 */ SyscallDesc("query_module", unimplementedFunc), + /* 168 */ SyscallDesc("poll", unimplementedFunc), + /* 169 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 170 */ SyscallDesc("setresgid", unimplementedFunc), + /* 171 */ SyscallDesc("getresgid", unimplementedFunc), + /* 172 */ SyscallDesc("prctl", unimplementedFunc), + /* 173 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 174 */ SyscallDesc("rt_sigaction", unimplementedFunc), + /* 175 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 176 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 177 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 178 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 179 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 180 */ SyscallDesc("pread64", unimplementedFunc), + /* 181 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 182 */ SyscallDesc("chown", unimplementedFunc), + /* 183 */ SyscallDesc("getcwd", unimplementedFunc), + /* 184 */ SyscallDesc("capget", unimplementedFunc), + /* 185 */ SyscallDesc("capset", unimplementedFunc), + /* 186 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 187 */ SyscallDesc("sendfile", unimplementedFunc), + /* 188 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 189 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 190 */ SyscallDesc("vfork", unimplementedFunc), + /* 191 */ SyscallDesc("ugetrlimit", unimplementedFunc), + /* 192 */ SyscallDesc("mmap2", mmapFunc<X86Linux32>), + /* 193 */ SyscallDesc("truncate64", unimplementedFunc), + /* 194 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 195 */ SyscallDesc("stat64", unimplementedFunc), + /* 196 */ SyscallDesc("lstat64", unimplementedFunc), + /* 197 */ SyscallDesc("fstat64", fstat64Func<X86Linux32>), + /* 198 */ SyscallDesc("lchown32", unimplementedFunc), + /* 199 */ SyscallDesc("getuid32", unimplementedFunc), + /* 200 */ SyscallDesc("getgid32", unimplementedFunc), + /* 201 */ SyscallDesc("geteuid32", unimplementedFunc), + /* 202 */ SyscallDesc("getegid32", unimplementedFunc), + /* 203 */ SyscallDesc("setreuid32", unimplementedFunc), + /* 204 */ SyscallDesc("setregid32", unimplementedFunc), + /* 205 */ SyscallDesc("getgroups32", unimplementedFunc), + /* 206 */ SyscallDesc("setgroups32", unimplementedFunc), + /* 207 */ SyscallDesc("fchown32", unimplementedFunc), + /* 208 */ SyscallDesc("setresuid32", unimplementedFunc), + /* 209 */ SyscallDesc("getresuid32", unimplementedFunc), + /* 210 */ SyscallDesc("setresgid32", unimplementedFunc), + /* 211 */ SyscallDesc("getresgid32", unimplementedFunc), + /* 212 */ SyscallDesc("chown32", unimplementedFunc), + /* 213 */ SyscallDesc("setuid32", unimplementedFunc), + /* 214 */ SyscallDesc("setgid32", unimplementedFunc), + /* 215 */ SyscallDesc("setfsuid32", unimplementedFunc), + /* 216 */ SyscallDesc("setfsgid32", unimplementedFunc), + /* 217 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 218 */ SyscallDesc("mincore", unimplementedFunc), + /* 219 */ SyscallDesc("madvise", unimplementedFunc), + /* 220 */ SyscallDesc("madvise1", unimplementedFunc), + /* 221 */ SyscallDesc("getdents64", unimplementedFunc), + /* 222 */ SyscallDesc("fcntl64", unimplementedFunc), + /* 223 */ SyscallDesc("unused", unimplementedFunc), + /* 224 */ SyscallDesc("gettid", unimplementedFunc), + /* 225 */ SyscallDesc("readahead", unimplementedFunc), + /* 226 */ SyscallDesc("setxattr", unimplementedFunc), + /* 227 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 228 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 229 */ SyscallDesc("getxattr", unimplementedFunc), + /* 230 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 231 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 232 */ SyscallDesc("listxattr", unimplementedFunc), + /* 233 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 234 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 235 */ SyscallDesc("removexattr", unimplementedFunc), + /* 236 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 237 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 238 */ SyscallDesc("tkill", unimplementedFunc), + /* 239 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 240 */ SyscallDesc("futex", unimplementedFunc), + /* 241 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 242 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 243 */ SyscallDesc("set_thread_area", setThreadArea32Func), + /* 244 */ SyscallDesc("get_thread_area", unimplementedFunc), + /* 245 */ SyscallDesc("io_setup", unimplementedFunc), + /* 246 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 247 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 248 */ SyscallDesc("io_submit", unimplementedFunc), + /* 249 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 250 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 251 */ SyscallDesc("unused", unimplementedFunc), + /* 252 */ SyscallDesc("exit_group", exitFunc), + /* 253 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 254 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 255 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 256 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 257 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 258 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 259 */ SyscallDesc("timer_create", unimplementedFunc), + /* 260 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 261 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 262 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 263 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 264 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 265 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 266 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 267 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 268 */ SyscallDesc("statfs64", unimplementedFunc), + /* 269 */ SyscallDesc("fstatfs64", unimplementedFunc), + /* 270 */ SyscallDesc("tgkill", unimplementedFunc), + /* 271 */ SyscallDesc("utimes", unimplementedFunc), + /* 272 */ SyscallDesc("fadvise64_64", unimplementedFunc), + /* 273 */ SyscallDesc("vserver", unimplementedFunc), + /* 274 */ SyscallDesc("mbind", unimplementedFunc), + /* 275 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 276 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 277 */ SyscallDesc("mq_open", unimplementedFunc), + /* 278 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 279 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 280 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 281 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 282 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 283 */ SyscallDesc("kexec_load", unimplementedFunc), + /* 284 */ SyscallDesc("waitid", unimplementedFunc), + /* 285 */ SyscallDesc("sys_setaltroot", unimplementedFunc), + /* 286 */ SyscallDesc("add_key", unimplementedFunc), + /* 287 */ SyscallDesc("request_key", unimplementedFunc), + /* 288 */ SyscallDesc("keyctl", unimplementedFunc), + /* 289 */ SyscallDesc("ioprio_set", unimplementedFunc), + /* 290 */ SyscallDesc("ioprio_get", unimplementedFunc), + /* 291 */ SyscallDesc("inotify_init", unimplementedFunc), + /* 292 */ SyscallDesc("inotify_add_watch", unimplementedFunc), + /* 293 */ SyscallDesc("inotify_rm_watch", unimplementedFunc), + /* 294 */ SyscallDesc("migrate_pages", unimplementedFunc), + /* 295 */ SyscallDesc("openat", unimplementedFunc), + /* 296 */ SyscallDesc("mkdirat", unimplementedFunc), + /* 297 */ SyscallDesc("mknodat", unimplementedFunc), + /* 298 */ SyscallDesc("fchownat", unimplementedFunc), + /* 299 */ SyscallDesc("futimesat", unimplementedFunc), + /* 300 */ SyscallDesc("fstatat64", unimplementedFunc), + /* 301 */ SyscallDesc("unlinkat", unimplementedFunc), + /* 302 */ SyscallDesc("renameat", unimplementedFunc), + /* 303 */ SyscallDesc("linkat", unimplementedFunc), + /* 304 */ SyscallDesc("symlinkat", unimplementedFunc), + /* 305 */ SyscallDesc("readlinkat", unimplementedFunc), + /* 306 */ SyscallDesc("fchmodat", unimplementedFunc), + /* 307 */ SyscallDesc("faccessat", unimplementedFunc), + /* 308 */ SyscallDesc("pselect6", unimplementedFunc), + /* 309 */ SyscallDesc("ppoll", unimplementedFunc), + /* 310 */ SyscallDesc("unshare", unimplementedFunc), + /* 311 */ SyscallDesc("set_robust_list", unimplementedFunc), + /* 312 */ SyscallDesc("get_robust_list", unimplementedFunc), + /* 313 */ SyscallDesc("splice", unimplementedFunc), + /* 314 */ SyscallDesc("sync_file_range", unimplementedFunc), + /* 315 */ SyscallDesc("tee", unimplementedFunc), + /* 316 */ SyscallDesc("vmsplice", unimplementedFunc), + /* 317 */ SyscallDesc("move_pages", unimplementedFunc), + /* 318 */ SyscallDesc("getcpu", unimplementedFunc), + /* 319 */ SyscallDesc("epoll_pwait", unimplementedFunc), + /* 320 */ SyscallDesc("utimensat", unimplementedFunc), + /* 321 */ SyscallDesc("signalfd", unimplementedFunc), + /* 322 */ SyscallDesc("timerfd", unimplementedFunc), + /* 323 */ SyscallDesc("eventfd", unimplementedFunc) +}; diff --git a/src/arch/x86/linux/system.cc b/src/arch/x86/linux/system.cc index 944bb2930..c2d9cb35c 100644 --- a/src/arch/x86/linux/system.cc +++ b/src/arch/x86/linux/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -68,7 +68,7 @@ using namespace LittleEndianGuest; using namespace X86ISA; LinuxX86System::LinuxX86System(Params *p) - : X86System(p), commandLine(p->boot_osflags) + : X86System(p), commandLine(p->boot_osflags), e820Table(p->e820_table) { } @@ -144,62 +144,7 @@ LinuxX86System::startup() // A pointer to the buffer for E820 entries. const Addr e820MapPointer = realModeData + 0x2d0; - struct e820Entry - { - Addr addr; - Addr size; - uint32_t type; - }; - - // The size is computed this way to ensure no padding sneaks in. - int e820EntrySize = - sizeof(e820Entry().addr) + - sizeof(e820Entry().size) + - sizeof(e820Entry().type); - - // I'm not sure what these should actually be. On a real machine they - // would be generated by the BIOS, and they need to reflect the regions - // which are actually available/reserved. These values are copied from - // my development machine. - e820Entry e820Map[] = { - {ULL(0x0), ULL(0x9d400), 1}, - {ULL(0x9d400), ULL(0xa0000) - ULL(0x9d400), 2}, - {ULL(0xe8000), ULL(0x100000) - ULL(0xe8000), 2}, - {ULL(0x100000), ULL(0xcfff9300) - ULL(0x100000), 1}, - {ULL(0xcfff9300), ULL(0xd0000000) - ULL(0xcfff9300), 2}, - {ULL(0xfec00000), ULL(0x100000000) - ULL(0xfec00000), 2} - }; - - uint8_t e820Nr = sizeof(e820Map) / sizeof(e820Entry); - - // Make sure the number of entries isn't bigger than what the kernel - // would be capable of providing. - assert(e820Nr <= 128); - - uint8_t guestE820Nr = X86ISA::htog(e820Nr); - physPort->writeBlob(e820MapNrPointer, - (uint8_t *)&guestE820Nr, sizeof(guestE820Nr)); - - for (int i = 0; i < e820Nr; i++) { - e820Entry guestE820Entry; - guestE820Entry.addr = X86ISA::htog(e820Map[i].addr); - guestE820Entry.size = X86ISA::htog(e820Map[i].size); - guestE820Entry.type = X86ISA::htog(e820Map[i].type); - physPort->writeBlob(e820MapPointer + e820EntrySize * i, - (uint8_t *)&guestE820Entry.addr, - sizeof(guestE820Entry.addr)); - physPort->writeBlob( - e820MapPointer + e820EntrySize * i + - sizeof(guestE820Entry.addr), - (uint8_t *)&guestE820Entry.size, - sizeof(guestE820Entry.size)); - physPort->writeBlob( - e820MapPointer + e820EntrySize * i + - sizeof(guestE820Entry.addr) + - sizeof(guestE820Entry.size), - (uint8_t *)&guestE820Entry.type, - sizeof(guestE820Entry.type)); - } + e820Table->writeTo(physPort, e820MapNrPointer, e820MapPointer); /* * Pass the location of the real mode data structure to the kernel diff --git a/src/arch/x86/linux/system.hh b/src/arch/x86/linux/system.hh index fc725ad45..a9c5f4ca9 100644 --- a/src/arch/x86/linux/system.hh +++ b/src/arch/x86/linux/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -62,12 +62,14 @@ #include <vector> #include "params/LinuxX86System.hh" +#include "arch/x86/bios/e820.hh" #include "arch/x86/system.hh" class LinuxX86System : public X86System { protected: std::string commandLine; + X86ISA::E820Table * e820Table; public: typedef LinuxX86SystemParams Params; diff --git a/src/arch/x86/microcode_rom.hh b/src/arch/x86/microcode_rom.hh new file mode 100644 index 000000000..f8ad410ce --- /dev/null +++ b/src/arch/x86/microcode_rom.hh @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_MICROCODE_ROM_HH__ +#define __ARCH_X86_MICROCODE_ROM_HH__ + +#include "arch/x86/emulenv.hh" +#include "cpu/static_inst.hh" + +namespace X86ISAInst +{ + class MicrocodeRom + { + protected: + + typedef StaticInstPtr (*GenFunc)(StaticInstPtr); + + static const MicroPC numMicroops; + + GenFunc * genFuncs; + + public: + //Constructor. + MicrocodeRom(); + + //Destructor. + ~MicrocodeRom() + { + delete [] genFuncs; + } + + StaticInstPtr + fetchMicroop(MicroPC microPC, StaticInstPtr curMacroop) + { + microPC = normalMicroPC(microPC); + assert(microPC < numMicroops); + return genFuncs[microPC](curMacroop); + } + }; +} + +namespace X86ISA +{ + using X86ISAInst::MicrocodeRom; +} + +#endif // __ARCH_X86_MICROCODE_ROM_HH__ diff --git a/src/arch/x86/miscregfile.cc b/src/arch/x86/miscregfile.cc index 3b4dc3407..0316603e5 100644 --- a/src/arch/x86/miscregfile.cc +++ b/src/arch/x86/miscregfile.cc @@ -87,6 +87,7 @@ #include "arch/x86/miscregfile.hh" #include "arch/x86/tlb.hh" +#include "cpu/base.hh" #include "cpu/thread_context.hh" #include "sim/serialize.hh" @@ -95,19 +96,16 @@ using namespace std; class Checkpoint; -//These functions map register indices to names -string X86ISA::getMiscRegName(RegIndex index) -{ - panic("No misc registers in x86 yet!\n"); -} - void MiscRegFile::clear() { - // Blank everything. 0 might not be an appropriate value for some things. + // Blank everything. 0 might not be an appropriate value for some things, + // but it is for most. memset(regVal, 0, NumMiscRegs * sizeof(MiscReg)); + regVal[MISCREG_DR6] = (mask(8) << 4) | (mask(16) << 16); + regVal[MISCREG_DR7] = 1 << 10; } -MiscReg MiscRegFile::readRegNoEffect(int miscReg) +MiscReg MiscRegFile::readRegNoEffect(MiscRegIndex miscReg) { // Make sure we're not dealing with an illegal control register. // Instructions should filter out these indexes, and nothing else should @@ -121,90 +119,15 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg) return regVal[miscReg]; } -MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc) +MiscReg MiscRegFile::readReg(MiscRegIndex miscReg, ThreadContext * tc) { - if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { - if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && - miscReg <= MISCREG_APIC_IN_SERVICE(15)) { - panic("Local APIC In-Service registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && - miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { - panic("Local APIC Trigger Mode registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && - miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { - panic("Local APIC Interrupt Request registers " - "are unimplemented.\n"); - } - switch (miscReg) { - case MISCREG_APIC_TASK_PRIORITY: - panic("Local APIC Task Priority register unimplemented.\n"); - break; - case MISCREG_APIC_ARBITRATION_PRIORITY: - panic("Local APIC Arbitration Priority register unimplemented.\n"); - break; - case MISCREG_APIC_PROCESSOR_PRIORITY: - panic("Local APIC Processor Priority register unimplemented.\n"); - break; - case MISCREG_APIC_EOI: - panic("Local APIC EOI register unimplemented.\n"); - break; - case MISCREG_APIC_LOGICAL_DESTINATION: - panic("Local APIC Logical Destination register unimplemented.\n"); - break; - case MISCREG_APIC_DESTINATION_FORMAT: - panic("Local APIC Destination Format register unimplemented.\n"); - break; - case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: - panic("Local APIC Spurious Interrupt Vector" - " register unimplemented.\n"); - break; - case MISCREG_APIC_ERROR_STATUS: - panic("Local APIC Error Status register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_TIMER: - panic("Local APIC LVT Timer register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_THERMAL_SENSOR: - panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: - panic("Local APIC LVT Performance Monitoring Counters" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT0: - panic("Local APIC LVT LINT0 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT1: - panic("Local APIC LVT LINT1 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_ERROR: - panic("Local APIC LVT Error register unimplemented.\n"); - break; - case MISCREG_APIC_INITIAL_COUNT: - panic("Local APIC Initial Count register unimplemented.\n"); - break; - case MISCREG_APIC_CURRENT_COUNT: - panic("Local APIC Current Count register unimplemented.\n"); - break; - case MISCREG_APIC_DIVIDE_COUNT: - panic("Local APIC Divide Count register unimplemented.\n"); - break; - } + if (miscReg == MISCREG_TSC) { + return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle(); } return readRegNoEffect(miscReg); } -void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val) +void MiscRegFile::setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val) { // Make sure we're not dealing with an illegal control register. // Instructions should filter out these indexes, and nothing else should @@ -217,96 +140,10 @@ void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val) regVal[miscReg] = val; } -void MiscRegFile::setReg(int miscReg, +void MiscRegFile::setReg(MiscRegIndex miscReg, const MiscReg &val, ThreadContext * tc) { MiscReg newVal = val; - if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { - if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && - miscReg <= MISCREG_APIC_IN_SERVICE(15)) { - panic("Local APIC In-Service registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && - miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { - panic("Local APIC Trigger Mode registers are unimplemented.\n"); - } - if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && - miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { - panic("Local APIC Interrupt Request registers " - "are unimplemented.\n"); - } - switch (miscReg) { - case MISCREG_APIC_ID: - panic("Local APIC ID register unimplemented.\n"); - break; - case MISCREG_APIC_VERSION: - panic("Local APIC Version register is read only.\n"); - break; - case MISCREG_APIC_TASK_PRIORITY: - panic("Local APIC Task Priority register unimplemented.\n"); - break; - case MISCREG_APIC_ARBITRATION_PRIORITY: - panic("Local APIC Arbitration Priority register unimplemented.\n"); - break; - case MISCREG_APIC_PROCESSOR_PRIORITY: - panic("Local APIC Processor Priority register unimplemented.\n"); - break; - case MISCREG_APIC_EOI: - panic("Local APIC EOI register unimplemented.\n"); - break; - case MISCREG_APIC_LOGICAL_DESTINATION: - panic("Local APIC Logical Destination register unimplemented.\n"); - break; - case MISCREG_APIC_DESTINATION_FORMAT: - panic("Local APIC Destination Format register unimplemented.\n"); - break; - case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: - panic("Local APIC Spurious Interrupt Vector" - " register unimplemented.\n"); - break; - case MISCREG_APIC_ERROR_STATUS: - panic("Local APIC Error Status register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_LOW: - panic("Local APIC Interrupt Command low" - " register unimplemented.\n"); - break; - case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: - panic("Local APIC Interrupt Command high" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_TIMER: - panic("Local APIC LVT Timer register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_THERMAL_SENSOR: - panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: - panic("Local APIC LVT Performance Monitoring Counters" - " register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT0: - panic("Local APIC LVT LINT0 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_LINT1: - panic("Local APIC LVT LINT1 register unimplemented.\n"); - break; - case MISCREG_APIC_LVT_ERROR: - panic("Local APIC LVT Error register unimplemented.\n"); - break; - case MISCREG_APIC_INITIAL_COUNT: - panic("Local APIC Initial Count register unimplemented.\n"); - break; - case MISCREG_APIC_CURRENT_COUNT: - panic("Local APIC Current Count register unimplemented.\n"); - break; - case MISCREG_APIC_DIVIDE_COUNT: - panic("Local APIC Divide Count register unimplemented.\n"); - break; - } - setRegNoEffect(miscReg, newVal); - return; - } switch(miscReg) { case MISCREG_CR0: @@ -314,17 +151,39 @@ void MiscRegFile::setReg(int miscReg, CR0 toggled = regVal[miscReg] ^ val; CR0 newCR0 = val; Efer efer = regVal[MISCREG_EFER]; + HandyM5Reg m5reg = regVal[MISCREG_M5_REG]; if (toggled.pg && efer.lme) { if (newCR0.pg) { //Turning on long mode efer.lma = 1; + m5reg.mode = LongMode; regVal[MISCREG_EFER] = efer; } else { //Turning off long mode efer.lma = 0; + m5reg.mode = LegacyMode; regVal[MISCREG_EFER] = efer; } } + // Figure out what submode we're in. + if (m5reg.mode == LongMode) { + SegAttr csAttr = regVal[MISCREG_CS_ATTR]; + if (csAttr.longMode) + m5reg.submode = SixtyFourBitMode; + else + m5reg.submode = CompatabilityMode; + } else { + if (newCR0.pe) { + RFLAGS rflags = regVal[MISCREG_RFLAGS]; + if (rflags.vm) + m5reg.submode = Virtual8086Mode; + else + m5reg.submode = ProtectedMode; + } else { + m5reg.submode = RealMode; + } + } + regVal[MISCREG_M5_REG] = m5reg; if (toggled.pg) { tc->getITBPtr()->invalidateAll(); tc->getDTBPtr()->invalidateAll(); @@ -355,20 +214,26 @@ void MiscRegFile::setReg(int miscReg, { SegAttr toggled = regVal[miscReg] ^ val; SegAttr newCSAttr = val; + HandyM5Reg m5reg = regVal[MISCREG_M5_REG]; if (toggled.longMode) { - SegAttr newCSAttr = val; if (newCSAttr.longMode) { + if (m5reg.mode == LongMode) + m5reg.submode = SixtyFourBitMode; regVal[MISCREG_ES_EFF_BASE] = 0; regVal[MISCREG_CS_EFF_BASE] = 0; regVal[MISCREG_SS_EFF_BASE] = 0; regVal[MISCREG_DS_EFF_BASE] = 0; } else { + if (m5reg.mode == LongMode) + m5reg.submode = CompatabilityMode; regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE]; regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE]; regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE]; regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE]; } } + m5reg.cpl = newCSAttr.dpl; + regVal[MISCREG_M5_REG] = m5reg; } break; // These segments always actually use their bases, or in other words @@ -396,6 +261,80 @@ void MiscRegFile::setReg(int miscReg, MISCREG_SEG_BASE_BASE)] = val; } break; + case MISCREG_TSC: + regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle(); + return; + case MISCREG_DR0: + case MISCREG_DR1: + case MISCREG_DR2: + case MISCREG_DR3: + /* These should eventually set up breakpoints. */ + break; + case MISCREG_DR4: + miscReg = MISCREG_DR6; + /* Fall through to have the same effects as DR6. */ + case MISCREG_DR6: + { + DR6 dr6 = regVal[MISCREG_DR6]; + DR6 newDR6 = val; + dr6.b0 = newDR6.b0; + dr6.b1 = newDR6.b1; + dr6.b2 = newDR6.b2; + dr6.b3 = newDR6.b3; + dr6.bd = newDR6.bd; + dr6.bs = newDR6.bs; + dr6.bt = newDR6.bt; + newVal = dr6; + } + break; + case MISCREG_DR5: + miscReg = MISCREG_DR7; + /* Fall through to have the same effects as DR7. */ + case MISCREG_DR7: + { + DR7 dr7 = regVal[MISCREG_DR7]; + DR7 newDR7 = val; + dr7.l0 = newDR7.l0; + dr7.g0 = newDR7.g0; + if (dr7.l0 || dr7.g0) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 0. */ + } + dr7.l1 = newDR7.l1; + dr7.g1 = newDR7.g1; + if (dr7.l1 || dr7.g1) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 1. */ + } + dr7.l2 = newDR7.l2; + dr7.g2 = newDR7.g2; + if (dr7.l2 || dr7.g2) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 2. */ + } + dr7.l3 = newDR7.l3; + dr7.g3 = newDR7.g3; + if (dr7.l3 || dr7.g3) { + panic("Debug register breakpoints not implemented.\n"); + } else { + /* Disable breakpoint 3. */ + } + dr7.gd = newDR7.gd; + dr7.rw0 = newDR7.rw0; + dr7.len0 = newDR7.len0; + dr7.rw1 = newDR7.rw1; + dr7.len1 = newDR7.len1; + dr7.rw2 = newDR7.rw2; + dr7.len2 = newDR7.len2; + dr7.rw3 = newDR7.rw3; + dr7.len3 = newDR7.len3; + } + break; + default: + break; } setRegNoEffect(miscReg, newVal); } diff --git a/src/arch/x86/miscregfile.hh b/src/arch/x86/miscregfile.hh index e095e06e9..6d3ae4e92 100644 --- a/src/arch/x86/miscregfile.hh +++ b/src/arch/x86/miscregfile.hh @@ -29,7 +29,7 @@ */ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -91,6 +91,7 @@ #include "arch/x86/faults.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/types.hh" +#include "sim/host.hh" #include <string> @@ -98,8 +99,6 @@ class Checkpoint; namespace X86ISA { - std::string getMiscRegName(RegIndex); - //These will have to be updated in the future. const int NumMiscArchRegs = NUM_MISCREGS; const int NumMiscRegs = NUM_MISCREGS; @@ -117,13 +116,13 @@ namespace X86ISA clear(); } - MiscReg readRegNoEffect(int miscReg); + MiscReg readRegNoEffect(MiscRegIndex miscReg); - MiscReg readReg(int miscReg, ThreadContext *tc); + MiscReg readReg(MiscRegIndex miscReg, ThreadContext *tc); - void setRegNoEffect(int miscReg, const MiscReg &val); + void setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val); - void setReg(int miscReg, + void setReg(MiscRegIndex miscReg, const MiscReg &val, ThreadContext *tc); void serialize(std::ostream & os); diff --git a/src/arch/x86/miscregs.hh b/src/arch/x86/miscregs.hh index d1016d2a9..af02e9422 100644 --- a/src/arch/x86/miscregs.hh +++ b/src/arch/x86/miscregs.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -82,6 +82,18 @@ namespace X86ISA OFBit = 1 << 11 }; + enum RFLAGBit { + TFBit = 1 << 8, + IFBit = 1 << 9, + NTBit = 1 << 14, + RFBit = 1 << 16, + VMBit = 1 << 17, + ACBit = 1 << 18, + VIFBit = 1 << 19, + VIPBit = 1 << 20, + IDBit = 1 << 21 + }; + enum MiscRegIndex { // Control registers @@ -118,6 +130,9 @@ namespace X86ISA // Flags register MISCREG_RFLAGS = MISCREG_DR_BASE + NumDRegs, + //Register to keep handy values like the CPU mode in. + MISCREG_M5_REG, + /* * Model Specific Registers */ @@ -183,6 +198,9 @@ namespace X86ISA MISCREG_MC2_CTL, MISCREG_MC3_CTL, MISCREG_MC4_CTL, + MISCREG_MC5_CTL, + MISCREG_MC6_CTL, + MISCREG_MC7_CTL, MISCREG_MC_STATUS_BASE, MISCREG_MC0_STATUS = MISCREG_MC_STATUS_BASE, @@ -190,6 +208,9 @@ namespace X86ISA MISCREG_MC2_STATUS, MISCREG_MC3_STATUS, MISCREG_MC4_STATUS, + MISCREG_MC5_STATUS, + MISCREG_MC6_STATUS, + MISCREG_MC7_STATUS, MISCREG_MC_ADDR_BASE, MISCREG_MC0_ADDR = MISCREG_MC_ADDR_BASE, @@ -197,6 +218,9 @@ namespace X86ISA MISCREG_MC2_ADDR, MISCREG_MC3_ADDR, MISCREG_MC4_ADDR, + MISCREG_MC5_ADDR, + MISCREG_MC6_ADDR, + MISCREG_MC7_ADDR, MISCREG_MC_MISC_BASE, MISCREG_MC0_MISC = MISCREG_MC_MISC_BASE, @@ -204,6 +228,9 @@ namespace X86ISA MISCREG_MC2_MISC, MISCREG_MC3_MISC, MISCREG_MC4_MISC, + MISCREG_MC5_MISC, + MISCREG_MC6_MISC, + MISCREG_MC7_MISC, // Extended feature enable register MISCREG_EFER, @@ -341,38 +368,6 @@ namespace X86ISA MISCREG_APIC_BASE, - MISCREG_APIC_START, - MISCREG_APIC_ID = MISCREG_APIC_START, - MISCREG_APIC_VERSION, - MISCREG_APIC_TASK_PRIORITY, - MISCREG_APIC_ARBITRATION_PRIORITY, - MISCREG_APIC_PROCESSOR_PRIORITY, - MISCREG_APIC_EOI, - MISCREG_APIC_LOGICAL_DESTINATION, - MISCREG_APIC_DESTINATION_FORMAT, - MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR, - - MISCREG_APIC_IN_SERVICE_BASE, - - MISCREG_APIC_TRIGGER_MODE_BASE = MISCREG_APIC_IN_SERVICE_BASE + 16, - - MISCREG_APIC_INTERRUPT_REQUEST_BASE = - MISCREG_APIC_TRIGGER_MODE_BASE + 16, - - MISCREG_APIC_ERROR_STATUS = MISCREG_APIC_INTERRUPT_REQUEST_BASE + 16, - MISCREG_APIC_INTERRUPT_COMMAND_LOW, - MISCREG_APIC_INTERRUPT_COMMAND_HIGH, - MISCREG_APIC_LVT_TIMER, - MISCREG_APIC_LVT_THERMAL_SENSOR, - MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS, - MISCREG_APIC_LVT_LINT0, - MISCREG_APIC_LVT_LINT1, - MISCREG_APIC_LVT_ERROR, - MISCREG_APIC_INITIAL_COUNT, - MISCREG_APIC_CURRENT_COUNT, - MISCREG_APIC_DIVIDE_COUNT, - MISCREG_APIC_END = MISCREG_APIC_DIVIDE_COUNT, - // "Fake" MSRs for internally implemented devices MISCREG_PCI_CONFIG_ADDRESS, @@ -481,24 +476,6 @@ namespace X86ISA return (MiscRegIndex)(MISCREG_SEG_ATTR_BASE + index); } - static inline MiscRegIndex - MISCREG_APIC_IN_SERVICE(int index) - { - return (MiscRegIndex)(MISCREG_APIC_IN_SERVICE_BASE + index); - } - - static inline MiscRegIndex - MISCREG_APIC_TRIGGER_MODE(int index) - { - return (MiscRegIndex)(MISCREG_APIC_TRIGGER_MODE_BASE + index); - } - - static inline MiscRegIndex - MISCREG_APIC_INTERRUPT_REQUEST(int index) - { - return (MiscRegIndex)(MISCREG_APIC_INTERRUPT_REQUEST_BASE + index); - } - /** * A type to describe the condition code bits of the RFLAGS register, * plus two flags, EZF and ECF, which are only visible to microcode. @@ -537,6 +514,12 @@ namespace X86ISA Bitfield<0> cf; // Carry Flag EndBitUnion(RFLAGS) + BitUnion64(HandyM5Reg) + Bitfield<0> mode; + Bitfield<3, 1> submode; + Bitfield<5, 4> cpl; + EndBitUnion(HandyM5Reg) + /** * Control registers */ @@ -589,6 +572,38 @@ namespace X86ISA Bitfield<3, 0> tpr; // Task Priority Register EndBitUnion(CR8) + BitUnion64(DR6) + Bitfield<0> b0; + Bitfield<1> b1; + Bitfield<2> b2; + Bitfield<3> b3; + Bitfield<13> bd; + Bitfield<14> bs; + Bitfield<15> bt; + EndBitUnion(DR6) + + BitUnion64(DR7) + Bitfield<0> l0; + Bitfield<1> g0; + Bitfield<2> l1; + Bitfield<3> g1; + Bitfield<4> l2; + Bitfield<5> g2; + Bitfield<6> l3; + Bitfield<7> g3; + Bitfield<8> le; + Bitfield<9> ge; + Bitfield<13> gd; + Bitfield<17, 16> rw0; + Bitfield<19, 18> len0; + Bitfield<21, 20> rw1; + Bitfield<23, 22> len1; + Bitfield<25, 24> rw2; + Bitfield<27, 26> len2; + Bitfield<29, 28> rw3; + Bitfield<31, 30> len3; + EndBitUnion(DR7) + // MTRR capabilities BitUnion64(MTRRcap) Bitfield<7, 0> vcnt; // Variable-Range Register Count diff --git a/src/arch/x86/mmaped_ipr.hh b/src/arch/x86/mmaped_ipr.hh index eda85c084..7056c0902 100644 --- a/src/arch/x86/mmaped_ipr.hh +++ b/src/arch/x86/mmaped_ipr.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -78,15 +78,12 @@ namespace X86ISA #if !FULL_SYSTEM panic("Shouldn't have a memory mapped register in SE\n"); #else + Addr offset = pkt->getAddr() & mask(3); MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); - if (index == MISCREG_PCI_CONFIG_ADDRESS || - (index >= MISCREG_APIC_START && - index <= MISCREG_APIC_END)) { - pkt->set((uint32_t)(xc->readMiscReg(pkt->getAddr() / - sizeof(MiscReg)))); - } else { - pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg))); - } + MiscReg data = htog(xc->readMiscReg(index)); + // Make sure we don't trot off the end of data. + assert(offset + pkt->getSize() <= sizeof(MiscReg)); + pkt->setData(((uint8_t *)&data) + offset); #endif return xc->getCpuPtr()->ticks(1); } @@ -97,15 +94,14 @@ namespace X86ISA #if !FULL_SYSTEM panic("Shouldn't have a memory mapped register in SE\n"); #else + Addr offset = pkt->getAddr() & mask(3); MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); - if (index == MISCREG_PCI_CONFIG_ADDRESS || - (index >= MISCREG_APIC_START && - index <= MISCREG_APIC_END)) { - xc->setMiscReg(index, gtoh(pkt->get<uint32_t>())); - } else { - xc->setMiscReg(pkt->getAddr() / sizeof(MiscReg), - gtoh(pkt->get<uint64_t>())); - } + MiscReg data; + data = htog(xc->readMiscRegNoEffect(index)); + // Make sure we don't trot off the end of data. + assert(offset + pkt->getSize() <= sizeof(MiscReg)); + pkt->writeData(((uint8_t *)&data) + offset); + xc->setMiscReg(index, gtoh(data)); #endif return xc->getCpuPtr()->ticks(1); } diff --git a/src/arch/x86/pagetable.hh b/src/arch/x86/pagetable.hh index e42693c03..1a7a945e4 100644 --- a/src/arch/x86/pagetable.hh +++ b/src/arch/x86/pagetable.hh @@ -113,6 +113,12 @@ namespace X86ISA TlbEntry(Addr asn, Addr _vaddr, Addr _paddr); TlbEntry() {} + void + updateVaddr(Addr new_vaddr) + { + vaddr = new_vaddr; + } + Addr pageStart() { return paddr; diff --git a/src/arch/x86/pagetable_walker.cc b/src/arch/x86/pagetable_walker.cc index e70c16b1d..f625cf4bd 100644 --- a/src/arch/x86/pagetable_walker.cc +++ b/src/arch/x86/pagetable_walker.cc @@ -84,8 +84,8 @@ BitUnion64(PageTableEntry) Bitfield<0> p; EndBitUnion(PageTableEntry) -void -Walker::doNext(PacketPtr &read, PacketPtr &write) +Fault +Walker::doNext(PacketPtr &write) { assert(state != Ready && state != Waiting); write = NULL; @@ -101,39 +101,45 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) bool badNX = pte.nx && (!tlb->allowNX() || !enableNX); switch(state) { case LongPML4: + DPRINTF(PageTableWalker, + "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size; doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (badNX) - panic("NX violation!\n"); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.noExec = pte.nx; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); nextState = LongPDP; break; case LongPDP: + DPRINTF(PageTableWalker, + "Got long mode PDP entry %#016x.\n", (uint64_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size; doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } nextState = LongPD; break; case LongPD: + DPRINTF(PageTableWalker, + "Got long mode PD entry %#016x.\n", (uint64_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -150,47 +156,49 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case LongPTE: + DPRINTF(PageTableWalker, + "Got long mode PTE entry %#016x.\n", (uint64_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(40) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; case PAEPDP: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } nextState = PAEPD; break; case PAEPD: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -206,39 +214,39 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case PAEPTE: + DPRINTF(PageTableWalker, + "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = entry.writable && pte.w; entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (badNX || !pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(40) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 7); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; case PSEPD: + DPRINTF(PageTableWalker, + "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } if (!pte.ps) { // 4 KB page entry.size = 4 * (1 << 10); @@ -255,54 +263,51 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) entry.patBit = bits(pte, 12); entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; } case PD: + DPRINTF(PageTableWalker, + "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } // 4 KB page entry.size = 4 * (1 << 10); nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; nextState = PTE; break; - nextState = PTE; - break; case PTE: + DPRINTF(PageTableWalker, + "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); doWrite = !pte.a; pte.a = 1; entry.writable = pte.w; entry.user = pte.u; - if (!pte.p) - panic("Page at %#x not present!\n", entry.vaddr); + if (!pte.p) { + stop(); + return pageFault(pte.p); + } entry.paddr = (uint64_t)pte & (mask(20) << 12); entry.uncacheable = uncacheable; entry.global = pte.g; entry.patBit = bits(pte, 7); entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); tlb->insert(entry.vaddr, entry); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; + stop(); + return NoFault; default: panic("Unknown page table walker state %d!\n"); } PacketPtr oldRead = read; //If we didn't return, we're setting up another read. - uint32_t flags = oldRead->req->getFlags(); - if (uncacheable) - flags |= UNCACHEABLE; - else - flags &= ~UNCACHEABLE; + Request::Flags flags = oldRead->req->getFlags(); + flags.set(Request::UNCACHEABLE, uncacheable); RequestPtr request = new Request(nextRead, oldRead->getSize(), flags); read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); @@ -319,14 +324,20 @@ Walker::doNext(PacketPtr &read, PacketPtr &write) delete oldRead->req; delete oldRead; } + return NoFault; } -void -Walker::start(ThreadContext * _tc, Addr vaddr) +Fault +Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, + RequestPtr _req, bool _write, bool _execute) { assert(state == Ready); - assert(!tc); tc = _tc; + req = _req; + Addr vaddr = req->getVaddr(); + execute = _execute; + write = _write; + translation = _translation; VAddr addr = vaddr; @@ -340,6 +351,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do long mode. state = LongPML4; top = (cr3.longPdtb << 12) + addr.longl4 * size; + enableNX = efer.nxe; } else { // We're in some flavor of legacy mode. CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); @@ -347,6 +359,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do legacy PAE. state = PAEPDP; top = (cr3.paePdtb << 5) + addr.pael3 * size; + enableNX = efer.nxe; } else { size = 4; top = (cr3.pdtb << 12) + addr.norml2 * size; @@ -357,38 +370,44 @@ Walker::start(ThreadContext * _tc, Addr vaddr) // Do legacy non PSE. state = PD; } + enableNX = false; } } nextState = Ready; entry.vaddr = vaddr; - enableNX = efer.nxe; - - RequestPtr request = - new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0); + Request::Flags flags = Request::PHYSICAL; + if (cr3.pcd) + flags.set(Request::UNCACHEABLE); + RequestPtr request = new Request(top, size, flags); read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); read->allocate(); Enums::MemoryMode memMode = sys->getMemoryMode(); if (memMode == Enums::timing) { - tc->suspend(); - port.sendTiming(read); + nextState = state; + state = Waiting; + timingFault = NoFault; + sendPackets(); } else if (memMode == Enums::atomic) { + Fault fault; do { port.sendAtomic(read); PacketPtr write = NULL; - doNext(read, write); + fault = doNext(write); + assert(fault == NoFault || read == NULL); state = nextState; nextState = Ready; if (write) port.sendAtomic(write); } while(read); - tc = NULL; state = Ready; nextState = Waiting; + return fault; } else { panic("Unrecognized memory system mode.\n"); } + return NoFault; } bool @@ -400,18 +419,19 @@ Walker::WalkerPort::recvTiming(PacketPtr pkt) bool Walker::recvTiming(PacketPtr pkt) { - inflight--; if (pkt->isResponse() && !pkt->wasNacked()) { + assert(inflight); + assert(state == Waiting); + assert(!read); + inflight--; if (pkt->isRead()) { - assert(inflight); - assert(state == Waiting); - assert(!read); state = nextState; nextState = Ready; PacketPtr write = NULL; - doNext(pkt, write); - state = Waiting; read = pkt; + timingFault = doNext(write); + state = Waiting; + assert(timingFault == NoFault || read == NULL); if (write) { writes.push_back(write); } @@ -420,14 +440,31 @@ Walker::recvTiming(PacketPtr pkt) sendPackets(); } if (inflight == 0 && read == NULL && writes.size() == 0) { - tc->activate(0); - tc = NULL; state = Ready; nextState = Waiting; + if (timingFault == NoFault) { + /* + * Finish the translation. Now that we now the right entry is + * in the TLB, this should work with no memory accesses. + * There could be new faults unrelated to the table walk like + * permissions violations, so we'll need the return value as + * well. + */ + bool delayedResponse; + Fault fault = tlb->translate(req, tc, NULL, write, execute, + delayedResponse, true); + assert(!delayedResponse); + // Let the CPU continue. + translation->finish(fault, req, tc, write); + } else { + // There was a fault during the walk. Let the CPU know. + translation->finish(timingFault, req, tc, write); + } } } else if (pkt->wasNacked()) { pkt->reinitNacked(); if (!port.sendTiming(pkt)) { + inflight--; retrying = true; if (pkt->isWrite()) { writes.push_back(pkt); @@ -435,8 +472,6 @@ Walker::recvTiming(PacketPtr pkt) assert(!read); read = pkt; } - } else { - inflight++; } } return true; @@ -490,27 +525,26 @@ Walker::sendPackets() //Reads always have priority if (read) { - if (!port.sendTiming(read)) { + PacketPtr pkt = read; + read = NULL; + inflight++; + if (!port.sendTiming(pkt)) { retrying = true; + read = pkt; + inflight--; return; - } else { - inflight++; - delete read->req; - delete read; - read = NULL; } } //Send off as many of the writes as we can. while (writes.size()) { PacketPtr write = writes.back(); + writes.pop_back(); + inflight++; if (!port.sendTiming(write)) { retrying = true; + writes.push_back(write); + inflight--; return; - } else { - inflight++; - delete write->req; - delete write; - writes.pop_back(); } } } @@ -524,6 +558,15 @@ Walker::getPort(const std::string &if_name, int idx) panic("No page table walker port named %s!\n", if_name); } +Fault +Walker::pageFault(bool present) +{ + DPRINTF(PageTableWalker, "Raising page fault.\n"); + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + return new PageFault(entry.vaddr, present, write, + m5reg.cpl == 3, false, execute && enableNX); +} + } X86ISA::Walker * diff --git a/src/arch/x86/pagetable_walker.hh b/src/arch/x86/pagetable_walker.hh index 324f16f3c..f73774a45 100644 --- a/src/arch/x86/pagetable_walker.hh +++ b/src/arch/x86/pagetable_walker.hh @@ -85,17 +85,28 @@ namespace X86ISA PSEPD, PD, PTE }; - // Act on the current state and determine what to do next. read - // should be the packet that just came back from a read and write + // Act on the current state and determine what to do next. The global + // read should be the packet that just came back from a read and write // should be NULL. When the function returns, read is either NULL // if the machine is finished, or points to a packet to initiate // the next read. If any write is required to update an "accessed" // bit, write will point to a packet to do the write. Otherwise it - // will be NULL. - void doNext(PacketPtr &read, PacketPtr &write); + // will be NULL. The return value is whatever fault was incurred + // during this stage of the lookup. + Fault doNext(PacketPtr &write); // Kick off the state machine. - void start(ThreadContext * _tc, Addr vaddr); + Fault start(ThreadContext * _tc, BaseTLB::Translation *translation, + RequestPtr req, bool write, bool execute); + // Clean up after the state machine. + void + stop() + { + nextState = Ready; + delete read->req; + delete read; + read = NULL; + } protected: @@ -111,6 +122,11 @@ namespace X86ISA bool retrying; /* + * The fault, if any, that's waiting to be delivered in timing mode. + */ + Fault timingFault; + + /* * Functions for dealing with packets. */ bool recvTiming(PacketPtr pkt); @@ -156,16 +172,21 @@ namespace X86ISA // The TLB we're supposed to load. TLB * tlb; System * sys; + BaseTLB::Translation * translation; /* * State machine state. */ ThreadContext * tc; + RequestPtr req; State state; State nextState; int size; bool enableNX; + bool write, execute, user; TlbEntry entry; + + Fault pageFault(bool present); public: diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc index 407a09ec0..620ab89ea 100644 --- a/src/arch/x86/predecoder.cc +++ b/src/arch/x86/predecoder.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -55,9 +55,11 @@ * Authors: Gabe Black */ +#include "arch/x86/miscregs.hh" #include "arch/x86/predecoder.hh" #include "base/misc.hh" #include "base/trace.hh" +#include "cpu/thread_context.hh" #include "sim/host.hh" namespace X86ISA @@ -78,7 +80,9 @@ namespace X86ISA emi.modRM = 0; emi.sib = 0; - emi.mode = 0; + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + emi.mode.mode = m5reg.mode; + emi.mode.submode = m5reg.submode; } void Predecoder::process() @@ -132,7 +136,10 @@ namespace X86ISA { uint8_t prefix = Prefixes[nextByte]; State nextState = PrefixState; - if(prefix) + // REX prefixes are only recognized in 64 bit mode. + if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode) + prefix = 0; + if (prefix) consumeByte(); switch(prefix) { @@ -209,10 +216,12 @@ namespace X86ISA DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte); emi.opcode.op = nextByte; + SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR); + //Figure out the effective operand size. This can be overriden to //a fixed value at the decoder level. int logOpSize; - if(/*FIXME long mode*/1) + if (emi.mode.submode == SixtyFourBitMode) { if(emi.rex.w) logOpSize = 3; // 64 bit operand size @@ -221,7 +230,7 @@ namespace X86ISA else logOpSize = 2; // 32 bit operand size } - else if(/*FIXME default 32*/1) + else if(csAttr.defaultSize) { if(emi.legacy.op) logOpSize = 1; // 16 bit operand size @@ -242,14 +251,14 @@ namespace X86ISA //Figure out the effective address size. This can be overriden to //a fixed value at the decoder level. int logAddrSize; - if(/*FIXME 64-bit mode*/1) + if(emi.mode.submode == SixtyFourBitMode) { if(emi.legacy.addr) logAddrSize = 2; // 32 bit address size else logAddrSize = 3; // 64 bit address size } - else if(/*FIXME default 32*/1) + else if(csAttr.defaultSize) { if(emi.legacy.addr) logAddrSize = 1; // 16 bit address size @@ -264,6 +273,16 @@ namespace X86ISA logAddrSize = 1; // 16 bit address size } + SegAttr ssAttr = tc->readMiscRegNoEffect(MISCREG_SS_ATTR); + //Figure out the effective stack width. This can be overriden to + //a fixed value at the decoder level. + if(emi.mode.submode == SixtyFourBitMode) + emi.stackSize = 8; // 64 bit stack width + else if(ssAttr.defaultSize) + emi.stackSize = 4; // 32 bit stack width + else + emi.stackSize = 2; // 16 bit stack width + //Set the actual address size emi.addrSize = 1 << logAddrSize; @@ -299,19 +318,21 @@ namespace X86ISA ModRM modRM; modRM = nextByte; DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte); - if (0) {//FIXME in 16 bit mode + SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR); + if (emi.mode.submode != SixtyFourBitMode && + !csAttr.defaultSize) { //figure out 16 bit displacement size - if(modRM.mod == 0 && modRM.rm == 6 || modRM.mod == 2) + if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2) displacementSize = 2; - else if(modRM.mod == 1) + else if (modRM.mod == 1) displacementSize = 1; else displacementSize = 0; } else { //figure out 32/64 bit displacement size - if(modRM.mod == 0 && modRM.rm == 5 || modRM.mod == 2) + if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2) displacementSize = 4; - else if(modRM.mod == 1) + else if (modRM.mod == 1) displacementSize = 1; else displacementSize = 0; diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index 6e41e8134..a16ce6fb8 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -58,6 +58,8 @@ #ifndef __ARCH_X86_PREDECODER_HH__ #define __ARCH_X86_PREDECODER_HH__ +#include <cassert> + #include "arch/x86/types.hh" #include "base/bitfield.hh" #include "base/misc.hh" diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/predecoder_tables.cc index a8c719054..5f2b5c421 100644 --- a/src/arch/x86/predecoder_tables.cc +++ b/src/arch/x86/predecoder_tables.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -123,7 +123,7 @@ namespace X86ISA { //LSB // MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F /* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1, -/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, /* 2 */ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, /* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, /* 4 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, @@ -201,7 +201,7 @@ namespace X86ISA //For two byte instructions { //LSB // MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F -/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 0 */ 0 , 0 , 0 , 0 , WO, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , BY , /* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* 2 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 76f0b5d04..4a61ed168 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -98,56 +98,115 @@ #include "mem/page_table.hh" #include "mem/translating_port.hh" #include "sim/process_impl.hh" +#include "sim/syscall_emul.hh" #include "sim/system.hh" using namespace std; using namespace X86ISA; -M5_64_auxv_t::M5_64_auxv_t(int64_t type, int64_t val) -{ - a_type = TheISA::htog(type); - a_val = TheISA::htog(val); -} - -X86LiveProcess::X86LiveProcess(LiveProcessParams * params, - ObjectFile *objFile) - : LiveProcess(params, objFile) +static const int ReturnValueReg = INTREG_RAX; +static const int ArgumentReg[] = { + INTREG_RDI, + INTREG_RSI, + INTREG_RDX, + //This argument register is r10 for syscalls and rcx for C. + INTREG_R10W, + //INTREG_RCX, + INTREG_R8W, + INTREG_R9W +}; +static const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int); +static const int ArgumentReg32[] = { + INTREG_EBX, + INTREG_ECX, + INTREG_EDX, + INTREG_ESI, + INTREG_EDI, +}; +static const int NumArgumentRegs32 = sizeof(ArgumentReg) / sizeof(const int); + +X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs) : + LiveProcess(params, objFile), syscallDescs(_syscallDescs), + numSyscallDescs(_numSyscallDescs) { brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); brk_point = roundUp(brk_point, VMPageSize); +} - // Set pointer for next thread stack. Reserve 8M for main stack. - next_thread_stack_base = stack_base - (8 * 1024 * 1024); - +X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params, + ObjectFile *objFile, SyscallDesc *_syscallDescs, + int _numSyscallDescs) : + X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs) +{ // Set up stack. On X86_64 Linux, stack goes from the top of memory // downward, less the hole for the kernel address space plus one page // for undertermined purposes. stack_base = (Addr)0x7FFFFFFFF000ULL; + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + // Set up region for mmaps. This was determined empirically and may not // always be correct. mmap_start = mmap_end = (Addr)0x2aaaaaaab000ULL; } -void X86LiveProcess::handleTrap(int trapNum, ThreadContext *tc) +void +I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc) { - switch(trapNum) - { - default: - panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum); + Addr eip = tc->readPC(); + if (eip >= vsyscallPage.base && + eip < vsyscallPage.base + vsyscallPage.size) { + tc->setNextPC(vsyscallPage.base + vsyscallPage.vsysexitOffset); } + X86LiveProcess::syscall(callnum, tc); +} + + +I386LiveProcess::I386LiveProcess(LiveProcessParams *params, + ObjectFile *objFile, SyscallDesc *_syscallDescs, + int _numSyscallDescs) : + X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs) +{ + _gdtStart = 0x100000000; + _gdtSize = VMPageSize; + + vsyscallPage.base = 0xffffe000ULL; + vsyscallPage.size = VMPageSize; + vsyscallPage.vsyscallOffset = 0x400; + vsyscallPage.vsysexitOffset = 0x410; + + stack_base = vsyscallPage.base; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + + // Set up region for mmaps. This was determined empirically and may not + // always be correct. + mmap_start = mmap_end = (Addr)0xf7ffd000ULL; +} + +SyscallDesc* +X86LiveProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum >= numSyscallDescs) + return NULL; + return &syscallDescs[callnum]; } void -X86LiveProcess::startup() +X86_64LiveProcess::startup() { + LiveProcess::startup(); + if (checkpointRestored) return; - argsInit(sizeof(IntReg), VMPageSize); + argsInit(sizeof(uint64_t), VMPageSize); - for (int i = 0; i < threadContexts.size(); i++) { - ThreadContext * tc = threadContexts[i]; + for (int i = 0; i < contextIds.size(); i++) { + ThreadContext * tc = system->getThreadContext(contextIds[i]); SegAttr dataAttr = 0; dataAttr.writable = 1; @@ -203,10 +262,122 @@ X86LiveProcess::startup() } void -X86LiveProcess::argsInit(int intSize, int pageSize) +I386LiveProcess::startup() +{ + LiveProcess::startup(); + + if (checkpointRestored) + return; + + argsInit(sizeof(uint32_t), VMPageSize); + + /* + * Set up a GDT for this process. The whole GDT wouldn't really be for + * this process, but the only parts we care about are. + */ + pTable->allocate(_gdtStart, _gdtSize); + uint64_t zero = 0; + assert(_gdtSize % sizeof(zero) == 0); + for (Addr gdtCurrent = _gdtStart; + gdtCurrent < _gdtStart + _gdtSize; gdtCurrent += sizeof(zero)) { + initVirtMem->write(gdtCurrent, zero); + } + + // Set up the vsyscall page for this process. + pTable->allocate(vsyscallPage.base, vsyscallPage.size); + uint8_t vsyscallBlob[] = { + 0x51, // push %ecx + 0x52, // push %edp + 0x55, // push %ebp + 0x89, 0xe5, // mov %esp, %ebp + 0x0f, 0x34 // sysenter + }; + initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsyscallOffset, + vsyscallBlob, sizeof(vsyscallBlob)); + + uint8_t vsysexitBlob[] = { + 0x5d, // pop %ebp + 0x5a, // pop %edx + 0x59, // pop %ecx + 0xc3 // ret + }; + initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsysexitOffset, + vsysexitBlob, sizeof(vsysexitBlob)); + + for (int i = 0; i < contextIds.size(); i++) { + ThreadContext * tc = system->getThreadContext(contextIds[i]); + + SegAttr dataAttr = 0; + dataAttr.writable = 1; + dataAttr.readable = 1; + dataAttr.expandDown = 0; + dataAttr.dpl = 3; + dataAttr.defaultSize = 1; + dataAttr.longMode = 0; + + //Initialize the segment registers. + for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) { + tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0); + tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0); + tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr); + tc->setMiscRegNoEffect(MISCREG_SEG_SEL(seg), 0xB); + tc->setMiscRegNoEffect(MISCREG_SEG_LIMIT(seg), (uint32_t)(-1)); + } + + SegAttr csAttr = 0; + csAttr.writable = 0; + csAttr.readable = 1; + csAttr.expandDown = 0; + csAttr.dpl = 3; + csAttr.defaultSize = 1; + csAttr.longMode = 0; + + tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr); + + tc->setMiscRegNoEffect(MISCREG_TSG_BASE, _gdtStart); + tc->setMiscRegNoEffect(MISCREG_TSG_EFF_BASE, _gdtStart); + tc->setMiscRegNoEffect(MISCREG_TSG_LIMIT, _gdtStart + _gdtSize - 1); + + // Set the LDT selector to 0 to deactivate it. + tc->setMiscRegNoEffect(MISCREG_TSL, 0); + + //Set up the registers that describe the operating mode. + CR0 cr0 = 0; + cr0.pg = 1; // Turn on paging. + cr0.cd = 0; // Don't disable caching. + cr0.nw = 0; // This is bit is defined to be ignored. + cr0.am = 0; // No alignment checking + cr0.wp = 0; // Supervisor mode can write read only pages + cr0.ne = 1; + cr0.et = 1; // This should always be 1 + cr0.ts = 0; // We don't do task switching, so causing fp exceptions + // would be pointless. + cr0.em = 0; // Allow x87 instructions to execute natively. + cr0.mp = 1; // This doesn't really matter, but the manual suggests + // setting it to one. + cr0.pe = 1; // We're definitely in protected mode. + tc->setMiscReg(MISCREG_CR0, cr0); + + Efer efer = 0; + efer.sce = 1; // Enable system call extensions. + efer.lme = 1; // Enable long mode. + efer.lma = 0; // Deactivate long mode. + efer.nxe = 1; // Enable nx support. + efer.svme = 0; // Disable svm support for now. It isn't implemented. + efer.ffxsr = 1; // Turn on fast fxsave and fxrstor. + tc->setMiscReg(MISCREG_EFER, efer); + } +} + +template<class IntType> +void +X86LiveProcess::argsInit(int pageSize, + std::vector<AuxVector<IntType> > extraAuxvs) { - typedef M5_64_auxv_t auxv_t; - Process::startup(); + int intSize = sizeof(IntType); + + typedef AuxVector<IntType> auxv_t; + std::vector<auxv_t> auxv = extraAuxvs; string filename; if(argv.size() < 1) @@ -399,35 +570,35 @@ X86LiveProcess::argsInit(int intSize, int pageSize) roundUp(stack_size, pageSize)); // map out initial stack contents - Addr sentry_base = stack_base - sentry_size; - Addr file_name_base = sentry_base - file_name_size; - Addr env_data_base = file_name_base - env_data_size; - Addr arg_data_base = env_data_base - arg_data_size; - Addr aux_data_base = arg_data_base - info_block_padding - aux_data_size; - Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding; - Addr envp_array_base = auxv_array_base - envp_array_size; - Addr argv_array_base = envp_array_base - argv_array_size; - Addr argc_base = argv_array_base - argc_size; - - DPRINTF(X86, "The addresses of items on the initial stack:\n"); - DPRINTF(X86, "0x%x - file name\n", file_name_base); - DPRINTF(X86, "0x%x - env data\n", env_data_base); - DPRINTF(X86, "0x%x - arg data\n", arg_data_base); - DPRINTF(X86, "0x%x - aux data\n", aux_data_base); - DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base); - DPRINTF(X86, "0x%x - envp array\n", envp_array_base); - DPRINTF(X86, "0x%x - argv array\n", argv_array_base); - DPRINTF(X86, "0x%x - argc \n", argc_base); - DPRINTF(X86, "0x%x - stack min\n", stack_min); + IntType sentry_base = stack_base - sentry_size; + IntType file_name_base = sentry_base - file_name_size; + IntType env_data_base = file_name_base - env_data_size; + IntType arg_data_base = env_data_base - arg_data_size; + IntType aux_data_base = arg_data_base - info_block_padding - aux_data_size; + IntType auxv_array_base = aux_data_base - aux_array_size - aux_padding; + IntType envp_array_base = auxv_array_base - envp_array_size; + IntType argv_array_base = envp_array_base - argv_array_size; + IntType argc_base = argv_array_base - argc_size; + + DPRINTF(Stack, "The addresses of items on the initial stack:\n"); + DPRINTF(Stack, "0x%x - file name\n", file_name_base); + DPRINTF(Stack, "0x%x - env data\n", env_data_base); + DPRINTF(Stack, "0x%x - arg data\n", arg_data_base); + DPRINTF(Stack, "0x%x - aux data\n", aux_data_base); + DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Stack, "0x%x - envp array\n", envp_array_base); + DPRINTF(Stack, "0x%x - argv array\n", argv_array_base); + DPRINTF(Stack, "0x%x - argc \n", argc_base); + DPRINTF(Stack, "0x%x - stack min\n", stack_min); // write contents to stack // figure out argc - uint64_t argc = argv.size(); - uint64_t guestArgc = TheISA::htog(argc); + IntType argc = argv.size(); + IntType guestArgc = X86ISA::htog(argc); //Write out the sentry void * - uint64_t sentry_NULL = 0; + IntType sentry_NULL = 0; initVirtMem->writeBlob(sentry_base, (uint8_t*)&sentry_NULL, sentry_size); @@ -458,17 +629,70 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + ThreadContext *tc = system->getThreadContext(contextIds[0]); //Set the stack pointer register - threadContexts[0]->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); // There doesn't need to be any segment base added in since we're dealing // with the flat segmentation model. - threadContexts[0]->setPC(prog_entry); - threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); //Align the "stack_min" to a page boundary. stack_min = roundDown(stack_min, pageSize); // num_processes++; } + +void +X86_64LiveProcess::argsInit(int intSize, int pageSize) +{ + std::vector<AuxVector<uint64_t> > extraAuxvs; + X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs); +} + +void +I386LiveProcess::argsInit(int intSize, int pageSize) +{ + std::vector<AuxVector<uint32_t> > extraAuxvs; + //Tell the binary where the vsyscall part of the vsyscall page is. + extraAuxvs.push_back(AuxVector<uint32_t>(0x20, + vsyscallPage.base + vsyscallPage.vsyscallOffset)); + extraAuxvs.push_back(AuxVector<uint32_t>(0x21, vsyscallPage.base)); + X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs); +} + +void +X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value) +{ + tc->setIntReg(INTREG_RAX, return_value.value()); +} + +X86ISA::IntReg +X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < NumArgumentRegs); + return tc->readIntReg(ArgumentReg[i]); +} + +void +X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) +{ + assert(i < NumArgumentRegs); + return tc->setIntReg(ArgumentReg[i], val); +} + +X86ISA::IntReg +I386LiveProcess::getSyscallArg(ThreadContext *tc, int i) +{ + assert(i < NumArgumentRegs32); + return tc->readIntReg(ArgumentReg32[i]); +} + +void +I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) +{ + assert(i < NumArgumentRegs); + return tc->setIntReg(ArgumentReg[i], val); +} diff --git a/src/arch/x86/process.hh b/src/arch/x86/process.hh index 5def9e13d..cd6d99e66 100644 --- a/src/arch/x86/process.hh +++ b/src/arch/x86/process.hh @@ -62,38 +62,76 @@ #include <vector> #include "sim/process.hh" +class SyscallDesc; + namespace X86ISA { - struct M5_64_auxv_t + + class X86LiveProcess : public LiveProcess { - int64_t a_type; - union { - int64_t a_val; - int64_t a_ptr; - int64_t a_fcn; - }; + protected: + Addr _gdtStart; + Addr _gdtSize; + + SyscallDesc *syscallDescs; + const int numSyscallDescs; - M5_64_auxv_t() - {} + X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); - M5_64_auxv_t(int64_t type, int64_t val); + template<class IntType> + void argsInit(int pageSize, + std::vector<AuxVector<IntType> > extraAuxvs); + + public: + Addr gdtStart() + { return _gdtStart; } + + Addr gdtSize() + { return _gdtSize; } + + SyscallDesc* getDesc(int callnum); + + void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value); }; - class X86LiveProcess : public LiveProcess + class X86_64LiveProcess : public X86LiveProcess { protected: - std::vector<M5_64_auxv_t> auxv; - - X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile); + X86_64LiveProcess(LiveProcessParams *params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); + public: + void argsInit(int intSize, int pageSize); void startup(); - public: + X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val); + }; - //Handles traps which request services from the operating system - virtual void handleTrap(int trapNum, ThreadContext *tc); + class I386LiveProcess : public X86LiveProcess + { + protected: + I386LiveProcess(LiveProcessParams *params, ObjectFile *objFile, + SyscallDesc *_syscallDescs, int _numSyscallDescs); + class VSyscallPage + { + public: + Addr base; + Addr size; + Addr vsyscallOffset; + Addr vsysexitOffset; + }; + VSyscallPage vsyscallPage; + + public: void argsInit(int intSize, int pageSize); + void startup(); + + void syscall(int64_t callnum, ThreadContext *tc); + X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i); + void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val); }; } diff --git a/src/arch/x86/regfile.cc b/src/arch/x86/regfile.cc index c27ab08ba..7d01c4bb4 100644 --- a/src/arch/x86/regfile.cc +++ b/src/arch/x86/regfile.cc @@ -135,23 +135,23 @@ void RegFile::clear() MiscReg RegFile::readMiscRegNoEffect(int miscReg) { - return miscRegFile.readRegNoEffect(miscReg); + return miscRegFile.readRegNoEffect((MiscRegIndex)miscReg); } MiscReg RegFile::readMiscReg(int miscReg, ThreadContext *tc) { - return miscRegFile.readReg(miscReg, tc); + return miscRegFile.readReg((MiscRegIndex)miscReg, tc); } void RegFile::setMiscRegNoEffect(int miscReg, const MiscReg &val) { - miscRegFile.setRegNoEffect(miscReg, val); + miscRegFile.setRegNoEffect((MiscRegIndex)miscReg, val); } void RegFile::setMiscReg(int miscReg, const MiscReg &val, ThreadContext * tc) { - miscRegFile.setReg(miscReg, val, tc); + miscRegFile.setReg((MiscRegIndex)miscReg, val, tc); } FloatReg RegFile::readFloatReg(int floatReg, int width) @@ -214,7 +214,7 @@ int X86ISA::flattenIntIndex(ThreadContext * tc, int reg) //If we need to fold over the index to match byte semantics, do that. //Otherwise, just strip off any extra bits and pass it through. if (reg & (1 << 6)) - return (reg & ~(1 << 6) - 0x4); + return (reg & (~(1 << 6) - 0x4)); else return (reg & ~(1 << 6)); } @@ -228,7 +228,8 @@ int X86ISA::flattenFloatIndex(ThreadContext * tc, int reg) return reg; } -void RegFile::serialize(std::ostream &os) +void +RegFile::serialize(EventManager *em, std::ostream &os) { intRegFile.serialize(os); floatRegFile.serialize(os); @@ -237,7 +238,8 @@ void RegFile::serialize(std::ostream &os) SERIALIZE_SCALAR(nextRip); } -void RegFile::unserialize(Checkpoint *cp, const std::string §ion) +void +RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) { intRegFile.unserialize(cp, section); floatRegFile.unserialize(cp, section); @@ -246,11 +248,6 @@ void RegFile::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(nextRip); } -void RegFile::changeContext(RegContextParam param, RegContextVal val) -{ - panic("changeContext not implemented for x86!\n"); -} - void X86ISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) { panic("copyMiscRegs not implemented for x86!\n"); diff --git a/src/arch/x86/regfile.hh b/src/arch/x86/regfile.hh index 650181aca..8938ab0bc 100644 --- a/src/arch/x86/regfile.hh +++ b/src/arch/x86/regfile.hh @@ -68,6 +68,7 @@ #include <string> class Checkpoint; +class EventManager; namespace X86ISA { @@ -96,8 +97,6 @@ namespace X86ISA void clear(); - int FlattenIntIndex(int reg); - MiscReg readMiscRegNoEffect(int miscReg); MiscReg readMiscReg(int miscReg, ThreadContext *tc); @@ -139,12 +138,11 @@ namespace X86ISA void setIntReg(int intReg, const IntReg &val); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(EventManager *em, std::ostream &os); + void unserialize(EventManager *em, Checkpoint *cp, + const std::string §ion); public: - - void changeContext(RegContextParam param, RegContextVal val); }; int flattenIntIndex(ThreadContext * tc, int reg); diff --git a/src/arch/x86/remote_gdb.cc b/src/arch/x86/remote_gdb.cc index 5ab0ec3fb..c416042c8 100644 --- a/src/arch/x86/remote_gdb.cc +++ b/src/arch/x86/remote_gdb.cc @@ -57,7 +57,7 @@ /* * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and @@ -65,8 +65,8 @@ * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -78,8 +78,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -96,7 +96,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 */ /*- @@ -116,8 +116,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -157,7 +157,7 @@ #include "cpu/thread_context.hh" using namespace std; -using namespace TheISA; +using namespace X86ISA; RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) : BaseRemoteGDB(_system, c, NumGDBRegs) diff --git a/src/arch/x86/stacktrace.cc b/src/arch/x86/stacktrace.cc index 300e8dcd0..87767583b 100644 --- a/src/arch/x86/stacktrace.cc +++ b/src/arch/x86/stacktrace.cc @@ -70,8 +70,6 @@ namespace X86ISA if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) panic("thread info not compiled into kernel\n"); name_off = vp->readGtoH<int32_t>(addr); - - tc->delVirtPort(vp); } Addr @@ -87,7 +85,6 @@ namespace X86ISA vp = tc->getVirtPort(); tsk = vp->readGtoH<Addr>(base + task_off); - tc->delVirtPort(vp); return tsk; } @@ -105,7 +102,6 @@ namespace X86ISA vp = tc->getVirtPort(); pd = vp->readGtoH<uint16_t>(task + pid_off); - tc->delVirtPort(vp); return pd; } diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc index 947a7793e..ed3dae4e6 100644 --- a/src/arch/x86/system.cc +++ b/src/arch/x86/system.cc @@ -55,13 +55,15 @@ * Authors: Gabe Black */ +#include "arch/x86/bios/smbios.hh" +#include "arch/x86/bios/intelmp.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/system.hh" -#include "arch/x86/smbios.hh" #include "arch/vtophys.hh" -#include "base/remote_gdb.hh" +#include "base/intmath.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" +#include "base/remote_gdb.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" #include "mem/physical.hh" @@ -72,14 +74,12 @@ using namespace LittleEndianGuest; using namespace X86ISA; -X86System::X86System(Params *p) - : System(p) -{ - smbiosTable = new X86ISA::SMBios::SMBiosTable; - smbiosTable->smbiosHeader.majorVersion = 2; - smbiosTable->smbiosHeader.minorVersion = 5; - smbiosTable->smbiosHeader.intermediateHeader.smbiosBCDRevision = 0x25; -} +X86System::X86System(Params *p) : + System(p), smbiosTable(p->smbios_table), + mpFloatingPointer(p->intel_mp_pointer), + mpConfigTable(p->intel_mp_table), + rsdp(p->acpi_description_table_pointer) +{} void X86System::startup() @@ -236,27 +236,67 @@ X86System::startup() // We should now be in long mode. Yay! + Addr ebdaPos = 0xF0000; + Addr fixed, table; + //Write out the SMBios/DMI table - writeOutSMBiosTable(0xF0000); + writeOutSMBiosTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); + ebdaPos = roundUp(ebdaPos, 16); + + //Write out the Intel MP Specification configuration table + writeOutMPTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); } void -X86System::writeOutSMBiosTable(Addr header, Addr table) +X86System::writeOutSMBiosTable(Addr header, + Addr &headerSize, Addr &structSize, Addr table) { // Get a port to write the table and header to memory. FunctionalPort * physPort = threadContexts[0]->getPhysPort(); // If the table location isn't specified, just put it after the header. // The header size as of the 2.5 SMBios specification is 0x1F bytes - if (!table) { - if (!smbiosTable->smbiosHeader.intermediateHeader.tableAddr) - smbiosTable->smbiosHeader. - intermediateHeader.tableAddr = header + 0x1F; - } else { - smbiosTable->smbiosHeader.intermediateHeader.tableAddr = table; + if (!table) + table = header + 0x1F; + smbiosTable->setTableAddr(table); + + smbiosTable->writeOut(physPort, header, headerSize, structSize); + + // Do some bounds checking to make sure we at least didn't step on + // ourselves. + assert(header > table || header + headerSize <= table); + assert(table > header || table + structSize <= header); +} + +void +X86System::writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table) +{ + // Get a port to write the table and header to memory. + FunctionalPort * physPort = threadContexts[0]->getPhysPort(); + + // If the table location isn't specified and it exists, just put + // it after the floating pointer. The fp size as of the 1.4 Intel MP + // specification is 0x10 bytes. + if (mpConfigTable) { + if (!table) + table = fp + 0x10; + mpFloatingPointer->setTableAddr(table); } - smbiosTable->writeOut(physPort, header); + fpSize = mpFloatingPointer->writeOut(physPort, fp); + if (mpConfigTable) + tableSize = mpConfigTable->writeOut(physPort, table); + else + tableSize = 0; + + // Do some bounds checking to make sure we at least didn't step on + // ourselves and the fp structure was the size we thought it was. + assert(fp > table || fp + fpSize <= table); + assert(table > fp || table + tableSize <= fp); + assert(fpSize == 0x10); } diff --git a/src/arch/x86/system.hh b/src/arch/x86/system.hh index 8a5483ebf..12a471f6f 100644 --- a/src/arch/x86/system.hh +++ b/src/arch/x86/system.hh @@ -74,6 +74,11 @@ namespace X86ISA { class SMBiosTable; } + namespace IntelMP + { + class FloatingPointer; + class ConfigTable; + } } class X86System : public System @@ -95,8 +100,15 @@ class X86System : public System protected: X86ISA::SMBios::SMBiosTable * smbiosTable; + X86ISA::IntelMP::FloatingPointer * mpFloatingPointer; + X86ISA::IntelMP::ConfigTable * mpConfigTable; + X86ISA::ACPI::RSDP * rsdp; + + void writeOutSMBiosTable(Addr header, + Addr &headerSize, Addr &tableSize, Addr table = 0); - void writeOutSMBiosTable(Addr header, Addr table = 0); + void writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table = 0); const Params *params() const { return (const Params *)_params; } diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index a87abf212..3fec4c7da 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2007-2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use of this software in source and binary forms, @@ -59,6 +59,7 @@ #include "config/full_system.hh" +#include "arch/x86/insts/microldstop.hh" #include "arch/x86/pagetable.hh" #include "arch/x86/tlb.hh" #include "arch/x86/x86_traits.hh" @@ -72,6 +73,9 @@ #if FULL_SYSTEM #include "arch/x86/pagetable_walker.hh" +#else +#include "mem/page_table.hh" +#include "sim/process.hh" #endif namespace X86ISA { @@ -90,7 +94,7 @@ TLB::TLB(const Params *p) : BaseTLB(p), configAddress(0), size(p->size) #endif } -void +TlbEntry * TLB::insert(Addr vpn, TlbEntry &entry) { //TODO Deal with conflicting entries @@ -106,6 +110,7 @@ TLB::insert(Addr vpn, TlbEntry &entry) *newEntry = entry; newEntry->vaddr = vpn; entryList.push_front(newEntry); + return newEntry; } TLB::EntryList::iterator @@ -138,14 +143,6 @@ TLB::lookup(Addr va, bool update_lru) return *entry; } -#if FULL_SYSTEM -void -TLB::walk(ThreadContext * _tc, Addr vaddr) -{ - walker->start(_tc, vaddr); -} -#endif - void TLB::invalidateAll() { @@ -188,16 +185,18 @@ TLB::demapPage(Addr va, uint64_t asn) } } -template<class TlbFault> Fault -TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) +TLB::translate(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write, bool execute, + bool &delayedResponse, bool timing) { + delayedResponse = false; Addr vaddr = req->getVaddr(); DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr); uint32_t flags = req->getFlags(); bool storeCheck = flags & StoreCheck; - int seg = flags & mask(4); + int seg = flags & SegmentFlagMask; //XXX Junk code to surpress the warning if (storeCheck); @@ -206,10 +205,11 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // value. if (seg == SEGMENT_REG_MS) { DPRINTF(TLB, "Addresses references internal memory.\n"); - Addr prefix = vaddr & IntAddrPrefixMask; + Addr prefix = (vaddr >> 3) & IntAddrPrefixMask; if (prefix == IntAddrPrefixCPUID) { panic("CPUID memory space not yet implemented!\n"); } else if (prefix == IntAddrPrefixMSR) { + vaddr = vaddr >> 3; req->setMmapedIpr(true); Addr regNum = 0; switch (vaddr & ~IntAddrPrefixMask) { @@ -357,6 +357,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x410: regNum = MISCREG_MC4_CTL; break; + case 0x414: + regNum = MISCREG_MC5_CTL; + break; + case 0x418: + regNum = MISCREG_MC6_CTL; + break; + case 0x41C: + regNum = MISCREG_MC7_CTL; + break; case 0x401: regNum = MISCREG_MC0_STATUS; break; @@ -372,6 +381,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x411: regNum = MISCREG_MC4_STATUS; break; + case 0x415: + regNum = MISCREG_MC5_STATUS; + break; + case 0x419: + regNum = MISCREG_MC6_STATUS; + break; + case 0x41D: + regNum = MISCREG_MC7_STATUS; + break; case 0x402: regNum = MISCREG_MC0_ADDR; break; @@ -387,6 +405,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x412: regNum = MISCREG_MC4_ADDR; break; + case 0x416: + regNum = MISCREG_MC5_ADDR; + break; + case 0x41A: + regNum = MISCREG_MC6_ADDR; + break; + case 0x41E: + regNum = MISCREG_MC7_ADDR; + break; case 0x403: regNum = MISCREG_MC0_MISC; break; @@ -402,6 +429,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x413: regNum = MISCREG_MC4_MISC; break; + case 0x417: + regNum = MISCREG_MC5_MISC; + break; + case 0x41B: + regNum = MISCREG_MC6_MISC; + break; + case 0x41F: + regNum = MISCREG_MC7_MISC; + break; case 0xC0000080: regNum = MISCREG_EFER; break; @@ -510,7 +546,8 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS); if (bits(configAddress, 31, 31)) { req->setPaddr(PhysAddrPrefixPciConfig | - bits(configAddress, 30, 0)); + mbits(configAddress, 30, 2) | + (IOPort & mask(2))); } } else { req->setPaddr(PhysAddrPrefixIO | IOPort); @@ -534,35 +571,38 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // If we're not in 64-bit mode, do protection/limit checks if (!efer.lma || !csAttr.longMode) { DPRINTF(TLB, "Not in long mode. Checking segment protection.\n"); - SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg)); - if (!attr.writable && write) - return new GeneralProtection(0); - if (!attr.readable && !write && !execute) + // Check for a NULL segment selector. + if (!tc->readMiscRegNoEffect(MISCREG_SEG_SEL(seg))) return new GeneralProtection(0); + bool expandDown = false; + SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg)); + if (seg >= SEGMENT_REG_ES && seg <= SEGMENT_REG_HS) { + if (!attr.writable && write) + return new GeneralProtection(0); + if (!attr.readable && !write && !execute) + return new GeneralProtection(0); + expandDown = attr.expandDown; + + } Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg)); Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg)); - if (!attr.expandDown) { + // This assumes we're not in 64 bit mode. If we were, the default + // address size is 64 bits, overridable to 32. + int size = 32; + bool sizeOverride = (flags & (AddrSizeFlagBit << FlagShift)); + if ((csAttr.defaultSize && sizeOverride) || + (!csAttr.defaultSize && !sizeOverride)) + size = 16; + Addr offset = bits(vaddr - base, size-1, 0); + Addr endOffset = offset + req->getSize() - 1; + if (expandDown) { DPRINTF(TLB, "Checking an expand down segment.\n"); - // We don't have to worry about the access going around the - // end of memory because accesses will be broken up into - // pieces at boundaries aligned on sizes smaller than an - // entire address space. We do have to worry about the limit - // being less than the base. - if (limit < base) { - if (limit < vaddr + req->getSize() && vaddr < base) - return new GeneralProtection(0); - } else { - if (limit < vaddr + req->getSize()) - return new GeneralProtection(0); - } + warn_once("Expand down segments are untested.\n"); + if (offset <= limit || endOffset <= limit) + return new GeneralProtection(0); } else { - if (limit < base) { - if (vaddr <= limit || vaddr + req->getSize() >= base) - return new GeneralProtection(0); - } else { - if (vaddr <= limit && vaddr + req->getSize() >= base) - return new GeneralProtection(0); - } + if (offset > limit || endOffset > limit) + return new GeneralProtection(0); } } // If paging is enabled, do the translation. @@ -571,14 +611,57 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) // The vaddr already has the segment base applied. TlbEntry *entry = lookup(vaddr); if (!entry) { - return new TlbFault(vaddr); - } else { - // Do paging protection checks. - DPRINTF(TLB, "Entry found with paddr %#x, doing protection checks.\n", entry->paddr); - Addr paddr = entry->paddr | (vaddr & (entry->size-1)); - DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr); - req->setPaddr(paddr); +#if FULL_SYSTEM + Fault fault = walker->start(tc, translation, req, + write, execute); + if (timing || fault != NoFault) { + // This gets ignored in atomic mode. + delayedResponse = true; + return fault; + } + entry = lookup(vaddr); + assert(entry); +#else + DPRINTF(TLB, "Handling a TLB miss for " + "address %#x at pc %#x.\n", + vaddr, tc->readPC()); + + Process *p = tc->getProcessPtr(); + TlbEntry newEntry; + bool success = p->pTable->lookup(vaddr, newEntry); + if(!success && !execute) { + p->checkAndAllocNextPage(vaddr); + success = p->pTable->lookup(vaddr, newEntry); + } + if(!success) { + panic("Tried to execute unmapped address %#x.\n", vaddr); + } else { + Addr alignedVaddr = p->pTable->pageAlign(vaddr); + DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, + newEntry.pageStart()); + entry = insert(alignedVaddr, newEntry); + } + DPRINTF(TLB, "Miss was serviced.\n"); +#endif } + // Do paging protection checks. + bool inUser = (csAttr.dpl == 3 && + !(flags & (CPL0FlagBit << FlagShift))); + if ((inUser && !entry->user) || + (write && !entry->writable)) { + // The page must have been present to get into the TLB in + // the first place. We'll assume the reserved bits are + // fine even though we're not checking them. + return new PageFault(vaddr, true, write, + inUser, false, execute); + } + + + DPRINTF(TLB, "Entry found with paddr %#x, " + "doing protection checks.\n", entry->paddr); + Addr paddr = entry->paddr | (vaddr & (entry->size-1)); + DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr); + req->setPaddr(paddr); } else { //Use the address which already has segmentation applied. DPRINTF(TLB, "Paging disabled.\n"); @@ -592,160 +675,68 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) req->setPaddr(vaddr); } // Check for an access to the local APIC +#if FULL_SYSTEM LocalApicBase localApicBase = tc->readMiscRegNoEffect(MISCREG_APIC_BASE); - Addr baseAddr = localApicBase.base << 12; + Addr baseAddr = localApicBase.base * PageBytes; Addr paddr = req->getPaddr(); - if (baseAddr <= paddr && baseAddr + (1 << 12) > paddr) { - req->setMmapedIpr(true); + if (baseAddr <= paddr && baseAddr + PageBytes > paddr) { + // The Intel developer's manuals say the below restrictions apply, + // but the linux kernel, because of a compiler optimization, breaks + // them. + /* // Check alignment if (paddr & ((32/8) - 1)) return new GeneralProtection(0); // Check access size if (req->getSize() != (32/8)) return new GeneralProtection(0); - MiscReg regNum; - switch (paddr - baseAddr) - { - case 0x20: - regNum = MISCREG_APIC_ID; - break; - case 0x30: - regNum = MISCREG_APIC_VERSION; - break; - case 0x80: - regNum = MISCREG_APIC_TASK_PRIORITY; - break; - case 0x90: - regNum = MISCREG_APIC_ARBITRATION_PRIORITY; - break; - case 0xA0: - regNum = MISCREG_APIC_PROCESSOR_PRIORITY; - break; - case 0xB0: - regNum = MISCREG_APIC_EOI; - break; - case 0xD0: - regNum = MISCREG_APIC_LOGICAL_DESTINATION; - break; - case 0xE0: - regNum = MISCREG_APIC_DESTINATION_FORMAT; - break; - case 0xF0: - regNum = MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR; - break; - case 0x100: - case 0x108: - case 0x110: - case 0x118: - case 0x120: - case 0x128: - case 0x130: - case 0x138: - case 0x140: - case 0x148: - case 0x150: - case 0x158: - case 0x160: - case 0x168: - case 0x170: - case 0x178: - regNum = MISCREG_APIC_IN_SERVICE( - (paddr - baseAddr - 0x100) / 0x8); - break; - case 0x180: - case 0x188: - case 0x190: - case 0x198: - case 0x1A0: - case 0x1A8: - case 0x1B0: - case 0x1B8: - case 0x1C0: - case 0x1C8: - case 0x1D0: - case 0x1D8: - case 0x1E0: - case 0x1E8: - case 0x1F0: - case 0x1F8: - regNum = MISCREG_APIC_TRIGGER_MODE( - (paddr - baseAddr - 0x180) / 0x8); - break; - case 0x200: - case 0x208: - case 0x210: - case 0x218: - case 0x220: - case 0x228: - case 0x230: - case 0x238: - case 0x240: - case 0x248: - case 0x250: - case 0x258: - case 0x260: - case 0x268: - case 0x270: - case 0x278: - regNum = MISCREG_APIC_INTERRUPT_REQUEST( - (paddr - baseAddr - 0x200) / 0x8); - break; - case 0x280: - regNum = MISCREG_APIC_ERROR_STATUS; - break; - case 0x300: - regNum = MISCREG_APIC_INTERRUPT_COMMAND_LOW; - break; - case 0x310: - regNum = MISCREG_APIC_INTERRUPT_COMMAND_HIGH; - break; - case 0x320: - regNum = MISCREG_APIC_LVT_TIMER; - break; - case 0x330: - regNum = MISCREG_APIC_LVT_THERMAL_SENSOR; - break; - case 0x340: - regNum = MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; - break; - case 0x350: - regNum = MISCREG_APIC_LVT_LINT0; - break; - case 0x360: - regNum = MISCREG_APIC_LVT_LINT1; - break; - case 0x370: - regNum = MISCREG_APIC_LVT_ERROR; - break; - case 0x380: - regNum = MISCREG_APIC_INITIAL_COUNT; - break; - case 0x390: - regNum = MISCREG_APIC_CURRENT_COUNT; - break; - case 0x3E0: - regNum = MISCREG_APIC_DIVIDE_COUNT; - break; - default: - // A reserved register field. - return new GeneralProtection(0); - break; - } - req->setPaddr(regNum * sizeof(MiscReg)); + */ + // Force the access to be uncacheable. + req->setFlags(Request::UNCACHEABLE); + req->setPaddr(x86LocalAPICAddress(tc->contextId(), paddr - baseAddr)); } +#endif return NoFault; }; Fault -DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) +{ + bool delayedResponse; + return TLB::translate(req, tc, NULL, write, + false, delayedResponse, false); +} + +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) { - return TLB::translate<FakeDTLBFault>(req, tc, write, false); + bool delayedResponse; + assert(translation); + Fault fault = TLB::translate(req, tc, translation, + write, false, delayedResponse, true); + if (!delayedResponse) + translation->finish(fault, req, tc, write); } Fault -ITB::translate(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) +{ + bool delayedResponse; + return TLB::translate(req, tc, NULL, false, + true, delayedResponse, false); +} + +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) { - return TLB::translate<FakeITLBFault>(req, tc, false, true); + bool delayedResponse; + assert(translation); + Fault fault = TLB::translate(req, tc, translation, + false, true, delayedResponse, true); + if (!delayedResponse) + translation->finish(fault, req, tc, false); } #if FULL_SYSTEM diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh index 89b965e97..2467bc472 100644 --- a/src/arch/x86/tlb.hh +++ b/src/arch/x86/tlb.hh @@ -87,8 +87,7 @@ namespace X86ISA class TLB : public BaseTLB { protected: - friend class FakeITLBFault; - friend class FakeDTLBFault; + friend class Walker; typedef std::list<TlbEntry *> EntryList; @@ -118,8 +117,6 @@ namespace X86ISA protected: Walker * walker; - - void walk(ThreadContext * _tc, Addr vaddr); #endif public: @@ -137,13 +134,13 @@ namespace X86ISA EntryList freeList; EntryList entryList; - template<class TlbFault> - Fault translate(RequestPtr &req, ThreadContext *tc, - bool write, bool execute); + Fault translate(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write, bool execute, + bool &delayedResponse, bool timing); public: - void insert(Addr vpn, TlbEntry &entry); + TlbEntry * insert(Addr vpn, TlbEntry &entry); // Checkpointing virtual void serialize(std::ostream &os); @@ -159,7 +156,9 @@ namespace X86ISA _allowNX = false; } - Fault translate(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); friend class DTB; }; @@ -172,7 +171,9 @@ namespace X86ISA { _allowNX = true; } - Fault translate(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); #if FULL_SYSTEM Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 90df38d13..29420352b 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -246,17 +246,6 @@ namespace X86ISA MiscReg ctrlReg; } AnyReg; - //XXX This is very hypothetical. X87 instructions would need to - //change their "context" constantly. It's also not clear how - //this would be handled as far as out of order execution. - //Maybe x87 instructions are in order? - enum RegContextParam - { - CONTEXT_X87_TOP - }; - - typedef int RegContextVal; - typedef uint16_t RegIndex; struct CoreSpecific { diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index 5fe5bf8c3..43a5ca1a9 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -55,11 +55,17 @@ * Authors: Gabe Black */ +#include "config/full_system.hh" + +#if FULL_SYSTEM +#include "arch/x86/interrupts.hh" +#endif #include "arch/x86/intregs.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/segmentregs.hh" #include "arch/x86/utility.hh" #include "arch/x86/x86_traits.hh" +#include "cpu/base.hh" #include "sim/system.hh" namespace X86ISA { @@ -254,9 +260,15 @@ void initCPU(ThreadContext *tc, int cpuId) lApicBase.bsp = (cpuId == 0); tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); - tc->setMiscRegNoEffect(MISCREG_APIC_ID, cpuId << 24); + Interrupts * interrupts = dynamic_cast<Interrupts *>( + tc->getCpuPtr()->getInterruptController()); + assert(interrupts); + + interrupts->setRegNoEffect(APIC_ID, cpuId << 24); - tc->setMiscRegNoEffect(MISCREG_APIC_VERSION, (5 << 16) | 0x14); + interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); + + interrupts->setClock(tc->getCpuPtr()->ticks(16)); // TODO Set the SMRAM base address (SMBASE) to 0x00030000 diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index 477a76e0b..6f0812a6a 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -93,7 +93,12 @@ namespace X86ISA static inline bool inUserMode(ThreadContext *tc) { - return false; +#if FULL_SYSTEM + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + return m5reg.cpl == 3; +#else + return true; +#endif } inline bool isCallerSaveIntegerRegister(unsigned int reg) { diff --git a/src/arch/x86/x86_traits.hh b/src/arch/x86/x86_traits.hh index d605ce218..0347a7099 100644 --- a/src/arch/x86/x86_traits.hh +++ b/src/arch/x86/x86_traits.hh @@ -55,11 +55,13 @@ * Authors: Gabe Black */ -#include "sim/host.hh" - #ifndef __ARCH_X86_X86TRAITS_HH__ #define __ARCH_X86_X86TRAITS_HH__ +#include <assert.h> + +#include "sim/host.hh" + namespace X86ISA { const int NumMicroIntRegs = 16; @@ -90,6 +92,37 @@ namespace X86ISA const Addr PhysAddrPrefixIO = ULL(0x8000000000000000); const Addr PhysAddrPrefixPciConfig = ULL(0xC000000000000000); + const Addr PhysAddrPrefixLocalAPIC = ULL(0x2000000000000000); + const Addr PhysAddrPrefixInterrupts = ULL(0xA000000000000000); + // Each APIC gets two pages. One page is used for local apics to field + // accesses from the CPU, and the other is for all APICs to communicate. + const Addr PhysAddrAPICRangeSize = 1 << 12; + + static inline Addr + x86IOAddress(const uint32_t port) + { + return PhysAddrPrefixIO | port; + } + + static inline Addr + x86PciConfigAddress(const uint32_t addr) + { + return PhysAddrPrefixPciConfig | addr; + } + + static inline Addr + x86LocalAPICAddress(const uint8_t id, const uint16_t addr) + { + assert(addr < (1 << 12)); + return PhysAddrPrefixLocalAPIC | (id * (1 << 12)) | addr; + } + + static inline Addr + x86InterruptAddress(const uint8_t id, const uint16_t addr) + { + assert(addr < PhysAddrAPICRangeSize); + return PhysAddrPrefixInterrupts | (id * PhysAddrAPICRangeSize) | addr; + } } #endif //__ARCH_X86_X86TRAITS_HH__ diff --git a/src/base/CPA.py b/src/base/CPA.py new file mode 100644 index 000000000..c0beaedef --- /dev/null +++ b/src/base/CPA.py @@ -0,0 +1,8 @@ +from m5.SimObject import SimObject +from m5.params import * + +class CPA(SimObject): + type = 'CPA' + + enabled = Param.Bool(False, "Is Annotation enabled?") + user_apps = VectorParam.String([], "List of apps to get symbols for") diff --git a/src/base/SConscript b/src/base/SConscript index f9d936d84..58c453184 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -30,11 +30,15 @@ Import('*') -Source('annotate.cc') +if env['CP_ANNOTATE']: + SimObject('CPA.py') + Source('cp_annotate.cc') +Source('atomicio.cc') Source('bigint.cc') Source('circlebuf.cc') Source('cprintf.cc') Source('crc.cc') +Source('debug.cc') Source('fast_alloc.cc') if env['USE_FENV']: Source('fenv.c') @@ -72,7 +76,6 @@ Source('loader/symtab.cc') Source('stats/events.cc') Source('stats/output.cc') -Source('stats/statdb.cc') Source('stats/text.cc') Source('stats/visit.cc') @@ -80,16 +83,23 @@ if env['USE_MYSQL']: Source('mysql.cc') Source('stats/mysql.cc') -TraceFlag('Annotate') -TraceFlag('GDBAcc') -TraceFlag('GDBExtra') -TraceFlag('GDBMisc') -TraceFlag('GDBRead') -TraceFlag('GDBRecv') -TraceFlag('GDBSend') -TraceFlag('GDBWrite') -TraceFlag('SQL') -TraceFlag('StatEvents') +TraceFlag('Annotate', "State machine annotation debugging") +TraceFlag('AnnotateQ', "State machine annotation queue debugging") +TraceFlag('AnnotateVerbose', "Dump all state machine annotation details") +TraceFlag('GDBAcc', "Remote debugger accesses") +TraceFlag('GDBExtra', "Dump extra information on reads and writes") +TraceFlag('GDBMisc', "Breakpoints, traps, watchpoints, etc.") +TraceFlag('GDBRead', "Reads to the remote address space") +TraceFlag('GDBRecv', "Messages received from the remote application") +TraceFlag('GDBSend', "Messages sent to the remote application") +TraceFlag('GDBWrite', "Writes to the remote address space") +TraceFlag('SQL', "SQL queries sent to the server") +TraceFlag('StatEvents', "Statistics event tracking") + +CompoundFlag('GDBAll', + [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', + 'GDBExtra' ], + desc="All Remote debugging flags") +CompoundFlag('AnnotateAll', ['Annotate', 'AnnotateQ', 'AnnotateVerbose'], + desc="All Annotation flags") -CompoundFlag('GDBAll', [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', - 'GDBRecv', 'GDBExtra' ]) diff --git a/src/base/annotate.cc b/src/base/annotate.cc deleted file mode 100644 index de7eeed51..000000000 --- a/src/base/annotate.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Ali Saidi - */ - -#include "base/annotate.hh" -#include "base/callback.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "sim/core.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" - - - -class AnnotateDumpCallback : public Callback -{ - public: - virtual void process(); -}; - -void -AnnotateDumpCallback::process() -{ - Annotate::annotations.dump(); -} - -namespace Annotate { - - -Annotate annotations; - -Annotate::Annotate() -{ - registerExitCallback(new AnnotateDumpCallback); -} - -void -Annotate::add(System *sys, Addr stack, uint32_t sm, uint32_t st, - uint32_t wm, uint32_t ws) -{ - AnnotateData *an; - - an = new AnnotateData; - an->time = curTick; - - std::map<System*, std::string>::iterator i = nameCache.find(sys); - if (i == nameCache.end()) { - nameCache[sys] = sys->name(); - } - - an->system = nameCache[sys]; - an->stack = stack; - an->stateMachine = sm; - an->curState = st; - an->waitMachine = wm; - an->waitState = ws; - - data.push_back(an); - if (an->waitMachine) - DPRINTF(Annotate, "Annotating: %s(%#llX) %d:%d waiting on %d:%d\n", - an->system, an->stack, an->stateMachine, an->curState, - an->waitMachine, an->waitState); - else - DPRINTF(Annotate, "Annotating: %s(%#llX) %d:%d beginning\n", an->system, - an->stack, an->stateMachine, an->curState); - - DPRINTF(Annotate, "Now %d events on list\n", data.size()); - -} - -void -Annotate::dump() -{ - - std::list<AnnotateData*>::iterator i; - - i = data.begin(); - - if (i == data.end()) - return; - - std::ostream *os = simout.create("annotate.dat"); - - AnnotateData *an; - - while (i != data.end()) { - DPRINTF(Annotate, "Writing\n", data.size()); - an = *i; - ccprintf(*os, "%d %s(%#llX) %d %d %d %d\n", an->time, an->system, - an->stack, an->stateMachine, an->curState, an->waitMachine, - an->waitState); - i++; - } -} - -} //namespace Annotate diff --git a/src/unittest/offtest.cc b/src/base/atomicio.cc index ebfb2515c..3f3e6d6f0 100644 --- a/src/unittest/offtest.cc +++ b/src/base/atomicio.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,45 +28,65 @@ * Authors: Nathan Binkert */ -#include <sys/types.h> -#include <stddef.h> -#include <stdio.h> -#include "dev/pcireg.h" +#include <cerrno> +#include <cstdio> -int -main() +#include "base/atomicio.hh" + +ssize_t +atomic_read(int fd, void *s, size_t n) +{ + char *p = reinterpret_cast<char *>(s); + ssize_t pos = 0; + + // Keep reading until we've gotten all of the data. + while (n > pos) { + ssize_t result = read(fd, p + pos, n - pos); + + // We didn't get any more data, so we should probably punt, + // otherwise we'd just keep spinning + if (result == 0) + break; + + // If there was an error, try again on EINTR/EAGAIN, pass the + // error up otherwise. + if (result == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + return result; + } + + pos += result; + } + + return pos; +} + +ssize_t +atomic_write(int fd, const void *s, size_t n) { -#define POFFSET(x) \ - printf("offsetof(PCIConfig, hdr."#x") = %d\n", \ - offsetof(PCIConfig, hdr.x)) + const char *p = reinterpret_cast<const char *>(s); + ssize_t pos = 0; + + // Keep writing until we've written all of the data + while (n > pos) { + ssize_t result = write(fd, p + pos, n - pos); + + // We didn't manage to write anything this time, so we should + // probably punt, otherwise we'd just keep spinning + if (result == 0) + break; + + // If there was an error, try again on EINTR/EAGAIN, pass the + // error up otherwise. + if (result == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + return result; + } - POFFSET(vendor); - POFFSET(device); - POFFSET(command); - POFFSET(status); - POFFSET(revision); - POFFSET(progIF); - POFFSET(subClassCode); - POFFSET(classCode); - POFFSET(cacheLineSize); - POFFSET(latencyTimer); - POFFSET(headerType); - POFFSET(bist); - POFFSET(pci0.baseAddr0); - POFFSET(pci0.baseAddr1); - POFFSET(pci0.baseAddr2); - POFFSET(pci0.baseAddr3); - POFFSET(pci0.baseAddr4); - POFFSET(pci0.baseAddr5); - POFFSET(pci0.cardbusCIS); - POFFSET(pci0.subsystemVendorID); - POFFSET(pci0.expansionROM); - POFFSET(pci0.reserved0); - POFFSET(pci0.reserved1); - POFFSET(pci0.interruptLine); - POFFSET(pci0.interruptPin); - POFFSET(pci0.minimumGrant); - POFFSET(pci0.minimumLatency); + pos += result; + } - return 0; + return pos; } diff --git a/src/base/atomicio.hh b/src/base/atomicio.hh new file mode 100644 index 000000000..5e703f315 --- /dev/null +++ b/src/base/atomicio.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_ATOMICIO_HH__ +#define __BASE_ATOMICIO_HH__ + +#include <unistd.h> + +// These functions keep reading/writing, if possible, until all data +// has been transferred. Basically, try again when there's no error, +// but there is data left also retry on EINTR. +// This function blocks until it is done. + +ssize_t atomic_read(int fd, void *s, size_t n); +ssize_t atomic_write(int fd, const void *s, size_t n); + +#endif // __BASE_ATOMICIO_HH__ diff --git a/src/base/bitunion.hh b/src/base/bitunion.hh index 7f7b06966..8ba28f3ba 100644 --- a/src/base/bitunion.hh +++ b/src/base/bitunion.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2005 The Regents of The University of Michigan + * Copyright (c) 2007-2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,7 @@ #include <inttypes.h> #include "base/bitfield.hh" -// The following implements the BitUnion system of defining bitfields +// The following implements the BitUnion system of defining bitfields //on top of an underlying class. This is done through the pervasive use of //both named and unnamed unions which all contain the same actual storage. //Since they're unioned with each other, all of these storage locations @@ -242,11 +242,7 @@ namespace BitfieldBackend //bitfields which are defined in the union, creating shared storage with no //overhead. #define __BitUnion(type, name) \ - namespace BitfieldUnderlyingClasses \ - { \ - class name; \ - } \ - class BitfieldUnderlyingClasses::name : \ + class BitfieldUnderlyingClasses##name : \ public BitfieldBackend::BitfieldTypes<type> \ { \ public: \ @@ -262,8 +258,8 @@ namespace BitfieldBackend }; \ }; \ typedef BitfieldBackend::BitUnionOperators< \ - BitfieldUnderlyingClasses::name::__DataType, \ - BitfieldUnderlyingClasses::name> name; + BitfieldUnderlyingClasses##name::__DataType, \ + BitfieldUnderlyingClasses##name> name; //This sets up a bitfield which has other bitfields nested inside of it. The //__data member functions like the "underlying storage" of the top level diff --git a/src/base/cast.hh b/src/base/cast.hh new file mode 100644 index 000000000..30a065cd2 --- /dev/null +++ b/src/base/cast.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_CAST_HH__ +#define __BASE_CAST_HH__ + +#include <cassert> + +// This is designed for situations where we have a pointer to a base +// type, but in all cases when we cast it to a derived type, we know +// by construction that it should work correctly. + +#if defined(DEBUG) + +// In debug builds, do the dynamic cast and assert the result is good + +template <class T, class U> +inline T +safe_cast(U ptr) +{ + T ret = dynamic_cast<T>(ptr); + assert(ret); + return ret; +} + +#else + +// In non debug builds statically cast the result to the pointer we +// want to use. This is technically unsafe, but this is only for +// cases where we know that this should work by construction. + +template <class T, class U> +inline T +safe_cast(U ptr) +{ + return static_cast<T>(ptr); +} + +#endif + +#endif // __BASE_CAST_HH__ diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh index e8238464b..d2ae45d1e 100644 --- a/src/base/chunk_generator.hh +++ b/src/base/chunk_generator.hh @@ -82,6 +82,7 @@ class ChunkGenerator { // chunkSize must be a power of two assert(chunkSize == 0 || isPowerOf2(chunkSize)); + assert(totalSize >= 0); // set up initial chunk. curAddr = startAddr; diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc index a0c015671..06d0075b2 100644 --- a/src/base/circlebuf.cc +++ b/src/base/circlebuf.cc @@ -29,12 +29,11 @@ */ #include <algorithm> +#include <cstdio> +#include <cstring> #include <string> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - +#include "base/atomicio.hh" #include "base/circlebuf.hh" #include "base/cprintf.hh" #include "base/intmath.hh" @@ -59,8 +58,8 @@ CircleBuf::dump() cprintf("start = %10d, stop = %10d, buflen = %10d\n", _start, _stop, _buflen); fflush(stdout); - ::write(STDOUT_FILENO, _buf, _buflen); - ::write(STDOUT_FILENO, "<\n", 2); + atomic_write(STDOUT_FILENO, _buf, _buflen); + atomic_write(STDOUT_FILENO, "<\n", 2); } void @@ -106,19 +105,19 @@ CircleBuf::read(int fd, int len) if (_stop > _start) { len = min(len, _stop - _start); - ::write(fd, _buf + _start, len); + atomic_write(fd, _buf + _start, len); _start += len; } else { int endlen = _buflen - _start; if (endlen > len) { - ::write(fd, _buf + _start, len); + atomic_write(fd, _buf + _start, len); _start += len; } else { - ::write(fd, _buf + _start, endlen); + atomic_write(fd, _buf + _start, endlen); _start = min(len - endlen, _stop); - ::write(fd, _buf, _start); + atomic_write(fd, _buf, _start); } } } @@ -129,11 +128,11 @@ CircleBuf::read(int fd) _size = 0; if (_stop > _start) { - ::write(fd, _buf + _start, _stop - _start); + atomic_write(fd, _buf + _start, _stop - _start); } else { - ::write(fd, _buf + _start, _buflen - _start); - ::write(fd, _buf, _stop); + atomic_write(fd, _buf + _start, _buflen - _start); + atomic_write(fd, _buf, _stop); } _start = _stop; @@ -159,9 +158,9 @@ void CircleBuf::readall(int fd) { if (_rollover) - ::write(fd, _buf + _stop, _buflen - _stop); + atomic_write(fd, _buf + _stop, _buflen - _stop); - ::write(fd, _buf, _stop); + atomic_write(fd, _buf, _stop); _start = _stop; } @@ -209,7 +208,7 @@ CircleBuf::write(const char *b, int len) _rollover = true; } - if (old_start > old_stop && old_start < _stop || - old_start < old_stop && _stop < old_stop) + if ((old_start > old_stop && old_start < _stop) || + (old_start < old_stop && _stop < old_stop)) _start = _stop + 1; } diff --git a/src/base/cp_annotate.cc b/src/base/cp_annotate.cc new file mode 100644 index 000000000..0aba2d999 --- /dev/null +++ b/src/base/cp_annotate.cc @@ -0,0 +1,1404 @@ +/* + * Copyright (c) 2006-2009 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#include "arch/utility.hh" +#include "arch/alpha/linux/threadinfo.hh" +#include "base/cp_annotate.hh" +#include "base/callback.hh" +#include "base/loader/object_file.hh" +#include "base/output.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "sim/arguments.hh" +#include "sim/core.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" + +struct CPAIgnoreSymbol +{ + const char *symbol; + size_t len; +}; +#define CPA_IGNORE_SYMBOL(sym) { #sym, sizeof(#sym) } + +CPAIgnoreSymbol ignoreSymbols[] = { + CPA_IGNORE_SYMBOL("m5a_"), + CPA_IGNORE_SYMBOL("ret_from_sys_call"), + CPA_IGNORE_SYMBOL("ret_from_reschedule"), + CPA_IGNORE_SYMBOL("_spin_"), + CPA_IGNORE_SYMBOL("local_bh_"), + CPA_IGNORE_SYMBOL("restore_all"), + CPA_IGNORE_SYMBOL("Call_Pal_"), + CPA_IGNORE_SYMBOL("pal_post_interrupt"), + CPA_IGNORE_SYMBOL("rti_to_"), + CPA_IGNORE_SYMBOL("sys_int_2"), + CPA_IGNORE_SYMBOL("sys_interrupt"), + CPA_IGNORE_SYMBOL("normal_int"), + CPA_IGNORE_SYMBOL("TRAP_INTERRUPT_10_"), + CPA_IGNORE_SYMBOL("Trap_Interrupt"), + CPA_IGNORE_SYMBOL("do_entInt"), + CPA_IGNORE_SYMBOL("__do_softirq"), + CPA_IGNORE_SYMBOL("_end"), + CPA_IGNORE_SYMBOL("entInt"), + CPA_IGNORE_SYMBOL("entSys"), + {0,0} +}; +#undef CPA_IGNORE_SYMBOL + +using namespace std; +using namespace TheISA; + +bool CPA::exists; +CPA *CPA::_cpa; + +class AnnotateDumpCallback : public Callback +{ + + private: + CPA *cpa; + public: + virtual void process(); + AnnotateDumpCallback(CPA *_cpa) + : cpa(_cpa) + {} +}; + +void +AnnotateDumpCallback::process() +{ + cpa->dump(true); + cpa->dumpKey(); +} + + +CPA::CPA(Params *p) + : SimObject(p), numSm(0), numSmt(0), numSys(0), numQs(0), conId(0) +{ + if (exists) + fatal("Multiple annotation objects found in system"); + exists = true; + + _enabled = p->enabled; + _cpa = this; + + vector<string>::iterator i; + i = p->user_apps.begin(); + + while (i != p->user_apps.end()) { + ObjectFile *of = createObjectFile(*i); + string sf; + if (!of) + fatal("Couldn't load symbols from file: %s\n", *i); + sf = *i; + sf.erase(0, sf.rfind('/') + 1);; + DPRINTFN("file %s short: %s\n", *i, sf); + userApp[sf] = new SymbolTable; + bool result1 = of->loadGlobalSymbols(userApp[sf]); + bool result2 = of->loadLocalSymbols(userApp[sf]); + if (!result1 || !result2) + panic("blah"); + assert(result1 && result2); + i++; + } +} + +void +CPA::startup() +{ + osbin = simout.create("annotate.bin", true); + // MAGIC version number 'M''5''A'N' + version/capabilities + ah.version = 0x4D35414E00000101ULL; + ah.num_recs = 0; + ah.key_off = 0; + osbin->write((char*)&ah, sizeof(AnnotateHeader)); + + registerExitCallback(new AnnotateDumpCallback(this)); +} +void +CPA::swSmBegin(ThreadContext *tc) +{ + if (!enabled()) + return; + + Arguments args(tc); + std::string st; + Addr junk; + char sm[50]; + if (!TheISA::inUserMode(tc)) + debugSymbolTable->findNearestSymbol( + tc->readIntReg(ReturnAddressReg), st, junk); + + CopyStringOut(tc, sm, args[0], 50); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + + if (!sm[0]) + warn("Got null SM at tick %d\n", curTick); + + int sysi = getSys(sys); + int smi = getSm(sysi, sm, args[1]); + DPRINTF(Annotate, "Starting machine: %s(%d) sysi: %d id: %#x\n", sm, + smi, sysi, args[1]); + DPRINTF(Annotate, "smMap[%d] = %d, %s, %#x\n", smi, + smMap[smi-1].first, smMap[smi-1].second.first, + smMap[smi-1].second.second); + + uint64_t frame = getFrame(tc); + StackId sid = StackId(sysi, frame); + + // check if we need to link to the previous state machine + int flags = args[2]; + if (flags & FL_LINK) { + if (smStack[sid].size()) { + int prev_smi = smStack[sid].back(); + DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n", + prev_smi, sm, smi, args[1]); + + if (lnMap[smi]) + DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", + smi, lnMap[smi]); + assert(lnMap[smi] == 0); + lnMap[smi] = prev_smi; + + add(OP_LINK, FL_NONE, tc->contextId(), prev_smi, smi); + } else { + DPRINTF(Annotate, "Not Linking to state machine %s(%d) [%#x]\n", + sm, smi, args[1]); + } + } + + + smStack[sid].push_back(smi); + + DPRINTF(Annotate, "Stack Now (%#X):\n", frame); + for (int x = smStack[sid].size()-1; x >= 0; x--) + DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); + + // reset the sw state exculsion to false + if (swExpl[sid]) + swExpl[sid] = false; + + + Id id = Id(sm, frame); + if (scLinks[sysi-1][id]) { + AnnDataPtr an = scLinks[sysi-1][id]; + scLinks[sysi-1].erase(id); + an->stq = smi; + an->dump = true; + DPRINTF(Annotate, + "Found prev unknown linking from %d to state machine %s(%d)\n", + an->sm, sm, smi); + + if (lnMap[smi]) + DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", + smi, lnMap[smi]); + assert(lnMap[smi] == 0); + lnMap[smi] = an->sm; + } + + // add a new begin ifwe have that info + if (st != "") { + DPRINTF(Annotate, "st: %s smi: %d stCache.size %d\n", st, + smi, stCache.size()); + int sti = getSt(sm, st); + lastState[smi] = sti; + add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti); + } +} + +void +CPA::swSmEnd(ThreadContext *tc) +{ + if (!enabled()) + return; + + Arguments args(tc); + char sm[50]; + CopyStringOut(tc, sm, args[0], 50); + System *sys = tc->getSystemPtr(); + doSwSmEnd(sys, tc->contextId(), sm, getFrame(tc)); +} + +void +CPA::doSwSmEnd(System *sys, int cpuid, string sm, uint64_t frame) +{ + int sysi = getSys(sys); + StackId sid = StackId(sysi, frame); + + + // reset the sw state exculsion to false + if (swExpl[sid]) + swExpl[sid] = false; + + + int smib = smStack[sid].back(); + StringWrap name(sys->name()); + DPRINTF(Annotate, "Ending machine: %s[%d, %#x] (%d?)\n", sm, sysi, + frame, smib); + + if (!smStack[sid].size() || smMap[smib-1].second.first != sm) { + DPRINTF(Annotate, "State Machine not unwinding correctly. sid: %d, %#x" + " top of stack: %s Current Stack:\n", + sysi, frame, smMap[smib-1].second.first); + for (int x = smStack[sid].size()-1; x >= 0; x--) + DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); + DPRINTF(Annotate, "Ending machine: %s; end stack: %s\n", sm, + smMap[smib-1].second.first); + + warn("State machine stack not unwinding correctly at %d\n", curTick); + } else { + DPRINTF(Annotate, + "State machine ending:%s sysi:%d id:%#x back:%d getSm:%d\n", + sm, sysi, smMap[smib-1].second.second, smStack[sid].back(), + getSm(sysi, sm, smMap[smib-1].second.second)); + assert(getSm(sysi, sm, smMap[smib-1].second.second) == + smStack[sid].back()); + + int smi = smStack[sid].back(); + smStack[sid].pop_back(); + + if (lnMap[smi]) { + DPRINTF(Annotate, "Linking %d back to %d\n", smi, lnMap[smi]); + add(OP_LINK, FL_NONE, cpuid, smi, lnMap[smi]); + lnMap.erase(smi); + } + + if (smStack[sid].size()) { + add(OP_BEGIN, FL_NONE, cpuid, smi, lastState[smi]); + } + + DPRINTF(Annotate, "Stack Now:\n"); + for (int x = smStack[sid].size()-1; x >= 0; x--) + DPRINTF(Annotate, "-- %d\n", smStack[sid][x]); + } +} + + +void +CPA::swExplictBegin(ThreadContext *tc) +{ + if (!enabled()) + return; + + Arguments args(tc); + char st[50]; + CopyStringOut(tc, st, args[1], 50); + + StringWrap name(tc->getSystemPtr()->name()); + DPRINTF(Annotate, "Explict begin of state %s\n", st); + uint32_t flags = args[0]; + if (flags & FL_BAD) + warn("BAD state encountered: at cycle %d: %s\n", curTick, st); + swBegin(tc->getSystemPtr(), tc->contextId(), st, getFrame(tc), true, args[0]); +} + +void +CPA::swAutoBegin(ThreadContext *tc, Addr next_pc) +{ + if (!enabled()) + return; + + string sym; + Addr sym_addr = 0; + SymbolTable *symtab = NULL; + + + if (!TheISA::inUserMode(tc)) { + debugSymbolTable->findNearestSymbol(next_pc, sym, sym_addr); + symtab = debugSymbolTable; + } else { + Linux::ThreadInfo ti(tc); + string app = ti.curTaskName(); + if (userApp.count(app)) + userApp[app]->findNearestSymbol(next_pc, sym, sym_addr); + } + + if (sym_addr) + swBegin(tc->getSystemPtr(), tc->contextId(), sym, getFrame(tc)); +} + +void +CPA::swBegin(System *sys, int cpuid, std::string st, uint64_t frame, bool expl, + int flags) +{ + int x = 0; + int len; + while (ignoreSymbols[x].len) + { + len = ignoreSymbols[x].len; + if (!st.compare(0,len, ignoreSymbols[x].symbol, len)) + return; + x++; + } + + int sysi = getSys(sys); + StackId sid = StackId(sysi, frame); + // if expl is true suspend symbol table based states + if (!smStack[sid].size()) + return; + if (!expl && swExpl[sid]) + return; + if (expl) + swExpl[sid] = true; + DPRINTFS(AnnotateVerbose, sys, "SwBegin: %s sysi: %d\n", st, sysi); + int smi = smStack[sid].back(); + int sti = getSt(smMap[smi-1].second.first, st); + if (lastState[smi] != sti) { + lastState[smi] = sti; + add(OP_BEGIN, flags, cpuid, smi, sti); + } +} + +void +CPA::swEnd(ThreadContext *tc) +{ + if (!enabled()) + return; + + std::string st; + Addr junk; + if (!TheISA::inUserMode(tc)) + debugSymbolTable->findNearestSymbol( + tc->readIntReg(ReturnAddressReg), st, junk); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) { + DPRINTF(Annotate, "Explict end of State: %s IGNORED\n", st); + return; + } + DPRINTF(Annotate, "Explict end of State: %s\n", st); + // return back to symbol table based states + swExpl[sid] = false; + int smi = smStack[sid].back(); + if (st != "") { + int sti = getSt(smMap[smi-1].second.first, st); + lastState[smi] = sti; + add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti); + } +} + +void +CPA::swQ(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + int32_t count = args[2]; + System *sys = tc->getSystemPtr(); + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + if (swExpl[sid]) + swExpl[sid] = false; + int qi = getQ(sysi, q, id); + if (count == 0) { + //warn("Tried to queue 0 bytes in %s, ignoring\n", q); + return; + } + DPRINTFS(AnnotateQ, sys, + "swQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n", + q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, count); +} + +void +CPA::swDq(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + int32_t count = args[2]; + System *sys = tc->getSystemPtr(); + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + if (swExpl[sid]) + swExpl[sid] = false; + DPRINTFS(AnnotateQ, sys, + "swDq: %s[%#x] cur size %d %d bytes: %d removing: %d\n", + q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + assert(count != 0); + + doDq(sys, FL_NONE, tc->contextId(), smi, q, qi, count); +} + +void +CPA::swPq(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + int32_t count = args[2]; + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + if (swExpl[sid]) + swExpl[sid] = false; + DPRINTFS(AnnotateQ, sys, + "swPq: %s [%#x] cur size %d %d bytes: %d peeking: %d\n", + q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + + assert(count != 0); + if (qBytes[qi-1] < count) { + dump(true); + dumpKey(); + fatal("Queue %s peeking with not enough bytes available in queue!\n", q); + } + + add(OP_PEEK, FL_NONE, tc->contextId(), smi, qi, count); +} + +void +CPA::swRq(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + int32_t count = args[2]; + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + if (swExpl[sid]) + swExpl[sid] = false; + DPRINTFS(AnnotateQ, sys, + "swRq: %s [%#x] cur size %d %d bytes: %d reserve: %d\n", + q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + + assert(count != 0); + + add(OP_RESERVE, FL_NONE, tc->contextId(), smi, qi, count); +} + + +void +CPA::swWf(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + int32_t count = args[3]; + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + add(OP_WAIT_FULL, FL_NONE, tc->contextId(), smi, qi, count); + + if (!!args[2]) { + char sm[50]; + CopyStringOut(tc, sm, args[2], 50); + doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); + } +} + +void +CPA::swWe(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + int32_t count = args[3]; + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + add(OP_WAIT_EMPTY, FL_NONE, tc->contextId(), smi, qi, count); + + if (!!args[2]) { + char sm[50]; + CopyStringOut(tc, sm, args[2], 50); + doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); + } +} + +void +CPA::swSq(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + int32_t size = args[2]; + int flags = args[3]; + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int qi = getQ(sysi, q, id); + DPRINTF(AnnotateQ, "swSq: %s [%#x] cur size: %d bytes: %d, new size: %d\n", + q, id, qSize[qi-1], qBytes[qi-1], size); + + if (FL_RESET & flags) { + DPRINTF(AnnotateQ, "Resetting Queue %s\n", q); + add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, 0); + qData[qi-1].clear(); + qSize[qi-1] = 0; + qBytes[qi-1] = 0; + } + + if (qBytes[qi-1] < size) + doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, size - qBytes[qi-1]); + else if (qBytes[qi-1] > size) { + DPRINTF(AnnotateQ, "removing for resize of queue %s\n", q); + add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, size); + if (size <= 0) { + qData[qi-1].clear(); + qSize[qi-1] = 0; + qBytes[qi-1] = 0; + return; + } + int need = qBytes[qi-1] - size; + qBytes[qi-1] = size; + while (need > 0) { + int32_t tail_bytes = qData[qi-1].back()->data; + if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) { + dump(true); + dumpKey(); + fatal("Queue %s had inconsistancy when doing size queue!\n", q); + } + if (tail_bytes > need) { + qData[qi-1].back()->data -= need; + need = 0; + } else if (tail_bytes == need) { + qData[qi-1].pop_back(); + qSize[qi-1]--; + need = 0; + } else { + qData[qi-1].pop_back(); + qSize[qi-1]--; + need -= tail_bytes; + } + } + } +} + +void +CPA::swAq(ThreadContext *tc) +{ + if (!enabled()) + return; + + char q[50]; + Arguments args(tc); + uint64_t id = args[0]; + CopyStringOut(tc, q, args[1], 50); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + int32_t size = args[2]; + + int sysi = getSys(sys); + int qi = getQ(sysi, q, id); + if (qBytes[qi-1] != size) { + DPRINTF(AnnotateQ, "Queue %s [%#x] has inconsintant size\n", q, id); + //dump(true); + //dumpKey(); + std::list<AnnDataPtr>::iterator ai = qData[qi-1].begin(); + int x = 0; + while (ai != qData[qi-1].end()) { + DPRINTF(AnnotateQ, "--Element %d size %d\n", x, (*ai)->data); + ai++; + x++; + } + + warn("%d: Queue Assert: SW said there should be %d byte(s) in %s," + "however there are %d byte(s)\n", + curTick, size, q, qBytes[qi-1]); + DPRINTF(AnnotateQ, "%d: Queue Assert: SW said there should be %d" + " byte(s) in %s, however there are %d byte(s)\n", + curTick, size, q, qBytes[qi-1]); + } +} + +void +CPA::swLink(ThreadContext *tc) +{ + if (!enabled()) + return; + + char lsm[50]; + Arguments args(tc); + CopyStringOut(tc, lsm, args[0], 50); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + + int sysi = getSys(sys); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + int lsmi = getSm(sysi, lsm, args[1]); + + DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n", + smi, lsm, lsmi, args[1]); + + if (lnMap[lsmi]) + DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n", + lsmi, lnMap[lsmi]); + assert(lnMap[lsmi] == 0); + lnMap[lsmi] = smi; + + add(OP_LINK, FL_NONE, tc->contextId(), smi, lsmi); + + if (!!args[2]) { + char sm[50]; + CopyStringOut(tc, sm, args[2], 50); + doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); + } +} + +void +CPA::swIdentify(ThreadContext *tc) +{ + if (!enabled()) + return; + + Arguments args(tc); + int sysi = getSys(tc->getSystemPtr()); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + return; + int smi = smStack[sid].back(); + + DPRINTFS(Annotate, tc->getSystemPtr(), "swIdentify: id %#X\n", args[0]); + + add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, args[0]); +} + +uint64_t +CPA::swGetId(ThreadContext *tc) +{ + if (!enabled()) + return 0; + + uint64_t id = ++conId; + int sysi = getSys(tc->getSystemPtr()); + StackId sid = StackId(sysi, getFrame(tc)); + if (!smStack[sid].size()) + panic("swGetId called without a state machine stack!"); + int smi = smStack[sid].back(); + + DPRINTFS(Annotate, tc->getSystemPtr(), "swGetId: id %#X\n", id); + + add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, id); + return id; +} + + +void +CPA::swSyscallLink(ThreadContext *tc) +{ + if (!enabled()) + return; + + char lsm[50]; + Arguments args(tc); + CopyStringOut(tc, lsm, args[0], 50); + System *sys = tc->getSystemPtr(); + StringWrap name(sys->name()); + int sysi = getSys(sys); + + Id id = Id(lsm, getFrame(tc)); + StackId sid = StackId(sysi, getFrame(tc)); + + if (!smStack[sid].size()) + return; + + int smi = smStack[sid].back(); + + DPRINTF(Annotate, "Linking from %d to state machine %s(UNKNOWN)\n", + smi, lsm); + + if (scLinks[sysi-1][id]) + DPRINTF(Annotate, + "scLinks already contains entry for system %d %s[%x] of %d\n", + sysi, lsm, getFrame(tc), scLinks[sysi-1][id]); + assert(scLinks[sysi-1][id] == 0); + scLinks[sysi-1][id] = add(OP_LINK, FL_NONE, tc->contextId(), smi, 0xFFFF); + scLinks[sysi-1][id]->dump = false; + + if (!!args[1]) { + char sm[50]; + CopyStringOut(tc, sm, args[1], 50); + doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc)); + } +} + +CPA::AnnDataPtr +CPA::add(int t, int f, int c, int sm, int stq, int32_t d) +{ + AnnDataPtr an = new AnnotateData; + an->time = curTick; + an->data = d; + an->orig_data = d; + an->op = t; + an->flag = f; + an->sm = sm; + an->stq = stq; + an->cpu = c; + an->dump = true; + + data.push_back(an); + + DPRINTF(AnnotateVerbose, "Annotate: op: %d flags: 0x%x sm: %d state: %d time: %d, data: %d\n", + an->op, an->flag, an->sm, an->stq, an->time, an->data); + + // Don't dump Links because we might be setting no-dump on it + if (an->op != OP_LINK) + dump(false); + + return an; +} + +void +CPA::dumpKey() +{ + std::streampos curpos = osbin->tellp(); + ah.key_off = curpos; + + // Output the various state machines and their corresponding states + *osbin << "# Automatically generated state machine descriptor file" << endl; + + *osbin << "sms = {}" << endl << endl; + vector<string> state_machines; + state_machines.resize(numSmt+1); + + // State machines, id -> states + SCache::iterator i = smtCache.begin(); + while (i != smtCache.end()) { + state_machines[i->second] = i->first; + i++; + } + + for (int x = 1; x < state_machines.size(); x++) { + vector<string> states; + states.resize(numSt[x-1]+1); + assert(x-1 < stCache.size()); + SCache::iterator i = stCache[x-1].begin(); + while (i != stCache[x-1].end()) { + states[i->second] = i->first; + i++; + } + *osbin << "sms[\"" << state_machines[x] << "\"] = [\"NULL\""; + for (int y = 1; y < states.size(); y++) + *osbin << ", \"" << states[y] << "\""; + *osbin << "]" << endl; + } + + *osbin << endl << endl << endl; + + // state machine number -> system, name, id + *osbin << "smNum = [\"NULL\""; + for (int x = 0; x < smMap.size(); x++) + *osbin << ", (" << smMap[x].first << ", \"" << smMap[x].second.first << + "\", " << smMap[x].second.second << ")"; + *osbin << "]" << endl; + + *osbin << endl << endl << endl; + + // Output the systems + vector<string> systems; + systems.resize(numSys+1); + NameCache::iterator i2 = nameCache.begin(); + while (i2 != nameCache.end()) { + systems[i2->second.second] = i2->second.first; + i2++; + } + + *osbin << "sysNum = [\"NULL\""; + for (int x = 1; x < systems.size(); x++) { + *osbin << ", \"" << systems[x] << "\""; + } + *osbin << "]" << endl; + + // queue number -> system, qname, qid + *osbin << "queues = [\"NULL\""; + for (int x = 0; x < qMap.size(); x++) + *osbin << ", (" << qMap[x].first << ", \"" << qMap[x].second.first << + "\", " << qMap[x].second.second << ")"; + *osbin << "]" << endl; + + *osbin << "smComb = [s for s in [(i,r) for i in xrange(1,len(sysNum)) " + << "for r in xrange (1,len(smNum))]]" << endl; + ah.key_len = osbin->tellp() - curpos; + + // output index + curpos = osbin->tellp(); + ah.idx_off = curpos; + + for (int x = 0; x < annotateIdx.size(); x++) + osbin->write((char*)&annotateIdx[x], sizeof(uint64_t)); + ah.idx_len = osbin->tellp() - curpos; + + osbin->seekp(0); + osbin->write((char*)&ah, sizeof(AnnotateHeader)); + osbin->flush(); + +} + +void +CPA::dump(bool all) +{ + + list<AnnDataPtr>::iterator i; + + i = data.begin(); + + if (i == data.end()) + return; + + // Dump the data every + if (!all && data.size() < 10000) + return; + + DPRINTF(Annotate, "Writing %d\n", data.size()); + while (i != data.end()) { + AnnDataPtr an = *i; + + // If we can't dump this record, hold here + if (!an->dump && !all) + break; + + ah.num_recs++; + if (ah.num_recs % 100000 == 0) + annotateIdx.push_back(osbin->tellp()); + + + osbin->write((char*)&(an->time), sizeof(an->time)); + osbin->write((char*)&(an->orig_data), sizeof(an->orig_data)); + osbin->write((char*)&(an->sm), sizeof(an->sm)); + osbin->write((char*)&(an->stq), sizeof(an->stq)); + osbin->write((char*)&(an->op), sizeof(an->op)); + osbin->write((char*)&(an->flag), sizeof(an->flag)); + osbin->write((char*)&(an->cpu), sizeof(an->cpu)); + i++; + } + if (data.begin() != i) + data.erase(data.begin(), i); + + if (all) + osbin->flush(); +} + +void +CPA::doQ(System *sys, int flags, int cpuid, int sm, + string q, int qi, int count) +{ + qSize[qi-1]++; + qBytes[qi-1] += count; + if (qSize[qi-1] > 2501 || qBytes[qi-1] > 2000000000) + warn("Queue %s is %d elements/%d bytes, " + "maybe things aren't being removed?\n", + q, qSize[qi-1], qBytes[qi-1]); + if (flags & FL_QOPP) + qData[qi-1].push_front(add(OP_QUEUE, flags, cpuid, sm, qi, count)); + else + qData[qi-1].push_back(add(OP_QUEUE, flags, cpuid, sm, qi, count)); + DPRINTFS(AnnotateQ, sys, "Queing in queue %s size now %d/%d\n", + q, qSize[qi-1], qBytes[qi-1]); + assert(qSize[qi-1] >= 0); + assert(qBytes[qi-1] >= 0); +} + + +void +CPA::doDq(System *sys, int flags, int cpuid, int sm, + string q, int qi, int count) +{ + + StringWrap name(sys->name()); + if (count == -1) { + add(OP_DEQUEUE, flags, cpuid, sm, qi, count); + qData[qi-1].clear(); + qSize[qi-1] = 0; + qBytes[qi-1] = 0; + DPRINTF(AnnotateQ, "Dequeing all data in queue %s size now %d/%d\n", + q, qSize[qi-1], qBytes[qi-1]); + return; + } + + assert(count > 0); + if (qSize[qi-1] <= 0 || qBytes[qi-1] <= 0 || !qData[qi-1].size()) { + dump(true); + dumpKey(); + fatal("Queue %s dequing with no data available in queue!\n", + q); + } + assert(qSize[qi-1] >= 0); + assert(qBytes[qi-1] >= 0); + assert(qData[qi-1].size()); + + int32_t need = count; + qBytes[qi-1] -= count; + if (qBytes[qi-1] < 0) { + dump(true); + dumpKey(); + fatal("Queue %s dequing with no bytes available in queue!\n", + q); + } + + while (need > 0) { + int32_t head_bytes = qData[qi-1].front()->data; + if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) { + dump(true); + dumpKey(); + fatal("Queue %s dequing with nothing in queue!\n", + q); + } + + if (head_bytes > need) { + qData[qi-1].front()->data -= need; + need = 0; + } else if (head_bytes == need) { + qData[qi-1].pop_front(); + qSize[qi-1]--; + need = 0; + } else { + qData[qi-1].pop_front(); + qSize[qi-1]--; + need -= head_bytes; + } + } + + add(OP_DEQUEUE, flags, cpuid, sm, qi, count); + DPRINTF(AnnotateQ, "Dequeing in queue %s size now %d/%d\n", + q, qSize[qi-1], qBytes[qi-1]); +} + + + +void +CPA::serialize(std::ostream &os) +{ + + SERIALIZE_SCALAR(numSm); + SERIALIZE_SCALAR(numSmt); + arrayParamOut(os, "numSt", numSt); + arrayParamOut(os, "numQ", numQ); + SERIALIZE_SCALAR(numSys); + SERIALIZE_SCALAR(numQs); + SERIALIZE_SCALAR(conId); + arrayParamOut(os, "qSize", qSize); + arrayParamOut(os, "qSize", qSize); + arrayParamOut(os, "qBytes", qBytes); + + std::list<AnnDataPtr>::iterator ai; + + SCache::iterator i; + int x = 0, y = 0; + + // smtCache (SCache) + x = 0; + y = 0; + i = smtCache.begin(); + while (i != smtCache.end()) { + paramOut(os, csprintf("smtCache%d.str", x), i->first); + paramOut(os, csprintf("smtCache%d.int", x), i->second); + x++; i++; + } + + // stCache (StCache) + for (x = 0; x < stCache.size(); x++) { + i = stCache[x].begin(); + y = 0; + while (i != stCache[x].end()) { + paramOut(os, csprintf("stCache%d_%d.str", x, y), i->first); + paramOut(os, csprintf("stCache%d_%d.int", x, y), i->second); + y++; i++; + } + } + + // qCache (IdCache) + IdHCache::iterator idi; + for (x = 0; x < qCache.size(); x++) { + idi = qCache[x].begin(); + y = 0; + while (idi != qCache[x].end()) { + paramOut(os, csprintf("qCache%d_%d.str", x, y), idi->first.first); + paramOut(os, csprintf("qCache%d_%d.id", x, y), idi->first.second); + paramOut(os, csprintf("qCache%d_%d.int", x, y), idi->second); + y++; idi++; + } + } + + // smCache (IdCache) + for (x = 0; x < smCache.size(); x++) { + idi = smCache[x].begin(); + y = 0; + paramOut(os, csprintf("smCache%d", x), smCache[x].size()); + while (idi != smCache[x].end()) { + paramOut(os, csprintf("smCache%d_%d.str", x, y), idi->first.first); + paramOut(os, csprintf("smCache%d_%d.id", x, y), idi->first.second); + paramOut(os, csprintf("smCache%d_%d.int", x, y), idi->second); + y++; idi++; + } + } + + // scLinks (ScCache) -- data not serialize + + + // namecache (NameCache) + NameCache::iterator ni; + + ni = nameCache.begin(); + x = 0; + while (ni != nameCache.end()) { + paramOut(os, csprintf("nameCache%d.name", x), ni->first->name()); + paramOut(os, csprintf("nameCache%d.str", x), ni->second.first); + paramOut(os, csprintf("nameCache%d.int", x), ni->second.second); + x++; ni++; + } + + // smStack (SmStack) + SmStack::iterator si; + si = smStack.begin(); + x = 0; + paramOut(os, "smStackIdCount", smStack.size()); + while (si != smStack.end()) { + paramOut(os, csprintf("smStackId%d.sys", x), si->first.first); + paramOut(os, csprintf("smStackId%d.frame", x), si->first.second); + paramOut(os, csprintf("smStackId%d.count", x), si->second.size()); + for (y = 0; y < si->second.size(); y++) + paramOut(os, csprintf("smStackId%d_%d", x, y), si->second[y]); + x++; si++; + } + + // lnMap (LinkMap) + x = 0; + LinkMap::iterator li; + li = lnMap.begin(); + paramOut(os, "lnMapSize", lnMap.size()); + while (li != lnMap.end()) { + paramOut(os, csprintf("lnMap%d.smi", x), li->first); + paramOut(os, csprintf("lnMap%d.lsmi", x), li->second); + x++; li++; + } + + // swExpl (vector) + SwExpl::iterator swexpli; + swexpli = swExpl.begin(); + x = 0; + paramOut(os, "swExplCount", swExpl.size()); + while (swexpli != swExpl.end()) { + paramOut(os, csprintf("swExpl%d.sys", x), swexpli->first.first); + paramOut(os, csprintf("swExpl%d.frame", x), swexpli->first.second); + paramOut(os, csprintf("swExpl%d.swexpl", x), swexpli->second); + x++; swexpli++; + } + + // lastState (IMap) + x = 0; + IMap::iterator ii; + ii = lastState.begin(); + paramOut(os, "lastStateSize", lastState.size()); + while (ii != lastState.end()) { + paramOut(os, csprintf("lastState%d.smi", x), ii->first); + paramOut(os, csprintf("lastState%d.sti", x), ii->second); + x++; ii++; + } + + // smMap (IdMap) + for (x = 0; x < smMap.size(); x++) { + paramOut(os, csprintf("smMap%d.sys", x), smMap[x].first); + paramOut(os, csprintf("smMap%d.smname", x), smMap[x].second.first); + paramOut(os, csprintf("smMap%d.id", x), smMap[x].second.second); + } + + // qMap (IdMap) + for (x = 0; x < qMap.size(); x++) { + paramOut(os, csprintf("qMap%d.sys", x), qMap[x].first); + paramOut(os, csprintf("qMap%d.qname", x), qMap[x].second.first); + paramOut(os, csprintf("qMap%d.id", x), qMap[x].second.second); + } + + // qData (vector<AnnotateList>) + for(x = 0; x < qData.size(); x++) { + if (!qData[x].size()) + continue; + y = 0; + ai = qData[x].begin(); + while (ai != qData[x].end()) { + nameOut(os, csprintf("%s.Q%d_%d", name(), x, y)); + (*ai)->serialize(os); + ai++; + y++; + } + } +} + +void +CPA::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(numSm); + UNSERIALIZE_SCALAR(numSmt); + arrayParamIn(cp, section, "numSt", numSt); + arrayParamIn(cp, section, "numQ", numQ); + UNSERIALIZE_SCALAR(numSys); + UNSERIALIZE_SCALAR(numQs); + UNSERIALIZE_SCALAR(conId); + arrayParamIn(cp, section, "qSize", qSize); + arrayParamIn(cp, section, "qBytes", qBytes); + + + // smtCache (SCache + string str; + int smi; + for (int x = 0; x < numSmt; x++) { + paramIn(cp, section, csprintf("smtCache%d.str", x), str); + paramIn(cp, section, csprintf("smtCache%d.int", x), smi); + smtCache[str] = smi; + } + + // stCache (StCache) + stCache.resize(numSmt); + for (int x = 0; x < numSmt; x++) { + for (int y = 0; y < numSt[x]; y++) { + paramIn(cp, section, csprintf("stCache%d_%d.str", x,y), str); + paramIn(cp, section, csprintf("stCache%d_%d.int", x,y), smi); + stCache[x][str] = smi; + } + } + + // qCache (IdCache) + uint64_t id; + qCache.resize(numSys); + for (int x = 0; x < numSys; x++) { + for (int y = 0; y < numQ[x]; y++) { + paramIn(cp, section, csprintf("qCache%d_%d.str", x,y), str); + paramIn(cp, section, csprintf("qCache%d_%d.id", x,y), id); + paramIn(cp, section, csprintf("qCache%d_%d.int", x,y), smi); + qCache[x][Id(str,id)] = smi; + } + } + + // smCache (IdCache) + smCache.resize(numSys); + for (int x = 0; x < numSys; x++) { + int size; + paramIn(cp, section, csprintf("smCache%d", x), size); + for (int y = 0; y < size; y++) { + paramIn(cp, section, csprintf("smCache%d_%d.str", x,y), str); + paramIn(cp, section, csprintf("smCache%d_%d.id", x,y), id); + paramIn(cp, section, csprintf("smCache%d_%d.int", x,y), smi); + smCache[x][Id(str,id)] = smi; + } + } + + // scLinks (ScCache) -- data not serialized, just creating one per sys + for (int x = 0; x < numSys; x++) + scLinks.push_back(ScHCache()); + + // nameCache (NameCache) + for (int x = 0; x < numSys; x++) { + System *sys; + SimObject *sptr; + string str; + int sysi; + + objParamIn(cp, section, csprintf("nameCache%d.name", x), sptr); + sys = dynamic_cast<System*>(sptr); + + paramIn(cp, section, csprintf("nameCache%d.str", x), str); + paramIn(cp, section, csprintf("nameCache%d.int", x), sysi); + nameCache[sys] = std::make_pair<std::string,int>(str, sysi); + } + + //smStack (SmStack) + int smStack_size; + paramIn(cp, section, "smStackIdCount", smStack_size); + for (int x = 0; x < smStack_size; x++) { + int sysi; + uint64_t frame; + int count; + paramIn(cp, section, csprintf("smStackId%d.sys", x), sysi); + paramIn(cp, section, csprintf("smStackId%d.frame", x), frame); + paramIn(cp, section, csprintf("smStackId%d.count", x), count); + StackId sid = StackId(sysi, frame); + for (int y = 0; y < count; y++) { + paramIn(cp, section, csprintf("smStackId%d_%d", x, y), smi); + smStack[sid].push_back(smi); + } + } + + // lnMap (LinkMap) + int lsmi; + int lnMap_size; + paramIn(cp, section, "lnMapSize", lnMap_size); + for (int x = 0; x < lnMap_size; x++) { + paramIn(cp, section, csprintf("lnMap%d.smi", x), smi); + paramIn(cp, section, csprintf("lnMap%d.lsmi", x), lsmi); + lnMap[smi] = lsmi; + } + + // swExpl (vector) + int swExpl_size; + paramIn(cp, section, "swExplCount", swExpl_size); + for (int x = 0; x < swExpl_size; x++) { + int sysi; + uint64_t frame; + bool b; + paramIn(cp, section, csprintf("swExpl%d.sys", x), sysi); + paramIn(cp, section, csprintf("swExpl%d.frame", x), frame); + paramIn(cp, section, csprintf("swExpl%d.swexpl", x), b); + StackId sid = StackId(sysi, frame); + swExpl[sid] = b; + } + + // lastState (IMap) + int sti; + int lastState_size; + paramIn(cp, section, "lastStateSize", lastState_size); + for (int x = 0; x < lastState_size; x++) { + paramIn(cp, section, csprintf("lastState%d.smi", x), smi); + paramIn(cp, section, csprintf("lastState%d.sti", x), sti); + lastState[smi] = sti; + } + + + //smMap (IdMap) + smMap.resize(numSm); + for (int x = 0; x < smMap.size(); x++) { + paramIn(cp, section, csprintf("smMap%d.sys", x), smMap[x].first); + paramIn(cp, section, csprintf("smMap%d.smname", x), smMap[x].second.first); + paramIn(cp, section, csprintf("smMap%d.id", x), smMap[x].second.second); + } + + //qMap (IdMap) + qMap.resize(numQs); + for (int x = 0; x < qMap.size(); x++) { + paramIn(cp, section, csprintf("qMap%d.sys", x), qMap[x].first); + paramIn(cp, section, csprintf("qMap%d.qname", x), qMap[x].second.first); + paramIn(cp, section, csprintf("qMap%d.id", x), qMap[x].second.second); + } + + + // qData (vector<AnnotateList>) + qData.resize(qSize.size()); + for (int x = 0; x < qSize.size(); x++) { + if (!qSize[x]) + continue; + for (int y = 0; y < qSize[x]; y++) { + AnnDataPtr a = new AnnotateData; + a->unserialize(cp, csprintf("%s.Q%d_%d", section, x, y)); + data.push_back(a); + qData[x].push_back(a); + } + } +} + +void +CPA::AnnotateData::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(time); + SERIALIZE_SCALAR(data); + SERIALIZE_SCALAR(sm); + SERIALIZE_SCALAR(stq); + SERIALIZE_SCALAR(op); + SERIALIZE_SCALAR(flag); + SERIALIZE_SCALAR(cpu); +} + +void +CPA::AnnotateData::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(time); + UNSERIALIZE_SCALAR(data); + orig_data = data; + UNSERIALIZE_SCALAR(sm); + UNSERIALIZE_SCALAR(stq); + UNSERIALIZE_SCALAR(op); + UNSERIALIZE_SCALAR(flag); + UNSERIALIZE_SCALAR(cpu); + dump = true; +} + +CPA* +CPAParams::create() +{ + return new CPA(this); +} + diff --git a/src/base/cp_annotate.hh b/src/base/cp_annotate.hh new file mode 100644 index 000000000..13ced82de --- /dev/null +++ b/src/base/cp_annotate.hh @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2006-2009 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#ifndef __BASE__CP_ANNOTATE_HH__ +#define __BASE__CP_ANNOTATE_HH__ + +#include "base/loader/symtab.hh" +#include "config/cp_annotate.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" +#include "sim/startup.hh" +#include "sim/system.hh" + +#include <string> +#include <list> +#include <vector> +#include <map> +#include "base/hashmap.hh" +#include "base/trace.hh" +#if CP_ANNOTATE +#include "params/CPA.hh" +#endif + +class System; +class ThreadContext; + + +#if !CP_ANNOTATE +class CPA +{ + public: + enum flags { + FL_NONE = 0x00, + FL_HW = 0x01, + FL_BAD = 0x02, + FL_QOPP = 0x04, + FL_WAIT = 0x08, + FL_LINK = 0x10, + FL_RESET = 0x20 + }; + + static CPA *cpa() { return NULL; } + static bool available() { return false; } + bool enabled() { return false; } + void swSmBegin(ThreadContext *tc) { return; } + void swSmEnd(ThreadContext *tc) { return; } + void swExplictBegin(ThreadContext *tc) { return; } + void swAutoBegin(ThreadContext *tc, Addr next_pc) { return; } + void swEnd(ThreadContext *tc) { return; } + void swQ(ThreadContext *tc) { return; } + void swDq(ThreadContext *tc) { return; } + void swPq(ThreadContext *tc) { return; } + void swRq(ThreadContext *tc) { return; } + void swWf(ThreadContext *tc) { return; } + void swWe(ThreadContext *tc) { return; } + void swSq(ThreadContext *tc) { return; } + void swAq(ThreadContext *tc) { return; } + void swLink(ThreadContext *tc) { return; } + void swIdentify(ThreadContext *tc) { return; } + uint64_t swGetId(ThreadContext *tc) { return 0; } + void swSyscallLink(ThreadContext *tc) { return; } + void hwBegin(flags f, System *sys, uint64_t frame, std::string sm, + std::string st) { return; } + void hwQ(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } + void hwDq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } + void hwPq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } + void hwRq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } + void hwWf(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } + void hwWe(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, + int32_t count = 1) { return; } +}; +#else +class CPA : SimObject +{ + public: + typedef CPAParams Params; + + /** The known operations that are written to the annotation output file. */ + enum ops { + OP_BEGIN = 0x01, + OP_WAIT_EMPTY = 0x02, + OP_WAIT_FULL = 0x03, + OP_QUEUE = 0x04, + OP_DEQUEUE = 0x05, + OP_SIZE_QUEUE = 0x08, + OP_PEEK = 0x09, + OP_LINK = 0x0A, + OP_IDENT = 0x0B, + OP_RESERVE = 0x0C + }; + + /** Flags for the various options.*/ + enum flags { + /* no flags */ + FL_NONE = 0x00, + /* operation was done on hardware */ + FL_HW = 0x01, + /* operation should cause a warning when encountered */ + FL_BAD = 0x02, + /* Queue like a stack, not a queue */ + FL_QOPP = 0x04, + /* Mark HW state as waiting for some non-resource constraint + * (e.g. wait because SM only starts after 10 items are queued) */ + FL_WAIT = 0x08, + /* operation is linking to another state machine */ + FL_LINK = 0x10, + /* queue should be completely cleared/reset before executing this + * operation */ + FL_RESET = 0x20 + }; + + + + protected: + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + /* struct that is written to the annotation output file */ + struct AnnotateData : public RefCounted { + + Tick time; + uint32_t data; + uint32_t orig_data; + uint16_t sm; + uint16_t stq; + uint8_t op; + uint8_t flag; + uint8_t cpu; + bool dump; + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + }; + + typedef RefCountingPtr<AnnotateData> AnnDataPtr; + + /* header for the annotation file */ + struct AnnotateHeader { + uint64_t version; + uint64_t num_recs; + uint64_t key_off; + uint64_t idx_off; + uint32_t key_len; + uint32_t idx_len; + }; + + AnnotateHeader ah; + + std::vector<uint64_t> annotateIdx; + + // number of state machines encountered in the simulation + int numSm; + // number of states encountered in the simulation + int numSmt; + // number of states/queues for a given state machine/system respectively + std::vector<int> numSt, numQ; + // number of systems in the simulation + int numSys; + // number of queues in the state machine + int numQs; + // maximum connection id assigned so far + uint64_t conId; + + // Convert state strings into state ids + typedef m5::hash_map<std::string, int> SCache; + typedef std::vector<SCache> StCache; + + // Convert sm and queue name,id into queue id + typedef std::pair<std::string, uint64_t> Id; + typedef m5::hash_map<Id, int> IdHCache; + typedef std::vector<IdHCache> IdCache; + + // Hold mapping of sm and queues to output python + typedef std::vector<std::pair<int, Id> > IdMap; + + // System pointer to name,id + typedef std::map<System*, std::pair<std::string, int> > NameCache; + + // array of systems each of which is a stack of running sm + typedef std::pair<int, uint64_t> StackId; + typedef std::map<StackId, std::vector<int> > SmStack; + + // map of each context and if it's currently in explict state mode + // states are not automatically updated until it leaves + typedef std::map<StackId, bool> SwExpl; + + typedef std::map<int,int> IMap; + // List of annotate records have not been written/completed yet + typedef std::list<AnnDataPtr> AnnotateList; + + // Maintain link state information + typedef std::map<int, int> LinkMap; + + // SC Links + typedef m5::hash_map<Id, AnnDataPtr> ScHCache; + typedef std::vector<ScHCache> ScCache; + + + AnnotateList data; + + // vector indexed by queueid to find current number of elements and bytes + std::vector<int> qSize; + std::vector<int32_t> qBytes; + + + // Turn state machine string into state machine id (small int) + // Used for outputting key to convert id back into string + SCache smtCache; + // Turn state machine id, state name into state id (small int) + StCache stCache; + // turn system, queue, and queue identify into qid (small int) + // turn system, state, and context into state machine id (small int) + IdCache qCache, smCache; + //Link state machines accross system calls + ScCache scLinks; + // System pointer to name,id + NameCache nameCache; + // Stack of state machines currently nested (should unwind correctly) + SmStack smStack; + // Map of currently outstanding links + LinkMap lnMap; + // If the state machine is currently exculding automatic changes + SwExpl swExpl; + // Last state that a given state machine was in + IMap lastState; + // Hold mapping of sm and queues to output python + IdMap smMap, qMap; + // Items still in queue, used for sanity checking + std::vector<AnnotateList> qData; + + void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi, + int count); + void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi, + int count); + + void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame); + + // Turn a system id, state machine string, state machine id into a small int + // for annotation output + int + getSm(int sysi, std::string si, uint64_t id) + { + int smi; + Id smid = Id(si, id); + + smi = smCache[sysi-1][smid]; + if (smi == 0) { + smCache[sysi-1][smid] = smi = ++numSm; + assert(smi < 65535); + smMap.push_back(std::make_pair<int, Id>(sysi, smid)); + } + return smi; + } + + // Turn a state machine string, state string into a small int + // for annotation output + int + getSt(std::string sm, std::string s) + { + int sti, smi; + + smi = smtCache[sm]; + if (smi == 0) + smi = smtCache[sm] = ++numSmt; + + while (stCache.size() < smi) { + //stCache.resize(sm); + stCache.push_back(SCache()); + numSt.push_back(0); + } + //assert(stCache.size() == sm); + //assert(numSt.size() == sm); + sti = stCache[smi-1][s]; + if (sti == 0) + stCache[smi-1][s] = sti = ++numSt[smi-1]; + return sti; + } + + // Turn state machine pointer into a smal int for annotation output + int + getSys(System *s) + { + NameCache::iterator i = nameCache.find(s); + if (i == nameCache.end()) { + nameCache[s] = std::make_pair<std::string,int>(s->name(), ++numSys); + i = nameCache.find(s); + // might need to put smstackid into map here, but perhaps not + //smStack.push_back(std::vector<int>()); + //swExpl.push_back(false); + numQ.push_back(0); + qCache.push_back(IdHCache()); + smCache.push_back(IdHCache()); + scLinks.push_back(ScHCache()); + } + return i->second.second; + } + + // Turn queue name, and queue context into small int for + // annotation output + int + getQ(int sys, std::string q, uint64_t id) + { + int qi; + Id qid = Id(q, id); + + qi = qCache[sys-1][qid]; + if (qi == 0) { + qi = qCache[sys-1][qid] = ++numQs; + assert(qi < 65535); + qSize.push_back(0); + qBytes.push_back(0); + qData.push_back(AnnotateList()); + numQ[sys-1]++; + qMap.push_back(std::make_pair<int, Id>(sys, qid)); + } + return qi; + } + + void swBegin(System *sys, int cpuid, std::string st, uint64_t frame, + bool expl = false, int flags = FL_NONE); + + AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0); + + std::ostream *osbin; + + bool _enabled; + + /** Only allow one CPA object in a system. It doesn't make sense to have + * more that one per simulation because if a part of the system was + * important it would have annotations and queues, and with more than one + * object none of the sanity checking for queues will work. */ + static bool exists; + static CPA *_cpa; + + + std::map<std::string, SymbolTable*> userApp; + + public: + static CPA *cpa() { return _cpa; } + void swSmBegin(ThreadContext *tc); + void swSmEnd(ThreadContext *tc); + void swExplictBegin(ThreadContext *tc); + void swAutoBegin(ThreadContext *tc, Addr next_pc); + void swEnd(ThreadContext *tc); + void swQ(ThreadContext *tc); + void swDq(ThreadContext *tc); + void swPq(ThreadContext *tc); + void swRq(ThreadContext *tc); + void swWf(ThreadContext *tc); + void swWe(ThreadContext *tc); + void swSq(ThreadContext *tc); + void swAq(ThreadContext *tc); + void swLink(ThreadContext *tc); + void swIdentify(ThreadContext *tc); + uint64_t swGetId(ThreadContext *tc); + void swSyscallLink(ThreadContext *tc); + + inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm, + std::string st) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int smi = getSm(sysi, sm, frame); + add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st)); + if (f & FL_BAD) + warn("BAD state encountered: at cycle %d: %s\n", curTick, st); + } + + inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + DPRINTFS(AnnotateQ, sys, + "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n", + q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count); + + } + + inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + DPRINTFS(AnnotateQ, sys, + "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n", + q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count); + } + + inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + DPRINTFS(AnnotateQ, sys, + "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n", + q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); + } + + inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + DPRINTFS(AnnotateQ, sys, + "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n", + q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count); + add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); + } + + inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); + } + + inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm, + std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1) + { + if (!enabled()) + return; + + int sysi = getSys(sys); + int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid); + add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count); + } + + public: + CPA(Params *p); + void startup(); + + // This code is ISA specific and will need to be changed + // if the annotation code is used for something other than Alpha + inline uint64_t getFrame(ThreadContext *tc) + { return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) & + ~ULL(0x3FFF)); } + + static bool available() { return true; } + + bool + enabled() + { + if (!this) + return false; + return _enabled; + } + + void dump(bool all); + void dumpKey(); + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + +}; +#endif // !CP_ANNOTATE + +#endif //__BASE__CP_ANNOTATE_HH__ + diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc index d4ba9ca21..5c11e501c 100644 --- a/src/base/cprintf.cc +++ b/src/base/cprintf.cc @@ -40,7 +40,7 @@ using namespace std; namespace cp { Print::Print(std::ostream &stream, const std::string &format) - : stream(stream), format(format.c_str()), ptr(format.c_str()) + : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false) { saved_flags = stream.flags(); saved_fill = stream.fill(); @@ -48,7 +48,7 @@ Print::Print(std::ostream &stream, const std::string &format) } Print::Print(std::ostream &stream, const char *format) - : stream(stream), format(format), ptr(format) + : stream(stream), format(format), ptr(format), cont(false) { saved_flags = stream.flags(); saved_fill = stream.fill(); @@ -60,8 +60,10 @@ Print::~Print() } void -Print::process(Format &fmt) +Print::process() { + fmt.clear(); + size_t len; while (*ptr) { @@ -221,8 +223,15 @@ Print::process(Format &fmt) number = number * 10 + (*ptr - '0'); break; + case '*': + if (have_precision) + fmt.get_precision = true; + else + fmt.get_width = true; + break; + case '%': - assert("we shouldn't get here"); + assert(false && "we shouldn't get here"); break; default: diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh index cff73a228..2920e210d 100644 --- a/src/base/cprintf.hh +++ b/src/base/cprintf.hh @@ -51,24 +51,53 @@ struct Print std::ostream &stream; const char *format; const char *ptr; + bool cont; std::ios::fmtflags saved_flags; char saved_fill; int saved_precision; - void process(Format &fmt); + Format fmt; + void process(); public: Print(std::ostream &stream, const std::string &format); Print(std::ostream &stream, const char *format); ~Print(); + int + get_number(int data) + { + return data; + } + + template <typename T> + int + get_number(const T& data) + { + return 0; + } + template <typename T> void add_arg(const T &data) { - Format fmt; - process(fmt); + if (!cont) + process(); + + if (fmt.get_width) { + fmt.get_width = false; + cont = true; + fmt.width = get_number(data); + return; + } + + if (fmt.get_precision) { + fmt.get_precision = false; + cont = true; + fmt.precision = get_number(data); + return; + } switch (fmt.format) { case Format::character: diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh index 4e8b2b09e..6bf6b2b66 100644 --- a/src/base/cprintf_formats.hh +++ b/src/base/cprintf_formats.hh @@ -31,8 +31,9 @@ #ifndef __BASE_CPRINTF_FORMATS_HH__ #define __BASE_CPRINTF_FORMATS_HH__ -#include <sstream> +#include <cstring> #include <ostream> +#include <sstream> namespace cp { @@ -49,6 +50,8 @@ struct Format enum { best, fixed, scientific } float_format; int precision; int width; + bool get_precision; + bool get_width; Format() { clear(); } @@ -64,6 +67,8 @@ struct Format format = none; precision = -1; width = 0; + get_precision = false; + get_width = false; } }; diff --git a/src/base/crc.cc b/src/base/crc.cc index 08f039577..ce837a408 100644 --- a/src/base/crc.cc +++ b/src/base/crc.cc @@ -1,6 +1,6 @@ /* * Copyright (c) 1988, 1992, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,8 +12,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. diff --git a/src/unittest/tracetest.cc b/src/base/debug.cc index b1343aac3..de201af18 100644 --- a/src/unittest/tracetest.cc +++ b/src/base/debug.cc @@ -28,29 +28,18 @@ * Authors: Nathan Binkert */ -#include "sim/host.hh" -#include "base/trace.hh" +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> -using namespace std; +#include "base/cprintf.hh" -Tick curTick = 0; - -struct foo -{ - foo() - { - char foo[9] = "testing"; - DPRINTF(Loader, "%s\n", foo); - } -}; - -int -main() +void +debug_break() { - Trace::flags[Trace::Loader] = true; - Trace::dprintf_stream = &cout; - - foo f; - - return 0; +#ifndef NDEBUG + kill(getpid(), SIGTRAP); +#else + cprintf("debug_break suppressed, compiled with NDEBUG\n"); +#endif } diff --git a/src/python/swig/init.hh b/src/base/debug.hh index 23d2c19a9..b1577f782 100644 --- a/src/python/swig/init.hh +++ b/src/base/debug.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2003-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,9 +28,9 @@ * Authors: Nathan Binkert */ -#ifndef __PYTHON_SWIG_INIT_HH__ -#define __PYTHON_SWIG_INIT_HH__ +#ifndef __BASE_DEBUG_HH__ +#define __BASE_DEBUG_HH__ -void init_swig(); +void debug_break(); -#endif // __PYTHON_SWIG_INIT_HH__ +#endif // __BASE_DEBUG_HH__ diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc index e1298a8bd..a91a99d20 100644 --- a/src/base/fast_alloc.cc +++ b/src/base/fast_alloc.cc @@ -34,7 +34,8 @@ * by permission. */ -#include <assert.h> +#include <cassert> + #include "base/fast_alloc.hh" #if !NO_FAST_ALLOC @@ -45,21 +46,22 @@ void *FastAlloc::freeLists[Num_Buckets]; -#ifdef FAST_ALLOC_STATS +#if FAST_ALLOC_STATS unsigned FastAlloc::newCount[Num_Buckets]; unsigned FastAlloc::deleteCount[Num_Buckets]; unsigned FastAlloc::allocCount[Num_Buckets]; #endif -void *FastAlloc::moreStructs(int bucket) +void * +FastAlloc::moreStructs(int bucket) { assert(bucket > 0 && bucket < Num_Buckets); int sz = bucket * Alloc_Quantum; - const int nstructs = Num_Structs_Per_New; // how many to allocate? + const int nstructs = Num_Structs_Per_New; // how many to allocate? char *p = ::new char[nstructs * sz]; -#ifdef FAST_ALLOC_STATS +#if FAST_ALLOC_STATS ++allocCount[bucket]; #endif @@ -71,14 +73,13 @@ void *FastAlloc::moreStructs(int bucket) return (p + sz); } +#if FAST_ALLOC_DEBUG -#ifdef FAST_ALLOC_DEBUG - -#include <typeinfo> -#include <iostream> #include <iomanip> +#include <iostream> #include <map> #include <string> +#include <typeinfo> using namespace std; @@ -97,7 +98,6 @@ FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next) inUseNext = next; } - // constructor: marks as in use, add to in-use list FastAlloc::FastAlloc() { @@ -131,7 +131,6 @@ FastAlloc::~FastAlloc() inUseNext->inUsePrev = inUsePrev; } - // summarize in-use list void FastAlloc::dump_summary() @@ -148,48 +147,43 @@ FastAlloc::dump_summary() cout << " count type\n" << " ----- ----\n"; for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter) - { cout << setw(6) << mapiter->second << " " << mapiter->first << endl; - } } - // show oldest n items on in-use list void FastAlloc::dump_oldest(int n) { // sanity check: don't want to crash the debugger if you forget to // pass in a parameter - if (n < 0 || n > numInUse) - { + if (n < 0 || n > numInUse) { cout << "FastAlloc::dump_oldest: bad arg " << n << " (" << numInUse << " objects in use" << endl; return; } - for (FastAlloc *p = inUseHead.inUsePrev; + for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead && n > 0; - p = p->inUsePrev, --n) - { + p = p->inUseNext, --n) cout << p << " " << typeid(*p).name() << endl; - } } - // // C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest(). // gdb seems to have trouble with calling C++ functions directly. // +void fast_alloc_summary() { FastAlloc::dump_summary(); } +void fast_alloc_oldest(int n) { FastAlloc::dump_oldest(n); } -#endif +#endif // FAST_ALLOC_DEBUG #endif // NO_FAST_ALLOC diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh index 3e22e59c1..775c93d50 100644 --- a/src/base/fast_alloc.hh +++ b/src/base/fast_alloc.hh @@ -34,10 +34,10 @@ * by permission. */ -#ifndef __FAST_ALLOC_H__ -#define __FAST_ALLOC_H__ +#ifndef __BASE_FAST_ALLOC_HH__ +#define __BASE_FAST_ALLOC_HH__ -#include <stddef.h> +#include <cstddef> // Fast structure allocator. Designed for small objects that are // frequently allocated and deallocated. This code is derived from the @@ -62,35 +62,30 @@ // collapse the destructor call chain back up the inheritance // hierarchy. -// Uncomment this #define to track in-use objects -// (for debugging memory leaks). -//#define FAST_ALLOC_DEBUG - -// Uncomment this #define to count news, deletes, and chunk allocations -// (by bucket). -// #define FAST_ALLOC_STATS - #include "config/no_fast_alloc.hh" +#include "config/fast_alloc_debug.hh" +#include "config/fast_alloc_stats.hh" #if NO_FAST_ALLOC -class FastAlloc { +class FastAlloc +{ }; #else -class FastAlloc { +class FastAlloc +{ public: - static void *allocate(size_t); static void deallocate(void *, size_t); void *operator new(size_t); void operator delete(void *, size_t); -#ifdef FAST_ALLOC_DEBUG +#if FAST_ALLOC_DEBUG FastAlloc(); - FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below + FastAlloc(FastAlloc *, FastAlloc *); // for inUseHead, see below virtual ~FastAlloc(); #else virtual ~FastAlloc() {} @@ -121,21 +116,21 @@ class FastAlloc { static void *freeLists[Num_Buckets]; -#ifdef FAST_ALLOC_STATS +#if FAST_ALLOC_STATS static unsigned newCount[Num_Buckets]; static unsigned deleteCount[Num_Buckets]; static unsigned allocCount[Num_Buckets]; #endif -#ifdef FAST_ALLOC_DEBUG +#if FAST_ALLOC_DEBUG // per-object debugging fields - bool inUse; // in-use flag - FastAlloc *inUsePrev; // ptrs to build list of in-use objects + bool inUse; // in-use flag + FastAlloc *inUsePrev; // ptrs to build list of in-use objects FastAlloc *inUseNext; // static (global) debugging vars - static int numInUse; // count in-use objects - static FastAlloc inUseHead; // dummy head for list of in-use objects + static int numInUse; // count in-use objects + static FastAlloc inUseHead; // dummy head for list of in-use objects public: // functions to dump debugging info (see fast_alloc.cc for C @@ -145,16 +140,14 @@ class FastAlloc { #endif }; - -inline -int FastAlloc::bucketFor(size_t sz) +inline int +FastAlloc::bucketFor(size_t sz) { return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum; } - -inline -void *FastAlloc::allocate(size_t sz) +inline void * +FastAlloc::allocate(size_t sz) { int b; void *p; @@ -170,21 +163,19 @@ void *FastAlloc::allocate(size_t sz) else p = moreStructs(b); -#ifdef FAST_ALLOC_STATS +#if FAST_ALLOC_STATS ++newCount[b]; #endif return p; } - -inline -void FastAlloc::deallocate(void *p, size_t sz) +inline void +FastAlloc::deallocate(void *p, size_t sz) { int b; - if (sz > Max_Alloc_Size) - { + if (sz > Max_Alloc_Size) { ::delete [] (char *)p; return; } @@ -192,25 +183,23 @@ void FastAlloc::deallocate(void *p, size_t sz) b = bucketFor(sz); *(void **)p = freeLists[b]; freeLists[b] = p; -#ifdef FAST_ALLOC_STATS +#if FAST_ALLOC_STATS ++deleteCount[b]; #endif } - -inline -void *FastAlloc::operator new(size_t sz) +inline void * +FastAlloc::operator new(size_t sz) { return allocate(sz); } - -inline -void FastAlloc::operator delete(void *p, size_t sz) +inline void +FastAlloc::operator delete(void *p, size_t sz) { deallocate(p, sz); } #endif // NO_FAST_ALLOC -#endif // __FAST_ALLOC_H__ +#endif // __BASE_FAST_ALLOC_HH__ diff --git a/src/base/flags.hh b/src/base/flags.hh new file mode 100644 index 000000000..2e0506391 --- /dev/null +++ b/src/base/flags.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_FLAGS_HH__ +#define __BASE_FLAGS_HH__ + +template <typename T> +class Flags +{ + private: + T _flags; + + public: + typedef T Type; + Flags() : _flags(0) {} + Flags(Type flags) : _flags(flags) {} + + operator const Type() const { return _flags; } + + template <typename U> + const Flags<T> & + operator=(const Flags<U> &flags) + { + _flags = flags._flags; + return *this; + } + + const Flags<T> & + operator=(T flags) + { + _flags = flags; + return *this; + } + + bool isSet() const { return _flags; } + bool isSet(Type flags) const { return (_flags & flags); } + bool allSet() const { return !(~_flags); } + bool allSet(Type flags) const { return (_flags & flags) == flags; } + bool noneSet() const { return _flags == 0; } + bool noneSet(Type flags) const { return (_flags & flags) == 0; } + void clear() { _flags = 0; } + void clear(Type flags) { _flags &= ~flags; } + void set(Type flags) { _flags |= flags; } + void set(Type f, bool val) { _flags = (_flags & ~f) | (val ? f : 0); } + void + update(Type flags, Type mask) + { + _flags = (_flags & ~mask) | (flags & mask); + } +}; + +#endif // __BASE_FLAGS_HH__ diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh index f8d799780..ff2aa151f 100644 --- a/src/base/hashmap.hh +++ b/src/base/hashmap.hh @@ -81,6 +81,16 @@ namespace __hash_namespace { return(__stl_hash_string(s.c_str())); } }; + + template <> + struct hash<std::pair<std::string, uint64_t> > { + size_t operator() (std::pair<std::string, uint64_t> r) const { + return (__stl_hash_string(r.first.c_str())) ^ r.second; + } + }; + + + } diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh index cb1d6003b..5e478553b 100644 --- a/src/base/hybrid_pred.hh +++ b/src/base/hybrid_pred.hh @@ -62,12 +62,12 @@ class HybridPredictor : public GenericPredictor // // Stats // - Stats::Scalar<> pred_one; //num_one_preds - Stats::Scalar<> pred_zero; //num_zero_preds - Stats::Scalar<> correct_pred_one; //num_one_correct - Stats::Scalar<> correct_pred_zero; //num_zero_correct - Stats::Scalar<> record_one; //num_one_updates - Stats::Scalar<> record_zero; //num_zero_updates + Stats::Scalar pred_one; //num_one_preds + Stats::Scalar pred_zero; //num_zero_preds + Stats::Scalar correct_pred_one; //num_one_correct + Stats::Scalar correct_pred_zero; //num_zero_correct + Stats::Scalar record_one; //num_one_updates + Stats::Scalar record_zero; //num_zero_updates Stats::Formula total_preds; Stats::Formula frac_preds_zero; diff --git a/src/base/inet.cc b/src/base/inet.cc index b8da12a99..8c3240fa6 100644 --- a/src/base/inet.cc +++ b/src/base/inet.cc @@ -206,4 +206,25 @@ TcpOpt::sack(vector<SackRange> &vec) const return false; } +int +hsplit(const EthPacketPtr &ptr) +{ + int split_point = 0; + + IpPtr ip(ptr); + if (ip) { + split_point = ip.pstart(); + + TcpPtr tcp(ip); + if (tcp) + split_point = tcp.pstart(); + + UdpPtr udp(ip); + if (udp) + split_point = udp.pstart(); + } + return split_point; +} + + /* namespace Net */ } diff --git a/src/base/inet.hh b/src/base/inet.hh index 1bf7c585f..59b05291d 100644 --- a/src/base/inet.hh +++ b/src/base/inet.hh @@ -140,6 +140,8 @@ class EthPtr EthPacketPtr packet() { return p; } bool operator!() const { return !p; } operator bool() const { return p; } + int off() const { return 0; } + int pstart() const { return off() + ((const EthHdr*)p->data)->size(); } }; /* @@ -162,6 +164,9 @@ struct IpHdr : public ip_hdr uint32_t dst() const { return ntohl(ip_dst); } void sum(uint16_t sum) { ip_sum = sum; } + void id(uint16_t _id) { ip_id = htons(_id); } + void len(uint16_t _len) { ip_len = htons(_len); } + bool options(std::vector<const IpOpt *> &vec) const; @@ -179,32 +184,31 @@ class IpPtr friend class UdpPtr; EthPacketPtr p; - const IpHdr *h() const - { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } - IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } - void set(const EthPacketPtr &ptr) { - EthHdr *eth = (EthHdr *)ptr->data; - if (eth->type() == ETH_TYPE_IP) - p = ptr; - else - p = 0; + p = 0; + + if (ptr) { + EthHdr *eth = (EthHdr *)ptr->data; + if (eth->type() == ETH_TYPE_IP) + p = ptr; + } } public: - IpPtr() {} - IpPtr(const EthPacketPtr &ptr) { set(ptr); } - IpPtr(const EthPtr &ptr) { set(ptr.p); } + IpPtr() : p(0) {} + IpPtr(const EthPacketPtr &ptr) : p(0) { set(ptr); } + IpPtr(const EthPtr &ptr) : p(0) { set(ptr.p); } IpPtr(const IpPtr &ptr) : p(ptr.p) { } - IpHdr *operator->() { return h(); } - IpHdr &operator*() { return *h(); } - operator IpHdr *() { return h(); } + IpHdr *get() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } + IpHdr *operator->() { return get(); } + IpHdr &operator*() { return *get(); } - const IpHdr *operator->() const { return h(); } - const IpHdr &operator*() const { return *h(); } - operator const IpHdr *() const { return h(); } + const IpHdr *get() const + { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } + const IpHdr *operator->() const { return get(); } + const IpHdr &operator*() const { return *get(); } const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; } const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } @@ -214,7 +218,8 @@ class IpPtr EthPacketPtr packet() { return p; } bool operator!() const { return !p; } operator bool() const { return p; } - operator bool() { return p; } + int off() const { return sizeof(eth_hdr); } + int pstart() const { return off() + get()->size(); } }; uint16_t cksum(const IpPtr &ptr); @@ -262,6 +267,8 @@ struct TcpHdr : public tcp_hdr uint16_t urp() const { return ntohs(th_urp); } void sum(uint16_t sum) { th_sum = sum; } + void seq(uint32_t _seq) { th_seq = htonl(_seq); } + void flags(uint8_t _flags) { th_flags = _flags; } bool options(std::vector<const TcpOpt *> &vec) const; @@ -276,41 +283,39 @@ class TcpPtr { protected: EthPacketPtr p; - int off; - - const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } - TcpHdr *h() { return (TcpHdr *)(p->data + off); } + int _off; - void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const EthPacketPtr &ptr, int offset) { p = ptr; _off = offset; } void set(const IpPtr &ptr) { - if (ptr->proto() == IP_PROTO_TCP) + if (ptr && ptr->proto() == IP_PROTO_TCP) set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); else set(0, 0); } public: - TcpPtr() {} - TcpPtr(const IpPtr &ptr) { set(ptr); } - TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} + TcpPtr() : p(0), _off(0) {} + TcpPtr(const IpPtr &ptr) : p(0), _off(0) { set(ptr); } + TcpPtr(const TcpPtr &ptr) : p(ptr.p), _off(ptr._off) {} - TcpHdr *operator->() { return h(); } - TcpHdr &operator*() { return *h(); } - operator TcpHdr *() { return h(); } + TcpHdr *get() { return (TcpHdr *)(p->data + _off); } + TcpHdr *operator->() { return get(); } + TcpHdr &operator*() { return *get(); } - const TcpHdr *operator->() const { return h(); } - const TcpHdr &operator*() const { return *h(); } - operator const TcpHdr *() const { return h(); } + const TcpHdr *get() const { return (const TcpHdr *)(p->data + _off); } + const TcpHdr *operator->() const { return get(); } + const TcpHdr &operator*() const { return *get(); } const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } + const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t._off); return *this; } const EthPacketPtr packet() const { return p; } EthPacketPtr packet() { return p; } bool operator!() const { return !p; } operator bool() const { return p; } - operator bool() { return p; } + int off() const { return _off; } + int pstart() const { return off() + get()->size(); } }; uint16_t cksum(const TcpPtr &ptr); @@ -354,6 +359,7 @@ struct UdpHdr : public udp_hdr uint16_t sum() const { return uh_sum; } void sum(uint16_t sum) { uh_sum = sum; } + void len(uint16_t _len) { uh_ulen = htons(_len); } int size() const { return sizeof(udp_hdr); } const uint8_t *bytes() const { return (const uint8_t *)this; } @@ -366,45 +372,45 @@ class UdpPtr { protected: EthPacketPtr p; - int off; + int _off; - const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } - UdpHdr *h() { return (UdpHdr *)(p->data + off); } - - void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const EthPacketPtr &ptr, int offset) { p = ptr; _off = offset; } void set(const IpPtr &ptr) { - if (ptr->proto() == IP_PROTO_UDP) + if (ptr && ptr->proto() == IP_PROTO_UDP) set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); else set(0, 0); } public: - UdpPtr() {} - UdpPtr(const IpPtr &ptr) { set(ptr); } - UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} + UdpPtr() : p(0), _off(0) {} + UdpPtr(const IpPtr &ptr) : p(0), _off(0) { set(ptr); } + UdpPtr(const UdpPtr &ptr) : p(ptr.p), _off(ptr._off) {} - UdpHdr *operator->() { return h(); } - UdpHdr &operator*() { return *h(); } - operator UdpHdr *() { return h(); } + UdpHdr *get() { return (UdpHdr *)(p->data + _off); } + UdpHdr *operator->() { return get(); } + UdpHdr &operator*() { return *get(); } - const UdpHdr *operator->() const { return h(); } - const UdpHdr &operator*() const { return *h(); } - operator const UdpHdr *() const { return h(); } + const UdpHdr *get() const { return (const UdpHdr *)(p->data + _off); } + const UdpHdr *operator->() const { return get(); } + const UdpHdr &operator*() const { return *get(); } const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } + const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t._off); return *this; } const EthPacketPtr packet() const { return p; } EthPacketPtr packet() { return p; } bool operator!() const { return !p; } operator bool() const { return p; } - operator bool() { return p; } + int off() const { return _off; } + int pstart() const { return off() + get()->size(); } }; uint16_t cksum(const UdpPtr &ptr); +int hsplit(const EthPacketPtr &ptr); + /* namespace Net */ } #endif // __BASE_INET_HH__ diff --git a/src/base/inifile.cc b/src/base/inifile.cc index 809cbe172..24d0013c4 100644 --- a/src/base/inifile.cc +++ b/src/base/inifile.cc @@ -29,22 +29,8 @@ * Steve Reinhardt */ -#define USE_CPP - -#ifdef USE_CPP -#include <sys/signal.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <libgen.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#endif - #include <fstream> #include <iostream> - #include <vector> #include <string> @@ -67,103 +53,6 @@ IniFile::~IniFile() } } - -#ifdef USE_CPP -bool -IniFile::loadCPP(const string &file, vector<char *> &cppArgs) -{ - // Open the file just to verify that we can. Otherwise if the - // file doesn't exist or has bad permissions the user will get - // confusing errors from cpp/g++. - ifstream tmpf(file.c_str()); - - if (!tmpf.is_open()) - return false; - - tmpf.close(); - - char *cfile = strncpy(new char[file.size() + 1], file.c_str(), - file.size()); - char *dir = dirname(cfile); - char *dir_arg = NULL; - if (*dir != '.') { - string arg = "-I"; - arg += dir; - - dir_arg = new char[arg.size() + 1]; - strncpy(dir_arg, arg.c_str(), arg.size()); - } - - delete [] cfile; - - char tempfile[] = "/tmp/configXXXXXX"; - int tmp_fd = mkstemp(tempfile); - - int pid = fork(); - - if (pid == -1) - return false; - - if (pid == 0) { - char filename[FILENAME_MAX]; - string::size_type i = file.copy(filename, sizeof(filename) - 1); - filename[i] = '\0'; - - int arg_count = cppArgs.size(); - - const char **args = new const char *[arg_count + 20]; - - int nextArg = 0; - args[nextArg++] = "g++"; - args[nextArg++] = "-E"; - args[nextArg++] = "-P"; - args[nextArg++] = "-nostdinc"; - args[nextArg++] = "-nostdinc++"; - args[nextArg++] = "-x"; - args[nextArg++] = "c++"; - args[nextArg++] = "-undef"; - - for (int i = 0; i < arg_count; i++) - args[nextArg++] = cppArgs[i]; - - if (dir_arg) - args[nextArg++] = dir_arg; - - args[nextArg++] = filename; - args[nextArg++] = NULL; - - close(STDOUT_FILENO); - if (dup2(tmp_fd, STDOUT_FILENO) == -1) - exit(1); - - // execvp signature is intentionally broken wrt const-ness for - // backwards compatibility... see man page - execvp("g++", const_cast<char * const *>(args)); - - exit(0); - } - - int retval; - waitpid(pid, &retval, 0); - - delete [] dir_arg; - - // check for normal completion of CPP - if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) - return false; - - close(tmp_fd); - - bool status = false; - - status = load(tempfile); - - unlink(tempfile); - - return status; -} -#endif - bool IniFile::load(const string &file) { diff --git a/src/base/inifile.hh b/src/base/inifile.hh index 631b29b87..83cf80cf0 100644 --- a/src/base/inifile.hh +++ b/src/base/inifile.hh @@ -61,8 +61,8 @@ class IniFile /// class Entry { - std::string value; ///< The entry value. - mutable bool referenced; ///< Has this entry been used? + std::string value; ///< The entry value. + mutable bool referenced; ///< Has this entry been used? public: /// Constructor. @@ -96,8 +96,8 @@ class IniFile /// EntryTable type. Map of strings to Entry object pointers. typedef m5::hash_map<std::string, Entry *> EntryTable; - EntryTable table; ///< Table of entries. - mutable bool referenced; ///< Has this section been used? + EntryTable table; ///< Table of entries. + mutable bool referenced; ///< Has this section been used? public: /// Constructor. @@ -167,14 +167,6 @@ class IniFile /// @retval True if successful, false if errors were encountered. bool load(std::istream &f); - /// Load the specified file, passing it through the C preprocessor. - /// Parameter settings found in the file will be merged with any - /// already defined in this object. - /// @param file The path of the file to load. - /// @param cppFlags Vector of extra flags to pass to cpp. - /// @retval True if successful, false if errors were encountered. - bool loadCPP(const std::string &file, std::vector<char *> &cppFlags); - /// Load the specified file. /// Parameter settings found in the file will be merged with any /// already defined in this object. diff --git a/src/base/intmath.hh b/src/base/intmath.hh index 227012e30..c536fda51 100644 --- a/src/base/intmath.hh +++ b/src/base/intmath.hh @@ -197,9 +197,9 @@ roundDown(T val, int align) inline bool isHex(char c) { - return c >= '0' && c <= '9' || - c >= 'A' && c <= 'F' || - c >= 'a' && c <= 'f'; + return (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); } inline bool diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc index 8fbad8030..1412adfc3 100644 --- a/src/base/loader/aout_object.cc +++ b/src/base/loader/aout_object.cc @@ -34,7 +34,7 @@ #include "base/loader/symtab.hh" -#include "base/trace.hh" // for DPRINTF +#include "base/trace.hh" // for DPRINTF #include "base/loader/exec_aout.h" diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h index 4c6540395..be0631141 100644 --- a/src/base/loader/coff_sym.h +++ b/src/base/loader/coff_sym.h @@ -65,7 +65,7 @@ * * Symbols are assumed to be in 'encounter order' - i.e. the order that * the things they represent were encountered by the compiler/assembler/loader. - * EXCEPT for globals! These are assumed to be bunched together, + * EXCEPT for globals! These are assumed to be bunched together, * probably right after the last 'normal' symbol. Globals ARE sorted * in ascending order. * @@ -76,13 +76,13 @@ * All "ifooMax" values are the highest legal value PLUS ONE. This makes * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". * - * "isym" Index into the SYMbol table. - * "ipd" Index into the Procedure Descriptor array. - * "ifd" Index into the File Descriptor array. - * "iss" Index into String Space. - * "cb" Count of Bytes. - * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. - * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. */ @@ -97,31 +97,31 @@ */ typedef struct ecoff_symhdr { - coff_short magic; /* to verify validity of the table */ - coff_short vstamp; /* version stamp */ - coff_int ilineMax; /* number of line number entries */ - coff_int idnMax; /* max index into dense number table */ - coff_int ipdMax; /* number of procedures */ - coff_int isymMax; /* number of local symbols */ - coff_int ioptMax; /* max index into optimization symbol entries */ - coff_int iauxMax; /* number of auxillary symbol entries */ - coff_int issMax; /* max index into local strings */ - coff_int issExtMax; /* max index into external strings */ - coff_int ifdMax; /* number of file descriptor entries */ - coff_int crfd; /* number of relative file descriptor entries */ - coff_int iextMax; /* max index into external symbols */ - coff_addr cbLine; /* number of bytes for line number entries */ - coff_addr cbLineOffset; /* offset to start of line number entries*/ - coff_addr cbDnOffset; /* offset to start dense number table */ - coff_addr cbPdOffset; /* offset to procedure descriptor table */ - coff_addr cbSymOffset; /* offset to start of local symbols*/ - coff_addr cbOptOffset; /* offset to optimization symbol entries */ - coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ - coff_addr cbSsOffset; /* offset to start of local strings */ - coff_addr cbSsExtOffset; /* offset to start of external strings */ - coff_addr cbFdOffset; /* offset to file descriptor table */ - coff_addr cbRfdOffset; /* offset to relative file descriptor table */ - coff_addr cbExtOffset; /* offset to start of external symbol entries*/ + coff_short magic; /* to verify validity of the table */ + coff_short vstamp; /* version stamp */ + coff_int ilineMax; /* number of line number entries */ + coff_int idnMax; /* max index into dense number table */ + coff_int ipdMax; /* number of procedures */ + coff_int isymMax; /* number of local symbols */ + coff_int ioptMax; /* max index into optimization symbol entries */ + coff_int iauxMax; /* number of auxillary symbol entries */ + coff_int issMax; /* max index into local strings */ + coff_int issExtMax; /* max index into external strings */ + coff_int ifdMax; /* number of file descriptor entries */ + coff_int crfd; /* number of relative file descriptor entries */ + coff_int iextMax; /* max index into external symbols */ + coff_addr cbLine; /* number of bytes for line number entries */ + coff_addr cbLineOffset; /* offset to start of line number entries*/ + coff_addr cbDnOffset; /* offset to start dense number table */ + coff_addr cbPdOffset; /* offset to procedure descriptor table */ + coff_addr cbSymOffset; /* offset to start of local symbols*/ + coff_addr cbOptOffset; /* offset to optimization symbol entries */ + coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ + coff_addr cbSsOffset; /* offset to start of local strings */ + coff_addr cbSsExtOffset; /* offset to start of external strings */ + coff_addr cbFdOffset; /* offset to file descriptor table */ + coff_addr cbRfdOffset; /* offset to relative file descriptor table */ + coff_addr cbExtOffset; /* offset to start of external symbol entries*/ /* If you add machine dependent fields, add them here */ } HDRR, *pHDRR; #define cbHDRR sizeof(HDRR) @@ -138,39 +138,39 @@ typedef struct ecoff_symhdr { * * There is one of these for EVERY FILE, whether compiled with * full debugging symbols or not. The name of a file should be - * the path name given to the compiler. This allows the user + * the path name given to the compiler. This allows the user * to simply specify the names of the directories where the COMPILES * were done, and we will be able to find their files. * A field whose comment starts with "R - " indicates that it will be * setup at runtime. */ typedef struct ecoff_fdr { - coff_addr adr; /* memory address of beginning of file */ - coff_addr cbLineOffset; /* byte offset from header for this file ln's */ - coff_addr cbLine; /* size of lines for this file */ - coff_addr cbSs; /* number of bytes in the ss */ - coff_int rss; /* file name (of source, if known) */ - coff_int issBase; /* file's string space */ - coff_int isymBase; /* beginning of symbols */ - coff_int csym; /* count file's of symbols */ - coff_int ilineBase; /* file's line symbols */ - coff_int cline; /* count of file's line symbols */ - coff_int ioptBase; /* file's optimization entries */ - coff_int copt; /* count of file's optimization entries */ - coff_int ipdFirst; /* start of procedures for this file */ - coff_int cpd; /* count of procedures for this file */ - coff_int iauxBase; /* file's auxiliary entries */ - coff_int caux; /* count of file's auxiliary entries */ - coff_int rfdBase; /* index into the file indirect table */ - coff_int crfd; /* count file indirect entries */ - unsigned lang: 5; /* language for this file */ - unsigned fMerge : 1; /* whether this file can be merged */ - unsigned fReadin : 1; /* true if it was read in (not just created) */ + coff_addr adr; /* memory address of beginning of file */ + coff_addr cbLineOffset; /* byte offset from header for this file ln's */ + coff_addr cbLine; /* size of lines for this file */ + coff_addr cbSs; /* number of bytes in the ss */ + coff_int rss; /* file name (of source, if known) */ + coff_int issBase; /* file's string space */ + coff_int isymBase; /* beginning of symbols */ + coff_int csym; /* count file's of symbols */ + coff_int ilineBase; /* file's line symbols */ + coff_int cline; /* count of file's line symbols */ + coff_int ioptBase; /* file's optimization entries */ + coff_int copt; /* count of file's optimization entries */ + coff_int ipdFirst; /* start of procedures for this file */ + coff_int cpd; /* count of procedures for this file */ + coff_int iauxBase; /* file's auxiliary entries */ + coff_int caux; /* count of file's auxiliary entries */ + coff_int rfdBase; /* index into the file indirect table */ + coff_int crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ - /* aux's will be in compile host's sex */ - unsigned glevel : 2; /* level this file was compiled with */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ unsigned reserved : 22; /* reserved for future use */ - coff_uint reserved2; + coff_uint reserved2; } FDR, *pFDR; #define cbFDR sizeof(FDR) #define fdNil ((pFDR)0) @@ -189,31 +189,31 @@ typedef struct ecoff_fdr { */ typedef struct pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ - coff_int isym; /* start of local symbol entries */ - coff_int iline; /* start of line number entries*/ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_int iopt; /* start of optimization symbol entries*/ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_int lnLow; /* lowest line in the procedure */ - coff_int lnHigh; /* highest line in the procedure */ + coff_addr adr; /* memory address of start of procedure */ + coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ + coff_int isym; /* start of local symbol entries */ + coff_int iline; /* start of line number entries*/ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_int iopt; /* start of optimization symbol entries*/ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_int lnLow; /* lowest line in the procedure */ + coff_int lnHigh; /* highest line in the procedure */ /* These fields are new for 64 bit ECOFF. */ unsigned gp_prologue : 8; /* byte size of GP prologue */ - unsigned gp_used : 1; /* true if the procedure uses GP */ - unsigned reg_frame : 1; /* true if register frame procedure */ - unsigned prof : 1; /* true if compiled with -pg */ - unsigned reserved : 13; /* reserved: must be zero */ - unsigned localoff : 8; /* offset of local variables from vfp */ - coff_short framereg; /* frame pointer register */ - coff_short pcreg; /* offset or reg of return pc */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned prof : 1; /* true if compiled with -pg */ + unsigned reserved : 13; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + coff_short framereg; /* frame pointer register */ + coff_short pcreg; /* offset or reg of return pc */ } PDR, *pPDR; #define cbPDR sizeof(PDR) #define pdNil ((pPDR) 0) -#define ipdNil -1 +#define ipdNil -1 /* * The structure of the runtime procedure descriptor created by the loader @@ -225,16 +225,16 @@ typedef struct pdr { */ #if 0 typedef struct runtime_pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_ushort framereg; /* frame pointer register */ - coff_ushort pcreg; /* offset or reg of return pc */ - coff_int irpss; /* index into the runtime string table */ - coff_uint reserved; + coff_addr adr; /* memory address of start of procedure */ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_ushort framereg; /* frame pointer register */ + coff_ushort pcreg; /* offset or reg of return pc */ + coff_int irpss; /* index into the runtime string table */ + coff_uint reserved; struct exception_info *exception_info;/* pointer to exception array */ } RPDR, *pRPDR; #define cbRPDR sizeof(RPDR) @@ -253,24 +253,24 @@ typedef struct runtime_pdr { * the first line of a procedure and represent the first address. */ -typedef coff_int LINER, *pLINER; +typedef coff_int LINER, *pLINER; #define lineNil ((pLINER)0) #define cbLINER sizeof(LINER) -#define ilineNil -1 +#define ilineNil -1 /* - * The Symbol Structure (GFW, to those who Know!) + * The Symbol Structure (GFW, to those who Know!) */ typedef struct ecoff_sym { - coff_long value; /* value of symbol */ - coff_int iss; /* index into String Space of name */ - unsigned st : 6; /* symbol type */ - unsigned sc : 5; /* storage class - text, data, etc */ - unsigned reserved : 1; /* reserved */ - unsigned index : 20; /* index into sym/aux table */ + coff_long value; /* value of symbol */ + coff_int iss; /* index into String Space of name */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ } SYMR, *pSYMR; #define symNil ((pSYMR)0) #define cbSYMR sizeof(SYMR) @@ -287,22 +287,22 @@ typedef struct ecoff_sym { /* E X T E R N A L S Y M B O L R E C O R D * - * Same as the SYMR except it contains file context to determine where - * the index is. + * Same as the SYMR except it contains file context to determine where + * the index is. */ typedef struct ecoff_extsym { - SYMR asym; /* symbol for the external */ - unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ - unsigned cobol_main:1; /* symbol is a cobol main procedure */ - unsigned weakext:1; /* symbol is weak external */ - unsigned reserved:29; /* reserved for future use */ - coff_int ifd; /* where the iss and index fields point into */ + SYMR asym; /* symbol for the external */ + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:29; /* reserved for future use */ + coff_int ifd; /* where the iss and index fields point into */ } EXTR, *pEXTR; #define extNil ((pEXTR)0) #define cbEXTR sizeof(EXTR) -/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ /* * Type Information Record @@ -310,12 +310,12 @@ typedef struct ecoff_extsym { typedef struct { unsigned fBitfield : 1; /* set if bit width is specified */ unsigned continued : 1; /* indicates additional TQ info in next AUX */ - unsigned bt : 6; /* basic type */ + unsigned bt : 6; /* basic type */ unsigned tq4 : 4; unsigned tq5 : 4; /* ---- 16 bit boundary ---- */ unsigned tq0 : 4; - unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ unsigned tq2 : 4; unsigned tq3 : 4; } TIR, *pTIR; @@ -327,22 +327,22 @@ typedef struct { * Relative symbol record * * If the rfd field is 4095, the index field indexes into the global symbol - * table. + * table. */ typedef struct { - unsigned rfd : 12; /* index into the file indirect table */ - unsigned index : 20; /* index int sym/aux/iss tables */ + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ } RNDXR, *pRNDXR; #define cbRNDXR sizeof(RNDXR) #define rndxNil ((pRNDXR)0) /* dense numbers or sometimes called block numbers are stored in this type, - * a rfd of 0xffffffff is an index into the global table. + * a rfd of 0xffffffff is an index into the global table. */ typedef struct { - coff_uint rfd; /* index into the file table */ - coff_uint index; /* index int sym/aux/iss tables */ + coff_uint rfd; /* index into the file table */ + coff_uint index; /* index int sym/aux/iss tables */ } DNR, *pDNR; #define cbDNR sizeof(DNR) #define dnNil ((pDNR)0) @@ -353,36 +353,36 @@ typedef struct { * Auxillary information occurs only if needed. * It ALWAYS occurs in this order when present. - isymMac used by stProc only - TIR type info - TIR additional TQ info (if first TIR was not enough) - rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, btTypedef): rsym.index == iaux for btSet or btRange else rsym.index == isym - dimLow btRange, btSet - dimMac btRange, btSet - rndx0 As many as there are tq arrays + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays dimLow0 dimHigh0 ... rndxMax-1 dimLowMax-1 dimHighMax-1 - width in bits if (bit field), width in bits. + width in bits if (bit field), width in bits. */ #define cAuxMax (6 + (idimMax*3)) /* a union of all possible info in the AUX universe */ typedef union { - TIR ti; /* type information record */ - RNDXR rndx; /* relative index into symbol table */ - coff_int dnLow; /* low dimension */ - coff_int dnHigh; /* high dimension */ - coff_int isym; /* symbol table index (end of proc) */ - coff_int iss; /* index into string space (not used) */ - coff_int width; /* width for non-default sized struc fields */ - coff_int count; /* count of ranges for variant arm */ + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + coff_int dnLow; /* low dimension */ + coff_int dnHigh; /* high dimension */ + coff_int isym; /* symbol table index (end of proc) */ + coff_int iss; /* index into string space (not used) */ + coff_int width; /* width for non-default sized struc fields */ + coff_int count; /* count of ranges for variant arm */ } AUXU, *pAUXU; #define cbAUXU sizeof(AUXU) #define auxNil ((pAUXU)0) @@ -401,12 +401,12 @@ typedef union { */ typedef struct { - unsigned ot: 8; /* optimization type */ - unsigned value: 24; /* address where we are moving it to */ - RNDXR rndx; /* points to a symbol or opt entry */ - coff_ulong offset; /* relative offset this occured */ + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + coff_ulong offset; /* relative offset this occured */ } OPTR, *pOPTR; -#define optNil ((pOPTR) 0) +#define optNil ((pOPTR) 0) #define cbOPTR sizeof(OPTR) #define ioptNil -1 @@ -414,15 +414,15 @@ typedef struct { * File Indirect * * When a symbol is referenced across files the following procedure is used: - * 1) use the file index to get the File indirect entry. - * 2) use the file indirect entry to get the File descriptor. - * 3) add the sym index to the base of that file's sym table + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table * */ typedef coff_long RFDT, *pRFDT; #define cbRFDT sizeof(RFDT) -#define rfdNil -1 +#define rfdNil -1 /* * The file indirect table in the mips loader is known as an array of FITs. @@ -430,9 +430,9 @@ typedef coff_long RFDT, *pRFDT; * these tables are merged. Note this is only a name change. */ typedef coff_int FIT, *pFIT; -#define cbFIT sizeof(FIT) -#define ifiNil -1 -#define fiNil ((pFIT) 0) +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) #ifdef _LANGUAGE_PASCAL #define ifdNil -1 @@ -448,18 +448,18 @@ typedef coff_int FIT, *pFIT; #define ioptNil -1 #define rfdNil -1 #define ifiNil -1 -#endif /* _LANGUAGE_PASCAL */ +#endif /* _LANGUAGE_PASCAL */ /* Dense numbers * * Rather than use file index, symbol index pairs to represent symbols - * and globals, we use dense number so that they can be easily embeded - * in intermediate code and the programs that process them can - * use direct access tabls instead of hash table (which would be - * necesary otherwise because of the sparse name space caused by - * file index, symbol index pairs. Dense number are represented - * by RNDXRs. + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. */ /* @@ -467,7 +467,7 @@ typedef coff_int FIT, *pFIT; * a function of the "st". (scD/B == scData OR scBss) * * Note: the value "isymMac" is used by symbols that have the concept - * of enclosing a block of related information. This value is the + * of enclosing a block of related information. This value is the * isym of the first symbol AFTER the end associated with the primary * symbol. For example if a procedure was at isym==90 and had an * isymMac==155, the associated end would be at isym==154, and the @@ -477,42 +477,42 @@ typedef coff_int FIT, *pFIT; * isym of the primary symbol that started the block. * -ST SC VALUE INDEX --------- ------ -------- ------ -stFile scText address isymMac -stLabel scText address --- -stGlobal scD/B address iaux -stStatic scD/B address iaux -stParam scAbs offset iaux -stLocal scAbs offset iaux -stProc scText address iaux (isymMac is first AUX) -stStaticProc scText address iaux (isymMac is first AUX) - -stMember scNil ordinal --- (if member of enum) +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) (mipsread thinks the case below has a bit, not byte, offset.) -stMember scNil byte offset iaux (if member of struct/union) -stMember scBits bit offset iaux (bit field spec) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) -stBlock scText address isymMac (text block) +stBlock scText address isymMac (text block) (the code seems to think that rather than scNil, we see scInfo for the two cases below.) -stBlock scNil cb isymMac (struct/union member define) -stBlock scNil cMembers isymMac (enum member define) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) (New types added by SGI to simplify things:) -stStruct scInfo cb isymMac (struct type define) -stUnion scInfo cb isymMac (union type define) -stEnum scInfo cMembers isymMac (enum type define) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) -stEnd scText address isymStart -stEnd scNil ------- isymStart (struct/union/enum) +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) -stTypedef scNil ------- iaux -stRegReloc sc??? value old register number -stForward sc??? new address isym to original symbol +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol -stConstant scInfo value --- (scalar) -stConstant scInfo iss --- (complex, e.g. string) +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) * */ diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h index f383c19e6..18529113f 100644 --- a/src/base/loader/coff_symconst.h +++ b/src/base/loader/coff_symconst.h @@ -59,30 +59,30 @@ */ /* glevels for field in FDR */ -#define GLEVEL_0 2 -#define GLEVEL_1 1 -#define GLEVEL_2 0 /* for upward compat reasons. */ -#define GLEVEL_3 3 +#define GLEVEL_0 2 +#define GLEVEL_1 1 +#define GLEVEL_2 0 /* for upward compat reasons. */ +#define GLEVEL_3 3 /* magic number fo symheader */ -#define magicSym 0x7009 +#define magicSym 0x7009 /* The Alpha uses this value instead, for some reason. */ -#define magicSym2 0x1992 +#define magicSym2 0x1992 /* Language codes */ -#define langC 0 -#define langPascal 1 -#define langFortran 2 -#define langAssembler 3 /* one Assembley inst might map to many mach */ -#define langMachine 4 -#define langNil 5 -#define langAda 6 -#define langPl1 7 -#define langCobol 8 -#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ -#define langCplusplus 9 /* FIXME: Collides with langStdc */ -#define langCplusplusV2 10 /* SGI addition */ -#define langMax 11 /* maximun allowed 32 -- 5 bits */ +#define langC 0 +#define langPascal 1 +#define langFortran 2 +#define langAssembler 3 /* one Assembley inst might map to many mach */ +#define langMachine 4 +#define langNil 5 +#define langAda 6 +#define langPl1 7 +#define langCobol 8 +#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ +#define langCplusplus 9 /* FIXME: Collides with langStdc */ +#define langCplusplusV2 10 /* SGI addition */ +#define langMax 11 /* maximun allowed 32 -- 5 bits */ /* The following are value definitions for the fields in the SYMR */ @@ -90,111 +90,111 @@ * Storage Classes */ -#define scNil 0 -#define scText 1 /* text symbol */ -#define scData 2 /* initialized data symbol */ -#define scBss 3 /* un-initialized data symbol */ -#define scRegister 4 /* value of symbol is register number */ -#define scAbs 5 /* value of symbol is absolute */ -#define scUndefined 6 /* who knows? */ -#define scCdbLocal 7 /* variable's value is IN se->va.?? */ -#define scBits 8 /* this is a bit field */ -#define scCdbSystem 9 /* variable's value is IN CDB's address space */ -#define scDbx 9 /* overlap dbx internal use */ -#define scRegImage 10 /* register value saved on stack */ -#define scInfo 11 /* symbol contains debugger information */ -#define scUserStruct 12 /* address in struct user for current process */ -#define scSData 13 /* load time only small data */ -#define scSBss 14 /* load time only small common */ -#define scRData 15 /* load time only read only data */ -#define scVar 16 /* Var parameter (fortran,pascal) */ -#define scCommon 17 /* common variable */ -#define scSCommon 18 /* small common */ -#define scVarRegister 19 /* Var parameter in a register */ -#define scVariant 20 /* Variant record */ -#define scSUndefined 21 /* small undefined(external) data */ -#define scInit 22 /* .init section symbol */ -#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ +#define scNil 0 +#define scText 1 /* text symbol */ +#define scData 2 /* initialized data symbol */ +#define scBss 3 /* un-initialized data symbol */ +#define scRegister 4 /* value of symbol is register number */ +#define scAbs 5 /* value of symbol is absolute */ +#define scUndefined 6 /* who knows? */ +#define scCdbLocal 7 /* variable's value is IN se->va.?? */ +#define scBits 8 /* this is a bit field */ +#define scCdbSystem 9 /* variable's value is IN CDB's address space */ +#define scDbx 9 /* overlap dbx internal use */ +#define scRegImage 10 /* register value saved on stack */ +#define scInfo 11 /* symbol contains debugger information */ +#define scUserStruct 12 /* address in struct user for current process */ +#define scSData 13 /* load time only small data */ +#define scSBss 14 /* load time only small common */ +#define scRData 15 /* load time only read only data */ +#define scVar 16 /* Var parameter (fortran,pascal) */ +#define scCommon 17 /* common variable */ +#define scSCommon 18 /* small common */ +#define scVarRegister 19 /* Var parameter in a register */ +#define scVariant 20 /* Variant record */ +#define scSUndefined 21 /* small undefined(external) data */ +#define scInit 22 /* .init section symbol */ +#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ #define scXData 24 /* exception handling data */ #define scPData 25 /* Procedure section */ #define scFini 26 /* .fini section */ -#define scRConst 27 /* .rconst section */ -#define scMax 32 +#define scRConst 27 /* .rconst section */ +#define scMax 32 /* * Symbol Types */ -#define stNil 0 /* Nuthin' special */ -#define stGlobal 1 /* external symbol */ -#define stStatic 2 /* static */ -#define stParam 3 /* procedure argument */ -#define stLocal 4 /* local variable */ -#define stLabel 5 /* label */ -#define stProc 6 /* " " Procedure */ -#define stBlock 7 /* beginnning of block */ -#define stEnd 8 /* end (of anything) */ -#define stMember 9 /* member (of anything - struct/union/enum */ -#define stTypedef 10 /* type definition */ -#define stFile 11 /* file name */ -#define stRegReloc 12 /* register relocation */ -#define stForward 13 /* forwarding address */ -#define stStaticProc 14 /* load time only static procs */ -#define stConstant 15 /* const */ -#define stStaParam 16 /* Fortran static parameters */ +#define stNil 0 /* Nuthin' special */ +#define stGlobal 1 /* external symbol */ +#define stStatic 2 /* static */ +#define stParam 3 /* procedure argument */ +#define stLocal 4 /* local variable */ +#define stLabel 5 /* label */ +#define stProc 6 /* " " Procedure */ +#define stBlock 7 /* beginnning of block */ +#define stEnd 8 /* end (of anything) */ +#define stMember 9 /* member (of anything - struct/union/enum */ +#define stTypedef 10 /* type definition */ +#define stFile 11 /* file name */ +#define stRegReloc 12 /* register relocation */ +#define stForward 13 /* forwarding address */ +#define stStaticProc 14 /* load time only static procs */ +#define stConstant 15 /* const */ +#define stStaParam 16 /* Fortran static parameters */ /* These new symbol types have been recently added to SGI machines. */ -#define stStruct 26 /* Beginning of block defining a struct type */ -#define stUnion 27 /* Beginning of block defining a union type */ -#define stEnum 28 /* Beginning of block defining an enum type */ -#define stIndirect 34 /* Indirect type specification */ +#define stStruct 26 /* Beginning of block defining a struct type */ +#define stUnion 27 /* Beginning of block defining a union type */ +#define stEnum 28 /* Beginning of block defining an enum type */ +#define stIndirect 34 /* Indirect type specification */ /* Pseudo-symbols - internal to debugger */ -#define stStr 60 /* string */ -#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ -#define stExpr 62 /* 2+2 vs. 4 */ -#define stType 63 /* post-coersion SER */ -#define stMax 64 +#define stStr 60 /* string */ +#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ +#define stExpr 62 /* 2+2 vs. 4 */ +#define stType 63 /* post-coersion SER */ +#define stMax 64 /* definitions for fields in TIR */ /* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ -#define tqNil 0 /* bt is what you see */ -#define tqPtr 1 /* pointer */ -#define tqProc 2 /* procedure */ -#define tqArray 3 /* duh */ -#define tqFar 4 /* longer addressing - 8086/8 land */ -#define tqVol 5 /* volatile */ -#define tqConst 6 /* const */ -#define tqMax 8 +#define tqNil 0 /* bt is what you see */ +#define tqPtr 1 /* pointer */ +#define tqProc 2 /* procedure */ +#define tqArray 3 /* duh */ +#define tqFar 4 /* longer addressing - 8086/8 land */ +#define tqVol 5 /* volatile */ +#define tqConst 6 /* const */ +#define tqMax 8 /* basic types as seen in ti.bt */ -#define btNil 0 /* undefined (also, enum members) */ -#define btAdr 1 /* address - integer same size as pointer */ -#define btChar 2 /* character */ -#define btUChar 3 /* unsigned character */ -#define btShort 4 /* short */ -#define btUShort 5 /* unsigned short */ -#define btInt 6 /* int */ -#define btUInt 7 /* unsigned int */ -#define btLong 8 /* long */ -#define btULong 9 /* unsigned long */ -#define btFloat 10 /* float (real) */ -#define btDouble 11 /* Double (real) */ -#define btStruct 12 /* Structure (Record) */ -#define btUnion 13 /* Union (variant) */ -#define btEnum 14 /* Enumerated */ -#define btTypedef 15 /* defined via a typedef, isymRef points */ -#define btRange 16 /* subrange of int */ -#define btSet 17 /* pascal sets */ -#define btComplex 18 /* fortran complex */ -#define btDComplex 19 /* fortran double complex */ -#define btIndirect 20 /* forward or unnamed typedef */ -#define btFixedDec 21 /* Fixed Decimal */ -#define btFloatDec 22 /* Float Decimal */ -#define btString 23 /* Varying Length Character String */ -#define btBit 24 /* Aligned Bit String */ -#define btPicture 25 /* Picture */ -#define btVoid 26 /* void */ -#define btLongLong 27 /* long long */ -#define btULongLong 28 /* unsigned long long */ -#define btMax 64 +#define btNil 0 /* undefined (also, enum members) */ +#define btAdr 1 /* address - integer same size as pointer */ +#define btChar 2 /* character */ +#define btUChar 3 /* unsigned character */ +#define btShort 4 /* short */ +#define btUShort 5 /* unsigned short */ +#define btInt 6 /* int */ +#define btUInt 7 /* unsigned int */ +#define btLong 8 /* long */ +#define btULong 9 /* unsigned long */ +#define btFloat 10 /* float (real) */ +#define btDouble 11 /* Double (real) */ +#define btStruct 12 /* Structure (Record) */ +#define btUnion 13 /* Union (variant) */ +#define btEnum 14 /* Enumerated */ +#define btTypedef 15 /* defined via a typedef, isymRef points */ +#define btRange 16 /* subrange of int */ +#define btSet 17 /* pascal sets */ +#define btComplex 18 /* fortran complex */ +#define btDComplex 19 /* fortran double complex */ +#define btIndirect 20 /* forward or unnamed typedef */ +#define btFixedDec 21 /* Fixed Decimal */ +#define btFloatDec 22 /* Float Decimal */ +#define btString 23 /* Varying Length Character String */ +#define btBit 24 /* Aligned Bit String */ +#define btPicture 25 /* Picture */ +#define btVoid 26 /* void */ +#define btLongLong 27 /* long long */ +#define btULongLong 28 /* unsigned long long */ +#define btMax 64 diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc index a5a0ad9a4..d1719f1c6 100644 --- a/src/base/loader/ecoff_object.cc +++ b/src/base/loader/ecoff_object.cc @@ -34,7 +34,7 @@ #include "base/misc.hh" #include "base/loader/symtab.hh" -#include "base/trace.hh" // for DPRINTF +#include "base/trace.hh" // for DPRINTF #include "base/loader/exec_ecoff.h" #include "base/loader/coff_sym.h" diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 8e41ffd16..16fc698dd 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -29,6 +29,7 @@ * Ali Saidi */ +#include <cassert> #include <string> #include "gelf.h" @@ -36,7 +37,7 @@ #include "base/loader/elf_object.hh" #include "base/loader/symtab.hh" #include "base/misc.hh" -#include "base/trace.hh" // for DPRINTF +#include "base/trace.hh" // for DPRINTF #include "sim/byteswap.hh" using namespace std; @@ -79,13 +80,19 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) arch = ObjectFile::SPARC32; } else if (ehdr.e_machine == EM_MIPS && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { - arch = ObjectFile::Mips; + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) { + arch = ObjectFile::Mips; + } else { + fatal("The binary you're trying to load is compiled for big " + "endian MIPS. M5\nonly supports little endian MIPS. " + "Please recompile your binary.\n"); + } } else if (ehdr.e_machine == EM_X86_64 && ehdr.e_ident[EI_CLASS] == ELFCLASS64) { - //In the future, we might want to differentiate between 32 bit - //and 64 bit x86 processes in case there are differences in their - //initial stack frame. - arch = ObjectFile::X86; + arch = ObjectFile::X86_64; + } else if (ehdr.e_machine == EM_386 && + ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + arch = ObjectFile::I386; } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { arch = ObjectFile::Alpha; } else if (ehdr.e_machine == EM_ARM) { @@ -284,6 +291,8 @@ ElfObject::ElfObject(const string &_filename, int _fd, data.size = phdr.p_filesz; data.fileImage = fileData + phdr.p_offset; } else { + // If it's none of the above but is loadable, + // load the filesize worth of data Segment extra; extra.baseAddr = phdr.p_paddr; extra.size = phdr.p_filesz; diff --git a/src/base/loader/hex_file.cc b/src/base/loader/hex_file.cc index 1855ebe0c..61d6c8009 100755 --- a/src/base/loader/hex_file.cc +++ b/src/base/loader/hex_file.cc @@ -28,134 +28,111 @@ * Authors: Jaidev Patwardhan */ +#include <cctype> +#include <cstdio> #include <list> #include <string> -#include <sys/types.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> - #include "base/cprintf.hh" #include "base/loader/hex_file.hh" #include "base/loader/symtab.hh" - - #include "mem/translating_port.hh" using namespace std; -/* Load a Hex File into memory. - Currently only used with MIPS BARE_IRON mode. - A hex file consists of [Address Data] tuples that get directly loaded into - physical memory. The address specified is a word address (i.e., to get the byte address, shift left by 2) - The data is a full 32-bit hex value. +/* + * Load a Hex File into memory. Currently only used with MIPS + * BARE_IRON mode. A hex file consists of [Address Data] tuples that + * get directly loaded into physical memory. The address specified is + * a word address (i.e., to get the byte address, shift left by 2) The + * data is a full 32-bit hex value. */ HexFile::HexFile(const string _filename) : filename(_filename) { - fp = fopen(filename.c_str(),"r"); - if(fp == NULL) - { - panic("Unable to open %s\n",filename.c_str()); - } - + fp = fopen(filename.c_str(), "r"); + if (fp == NULL) + panic("Unable to open %s\n", filename.c_str()); } HexFile::~HexFile() { } - bool -HexFile::loadSections(Port *memPort, Addr addrMask) +HexFile::loadSections(Port *memPort) { - char Line[64]; - Addr MemAddr; - uint32_t Data; - while(!feof(fp)) - { - fgets(Line,64,fp); - parseLine(Line,&MemAddr,&Data); - // printf("Hex:%u\n",Data); - - if(MemAddr != 0) - { - // Now, write to memory - memPort->writeBlob(MemAddr<<2,(uint8_t *)&Data,sizeof(Data)); + char Line[64]; + Addr MemAddr; + uint32_t Data; + while (!feof(fp)) { + char *ret = fgets(Line, sizeof(Line), fp); + if (!ret) + panic("malformed file"); + parseLine(Line, &MemAddr, &Data); + if (MemAddr != 0) { + // Now, write to memory + memPort->writeBlob(MemAddr << 2, (uint8_t *)&Data, sizeof(Data)); } } return true; } -void HexFile::parseLine(char *Str,Addr *A, uint32_t *D) -{ - int i=0; - bool Flag = false; - *A = 0; - *D = 0; - int Digit = 0; - unsigned Number = 0; - /* Skip white spaces */ - while(Str[i] != '\0' && Str[i]==' ') - i++; - /* Ok, we're at some character...process things */ - while(Str[i] != '\0') - { - if(Str[i]>='0' && Str[i]<='9') - { - Digit=Str[i]-'0'; - } - else if(Str[i]>='a' && Str[i]<='f') - { - Digit=Str[i]-'a'+10; - } - else if(Str[i]>='A' && Str[i]<='F') - { +void +HexFile::parseLine(char *Str, Addr *A, uint32_t *D) +{ + int i = 0; + bool Flag = false; + *A = 0; + *D = 0; + int Digit = 0; + unsigned Number = 0; + + /* Skip white spaces */ + while (Str[i] != '\0' && Str[i]==' ') + i++; + + /* Ok, we're at some character...process things */ + while (Str[i] != '\0') { + if (Str[i] >= '0' && Str[i] <= '9') { + Digit = Str[i] - '0'; + } else if (Str[i] >= 'a' && Str[i] <= 'f') { + Digit = Str[i] - 'a' + 10; + } else if (Str[i] >= 'A' && Str[i] <= 'F') { Digit=Str[i]-'A'+10; - } - else if(Str[i] == ' ' || Str[i]=='\n') - { - if(Number == 0) - return; - if(Flag == false) - { - *A = Number; - Number = 0; - Flag = true; - } - else - { - *D = Number; - return; + } else if (Str[i] == ' ' || Str[i] == '\n') { + if (Number == 0) + return; + if (Flag == false) { + *A = Number; + Number = 0; + Flag = true; + } else { + *D = Number; + return; } + } else { + // Ok, we've encountered a non-hex character, cannot be a + // valid line, skip and return 0's + *A = 0; + *D = 0; + return; } - else - { - // Ok, we've encountered a non-hex character, cannot be a valid line, skip and return 0's - *A = 0; - *D = 0; - return; - } - Number<<=4; - Number+=Digit; - i++; + Number <<= 4; + Number += Digit; + i++; } - if(Flag != true) - { - *A = 0; - *D = 0; - } - else - *D = Number; + if (Flag != true) { + *A = 0; + *D = 0; + } else { + *D = Number; + } } - - void HexFile::close() { - fclose(fp); + fclose(fp); } diff --git a/src/base/loader/hex_file.hh b/src/base/loader/hex_file.hh index 1dbfd034f..40483e684 100755 --- a/src/base/loader/hex_file.hh +++ b/src/base/loader/hex_file.hh @@ -28,50 +28,31 @@ * Authors: Jaidev Patwardhan */ -#ifndef __HEX_FILE_HH__ -#define __HEX_FILE_HH__ +#ifndef __BASE_LOADER_HEX_FILE_HH__ +#define __BASE_LOADER_HEX_FILE_HH__ +#include <cstdio> #include <limits> #include <string> -#include "sim/host.hh" // for Addr -#include <fstream> +#include "sim/host.hh" // for Addr class Port; class HexFile { - public: - - protected: const std::string filename; FILE *fp; + void parseLine(char *, Addr *, uint32_t *); + public: - virtual ~HexFile(); HexFile(const std::string _filename); + virtual ~HexFile(); void close(); - - bool loadSections(Port *memPort, Addr addrMask = - std::numeric_limits<Addr>::max()); - - protected: - - typedef struct { - Addr MemAddr; - uint32_t Data; - } HexLine; - - Addr entry; - Addr globalPtr; - - public: - void parseLine(char *,Addr *,uint32_t *); - Addr entryPoint() const { return entry; } - Addr globalPointer() const { return globalPtr; } - + bool loadSections(Port *memPort); }; -#endif // __HEX_FILE_HH__ +#endif // __BASE_LOADER_HEX_FILE_HH__ diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 7f2bef0bf..d363cde84 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -35,7 +35,7 @@ #include <limits> #include <string> -#include "sim/host.hh" // for Addr +#include "sim/host.hh" // for Addr class Port; class SymbolTable; @@ -50,7 +50,8 @@ class ObjectFile SPARC64, SPARC32, Mips, - X86, + X86_64, + I386, Arm }; diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh index 184c0a996..cc1dc368f 100644 --- a/src/base/loader/symtab.hh +++ b/src/base/loader/symtab.hh @@ -34,8 +34,9 @@ #include <iosfwd> #include <map> +#include <string> -#include "sim/host.hh" // for Addr +#include "sim/host.hh" // for Addr class Checkpoint; class SymbolTable diff --git a/src/base/misc.cc b/src/base/misc.cc index afb48ca80..035282baf 100644 --- a/src/base/misc.cc +++ b/src/base/misc.cc @@ -28,8 +28,10 @@ * Authors: Nathan Binkert */ +#include <cstdlib> #include <iostream> #include <string> +#include <zlib.h> #include "base/cprintf.hh" #include "base/hostinfo.hh" @@ -42,42 +44,24 @@ using namespace std; -void -__panic(const char *func, const char *file, int line, const char *fmt, - CPRINTF_DEFINITION) -{ - string format = "panic: "; - format += fmt; - switch (format[format.size() - 1]) { - case '\n': - case '\r': - break; - default: - format += "\n"; - } - - format += " @ cycle %d\n[%s:%s, line %d]\n"; - - CPrintfArgsList args(VARARGS_ALLARGS); - - args.push_back(curTick); - args.push_back(func); - args.push_back(file); - args.push_back(line); +bool want_warn = true; +bool want_info = true; +bool want_hack = true; - ccprintf(cerr, format.c_str(), args); - - abort(); -} +bool warn_verbose = false; +bool info_verbose = false; +bool hack_verbose = false; void -__fatal(const char *func, const char *file, int line, const char *fmt, - CPRINTF_DEFINITION) +__exit_message(const char *prefix, int code, + const char *func, const char *file, int line, + const char *fmt, CPRINTF_DEFINITION) { CPrintfArgsList args(VARARGS_ALLARGS); - string format = "fatal: "; - format += fmt; + string format = prefix; + format += ": "; + format += fmt; switch (format[format.size() - 1]) { case '\n': case '\r': @@ -85,28 +69,39 @@ __fatal(const char *func, const char *file, int line, const char *fmt, default: format += "\n"; } + + uint32_t crc = crc32(0, (const Bytef*)fmt, strlen(fmt)); format += " @ cycle %d\n[%s:%s, line %d]\n"; format += "Memory Usage: %ld KBytes\n"; + format += "For more information see: http://www.m5sim.org/%s/%x\n"; args.push_back(curTick); args.push_back(func); args.push_back(file); args.push_back(line); args.push_back(memUsage()); + args.push_back(prefix); + args.push_back(crc); ccprintf(cerr, format.c_str(), args); - exit(1); + if (code < 0) + abort(); + else + exit(code); } void -__warn(const char *func, const char *file, int line, const char *fmt, - CPRINTF_DEFINITION) +__base_message(std::ostream &stream, const char *prefix, bool verbose, + const char *func, const char *file, int line, + const char *fmt, CPRINTF_DEFINITION) { - string format = "warn: "; - format += fmt; + CPrintfArgsList args(VARARGS_ALLARGS); + string format = prefix; + format += ": "; + format += fmt; switch (format[format.size() - 1]) { case '\n': case '\r': @@ -114,21 +109,22 @@ __warn(const char *func, const char *file, int line, const char *fmt, default: format += "\n"; } + + uint32_t crc = crc32(0, (const Bytef*)fmt, strlen(fmt)); + + if (verbose) { + format += " @ cycle %d\n[%s:%s, line %d]\n"; + args.push_back(curTick); + args.push_back(func); + args.push_back(file); + args.push_back(line); + } -#ifdef VERBOSE_WARN - format += " @ cycle %d\n[%s:%s, line %d]\n"; -#endif - - CPrintfArgsList args(VARARGS_ALLARGS); - -#ifdef VERBOSE_WARN - args.push_back(curTick); - args.push_back(func); - args.push_back(file); - args.push_back(line); -#endif + if (strcmp(prefix, "warn") == 0) { + format += "For more information see: http://www.m5sim.org/%s/%x\n"; + args.push_back(prefix); + args.push_back(crc); + } - ccprintf(cerr, format.c_str(), args); - if (simout.isFile(*outputStream)) - ccprintf(*outputStream, format.c_str(), args); + ccprintf(stream, format.c_str(), args); } diff --git a/src/base/misc.hh b/src/base/misc.hh index 1509ea2d2..25dcbaa62 100644 --- a/src/base/misc.hh +++ b/src/base/misc.hh @@ -29,10 +29,8 @@ * Dave Greene */ -#ifndef __MISC_HH__ -#define __MISC_HH__ - -#include <cassert> +#ifndef __BASE_MISC_HH__ +#define __BASE_MISC_HH__ #include "base/compiler.hh" #include "base/cprintf.hh" @@ -42,6 +40,30 @@ #define __FUNCTION__ "how to fix me?" #endif +// General exit message, these functions will never return and will +// either abort() if code is < 0 or exit with the code if >= 0 +void __exit_message(const char *prefix, int code, + const char *func, const char *file, int line, + const char *format, CPRINTF_DECLARATION) M5_ATTR_NORETURN; + +void __exit_message(const char *prefix, int code, + const char *func, const char *file, int line, + const std::string &format, CPRINTF_DECLARATION) M5_ATTR_NORETURN; + +inline void +__exit_message(const char *prefix, int code, + const char *func, const char *file, int line, + const std::string& format, CPRINTF_DEFINITION) +{ + __exit_message(prefix, code, func, file, line, format.c_str(), + VARARGS_ALLARGS); +} + +M5_PRAGMA_NORETURN(__exit_message) +#define exit_message(prefix, code, ...) \ + __exit_message(prefix, code, __FUNCTION__, __FILE__, __LINE__, \ + __VA_ARGS__) + // // This implements a cprintf based panic() function. panic() should // be called when something happens that should never ever happen @@ -49,20 +71,7 @@ // calls abort which can dump core or enter the debugger. // // -void __panic(const char *func, const char *file, int line, const char *format, - CPRINTF_DECLARATION) M5_ATTR_NORETURN; -void __panic(const char *func, const char *file, int line, - const std::string &format, CPRINTF_DECLARATION) -M5_ATTR_NORETURN; - -inline void -__panic(const char *func, const char *file, int line, - const std::string &format, CPRINTF_DEFINITION) -{ - __panic(func, file, line, format.c_str(), VARARGS_ALLARGS); -} -M5_PRAGMA_NORETURN(__panic) -#define panic(...) __panic(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +#define panic(...) exit_message("panic", -1, __VA_ARGS__) // // This implements a cprintf based fatal() function. fatal() should @@ -72,54 +81,70 @@ M5_PRAGMA_NORETURN(__panic) // "normal" exit with an error code, as opposed to abort() like // panic() does. // -void __fatal(const char *func, const char *file, int line, const char *format, - CPRINTF_DECLARATION) M5_ATTR_NORETURN; -void __fatal(const char *func, const char *file, int line, - const std::string &format, CPRINTF_DECLARATION) - M5_ATTR_NORETURN; +#define fatal(...) exit_message("fatal", 1, __VA_ARGS__) -inline void -__fatal(const char *func, const char *file, int line, - const std::string &format, CPRINTF_DEFINITION) -{ - __fatal(func, file, line, format.c_str(), VARARGS_ALLARGS); -} -M5_PRAGMA_NORETURN(__fatal) -#define fatal(...) __fatal(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +void +__base_message(std::ostream &stream, const char *prefix, bool verbose, + const char *func, const char *file, int line, + const char *format, CPRINTF_DECLARATION); -// -// This implements a cprintf based warn -// -void __warn(const char *func, const char *file, int line, const char *format, - CPRINTF_DECLARATION); inline void -__warn(const char *func, const char *file, int line, const std::string &format, - CPRINTF_DECLARATION) +__base_message(std::ostream &stream, const char *prefix, bool verbose, + const char *func, const char *file, int line, + const std::string &format, CPRINTF_DECLARATION) { - __warn(func, file, line, format, VARARGS_ALLARGS); + __base_message(stream, prefix, verbose, func, file, line, format.c_str(), + VARARGS_ALLARGS); } -#define warn(...) __warn(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) - -// Only print the warning message the first time it is seen. This -// doesn't check the warning string itself, it just only lets one -// warning come from the statement. So, even if the arguments change -// and that would have resulted in a different warning message, -// subsequent messages would still be supressed. -#define warn_once(...) do { \ - static bool once = false; \ - if (!once) { \ - warn(__VA_ARGS__); \ - once = true; \ - } \ + +#define base_message(stream, prefix, verbose, ...) \ + __base_message(stream, prefix, verbose, __FUNCTION__, __FILE__, __LINE__, \ + __VA_ARGS__) + +// Only print the message the first time this expression is +// encountered. i.e. This doesn't check the string itself and +// prevent duplicate strings, this prevents the statement from +// happening more than once. So, even if the arguments change and that +// would have resulted in a different message thoes messages would be +// supressed. +#define base_message_once(...) do { \ + static bool once = false; \ + if (!once) { \ + base_message(__VA_ARGS__); \ + once = true; \ + } \ } while (0) -// -// assert() that prints out the current cycle -// -#define m5_assert(TEST) do { \ - if (!(TEST)) \ - ccprintf(std::cerr, "Assertion failure, curTick = %d\n", curTick); \ - assert(TEST); \ -} while (0) +#define cond_message(cond, ...) do { \ + if (cond) \ + base_message(__VA_ARGS__); \ + } while (0) + +#define cond_message_once(cond, ...) do { \ + static bool once = false; \ + if (!once && cond) { \ + base_message(__VA_ARGS__); \ + once = true; \ + } \ + } while (0) + + +extern bool want_warn, warn_verbose; +extern bool want_info, info_verbose; +extern bool want_hack, hack_verbose; + +#define warn(...) \ + cond_message(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__) +#define inform(...) \ + cond_message(want_info, std::cout, "info", info_verbose, __VA_ARGS__) +#define hack(...) \ + cond_message(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__) + +#define warn_once(...) \ + cond_message_once(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__) +#define inform_once(...) \ + cond_message_once(want_info, std::cout, "info", info_verbose, __VA_ARGS__) +#define hack_once(...) \ + cond_message_once(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__) -#endif // __MISC_HH__ +#endif // __BASE_MISC_HH__ diff --git a/src/base/output.cc b/src/base/output.cc index 9d02a4a71..ea13e23d4 100644 --- a/src/base/output.cc +++ b/src/base/output.cc @@ -36,6 +36,8 @@ #include <fstream> +#include <gzstream.hh> + #include "base/misc.hh" #include "base/output.hh" @@ -50,7 +52,45 @@ OutputDirectory::OutputDirectory() {} OutputDirectory::~OutputDirectory() -{} +{ + for (map_t::iterator i = files.begin(); i != files.end(); i++) { + if (i->second) + delete i->second; + } +} + +std::ostream * +OutputDirectory::checkForStdio(const string &name) const +{ + if (name == "cerr" || name == "stderr") + return &cerr; + + if (name == "cout" || name == "stdout") + return &cout; + + return NULL; +} + +ostream * +OutputDirectory::openFile(const string &filename, + ios_base::openmode mode) const +{ + if (filename.find(".gz", filename.length()-3) < filename.length()) { + ogzstream *file = new ogzstream(filename.c_str(), mode); + + if (!file->is_open()) + fatal("Cannot open file %s", filename); + + return file; + } else { + ofstream *file = new ofstream(filename.c_str(), mode); + + if (!file->is_open()) + fatal("Cannot open file %s", filename); + + return file; + } +} void OutputDirectory::setDirectory(const string &d) @@ -60,19 +100,13 @@ OutputDirectory::setDirectory(const string &d) dir = d; - if (dir != ".") { - if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST) - panic("couldn't make output dir %s: %s\n", - dir, strerror(errno)); - } - // guarantee that directory ends with a '/' if (dir[dir.size() - 1] != '/') dir += "/"; } const string & -OutputDirectory::directory() +OutputDirectory::directory() const { if (dir.empty()) panic("Output directory not set!"); @@ -80,8 +114,8 @@ OutputDirectory::directory() return dir; } -string -OutputDirectory::resolve(const string &name) +inline string +OutputDirectory::resolve(const string &name) const { return (name[0] != '/') ? dir + name : name; } @@ -89,16 +123,14 @@ OutputDirectory::resolve(const string &name) ostream * OutputDirectory::create(const string &name, bool binary) { - if (name == "cerr" || name == "stderr") - return &cerr; - - if (name == "cout" || name == "stdout") - return &cout; + ostream *file = checkForStdio(name); + if (file) + return file; - ofstream *file = new ofstream(resolve(name).c_str(), - ios::trunc | binary ? ios::binary : (ios::openmode)0); - if (!file->is_open()) - panic("Cannot open file %s", name); + string filename = resolve(name); + ios_base::openmode mode = + ios::trunc | binary ? ios::binary : (ios::openmode)0; + file = openFile(filename, mode); return file; } @@ -106,21 +138,16 @@ OutputDirectory::create(const string &name, bool binary) ostream * OutputDirectory::find(const string &name) { - if (name == "cerr" || name == "stderr") - return &cerr; - - if (name == "cout" || name == "stdout") - return &cout; + ostream *file = checkForStdio(name); + if (file) + return file; string filename = resolve(name); map_t::iterator i = files.find(filename); if (i != files.end()) return (*i).second; - ofstream *file = new ofstream(filename.c_str(), ios::trunc); - if (!file->is_open()) - panic("Cannot open file %s", filename); - + file = openFile(filename); files[filename] = file; return file; } diff --git a/src/base/output.hh b/src/base/output.hh index 5de0c4005..38c63714c 100644 --- a/src/base/output.hh +++ b/src/base/output.hh @@ -31,7 +31,7 @@ #ifndef __BASE_OUTPUT_HH__ #define __BASE_OUTPUT_HH__ -#include <iosfwd> +#include <ios> #include <map> #include <string> @@ -43,14 +43,20 @@ class OutputDirectory map_t files; std::string dir; + std::string resolve(const std::string &name) const; + + protected: + std::ostream *checkForStdio(const std::string &name) const; + std::ostream *openFile(const std::string &filename, + std::ios_base::openmode mode = std::ios::trunc) const; + public: OutputDirectory(); ~OutputDirectory(); void setDirectory(const std::string &dir); - const std::string &directory(); + const std::string &directory() const; - std::string resolve(const std::string &name); std::ostream *create(const std::string &name, bool binary = false); std::ostream *find(const std::string &name); diff --git a/src/base/random_mt.cc b/src/base/random_mt.cc index 1492240ee..6ea54ec03 100644 --- a/src/base/random_mt.cc +++ b/src/base/random_mt.cc @@ -123,15 +123,15 @@ Random::genrand() int kk; for (kk = 0; kk < N - M; kk++) { - y = mt[kk] & UPPER_MASK | mt[kk+1] & LOWER_MASK; + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (; kk < N - 1; kk++) { - y = mt[kk] & UPPER_MASK | mt[kk+1] & LOWER_MASK; + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } - y = mt[N - 1] & UPPER_MASK | mt[0] & LOWER_MASK; + y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; diff --git a/src/base/range_map.hh b/src/base/range_map.hh index 6d3450739..0ffc28ed9 100644 --- a/src/base/range_map.hh +++ b/src/base/range_map.hh @@ -46,7 +46,8 @@ class range_map typedef typename RangeMap::iterator iterator; template <class U> - const iterator find(const Range<U> &r) + const iterator + find(const Range<U> &r) { iterator i; @@ -69,7 +70,15 @@ class range_map } template <class U> - bool intersect(const Range<U> &r) + const iterator + find(const U &r) + { + return find(RangeSize(r, 1)); + } + + template <class U> + bool + intersect(const Range<U> &r) { iterator i; i = find(r); @@ -80,7 +89,8 @@ class range_map template <class U,class W> - iterator insert(const Range<U> &r, const W d) + iterator + insert(const Range<U> &r, const W d) { if (intersect(r)) return tree.end(); @@ -88,42 +98,50 @@ class range_map return tree.insert(std::make_pair<Range<T>,V>(r, d)).first; } - size_t erase(T k) + size_t + erase(T k) { return tree.erase(k); } - void erase(iterator p) + void + erase(iterator p) { tree.erase(p); } - void erase(iterator p, iterator q) + void + erase(iterator p, iterator q) { tree.erase(p,q); } - void clear() + void + clear() { tree.erase(tree.begin(), tree.end()); } - iterator begin() + iterator + begin() { return tree.begin(); } - iterator end() + iterator + end() { return tree.end(); } - size_t size() + size_t + size() { return tree.size(); } - bool empty() + bool + empty() { return tree.empty(); } @@ -180,7 +198,8 @@ class range_multimap } template <class U> - bool intersect(const Range<U> &r) + bool + intersect(const Range<U> &r) { std::pair<iterator,iterator> p; p = find(r); @@ -191,7 +210,8 @@ class range_multimap template <class U,class W> - iterator insert(const Range<U> &r, const W d) + iterator + insert(const Range<U> &r, const W d) { std::pair<iterator,iterator> p; p = find(r); @@ -202,42 +222,50 @@ class range_multimap return tree.end(); } - size_t erase(T k) + size_t + erase(T k) { return tree.erase(k); } - void erase(iterator p) + void + erase(iterator p) { tree.erase(p); } - void erase(iterator p, iterator q) + void + erase(iterator p, iterator q) { tree.erase(p,q); } - void clear() + void + clear() { tree.erase(tree.begin(), tree.end()); } - iterator begin() + iterator + begin() { return tree.begin(); } - iterator end() + iterator + end() { return tree.end(); } - size_t size() + size_t + size() { return tree.size(); } - bool empty() + bool + empty() { return tree.empty(); } diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc index d5095e7f9..93d86447e 100644 --- a/src/base/remote_gdb.cc +++ b/src/base/remote_gdb.cc @@ -30,7 +30,7 @@ /* * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and @@ -38,8 +38,8 @@ * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,8 +51,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -69,7 +69,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 */ /*- @@ -89,8 +89,8 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. @@ -195,6 +195,11 @@ GDBListener::name() void GDBListener::listen() { + if (ListenSocket::allDisabled()) { + warn_once("Sockets disabled, not accepting gdb connections"); + return; + } + while (!listener.listen(port, true)) { DPRINTF(GDBMisc, "Can't bind port %d\n", port); port++; @@ -341,14 +346,16 @@ uint8_t BaseRemoteGDB::getbyte() { uint8_t b; - ::read(fd, &b, 1); + if (::read(fd, &b, 1) != 1) + warn("could not read byte from debugger"); return b; } void BaseRemoteGDB::putbyte(uint8_t b) { - ::write(fd, &b, 1); + if (::write(fd, &b, 1) != 1) + warn("could not write byte to debugger"); } // Send a packet to gdb @@ -454,14 +461,11 @@ BaseRemoteGDB::read(Addr vaddr, size_t size, char *data) DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); #if FULL_SYSTEM - VirtualPort *port = context->getVirtPort(context); + VirtualPort *port = context->getVirtPort(); #else TranslatingPort *port = context->getMemPort(); #endif port->readBlob(vaddr, (uint8_t*)data, size); -#if FULL_SYSTEM - context->delVirtPort(port); -#endif #if TRACING_ON if (DTRACE(GDBRead)) { @@ -499,14 +503,12 @@ BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data) DPRINTFNR("\n"); } #if FULL_SYSTEM - VirtualPort *port = context->getVirtPort(context); + VirtualPort *port = context->getVirtPort(); #else TranslatingPort *port = context->getMemPort(); #endif port->writeBlob(vaddr, (uint8_t*)data, size); -#if FULL_SYSTEM - context->delVirtPort(port); -#else +#if !FULL_SYSTEM delete port; #endif diff --git a/src/base/res_list.hh b/src/base/res_list.hh index 442280e15..024b56982 100644 --- a/src/base/res_list.hh +++ b/src/base/res_list.hh @@ -635,7 +635,7 @@ res_list<T>::remove(iterator q) // A little "garbage collection" if (++remove_count > 10) { - // free_extras(); + // free_extras(); remove_count = 0; } diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh index 79de11156..38c4ec74f 100644 --- a/src/base/sat_counter.hh +++ b/src/base/sat_counter.hh @@ -64,13 +64,13 @@ class SaturatingCounterPred : public GenericPredictor unsigned *table; // Statistics - Stats::Scalar<> predicted_one; // Total predictions of one, preds_one - Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero - Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one - Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero + Stats::Scalar predicted_one; // Total predictions of one, preds_one + Stats::Scalar predicted_zero; // Total predictions of zero, preds_zero + Stats::Scalar correct_pred_one; // Total correct predictions of one, correct_one + Stats::Scalar correct_pred_zero; // Total correct predictions of zero, correct_zero - Stats::Scalar<> record_zero; //updates_zero - Stats::Scalar<> record_one; //updates_one + Stats::Scalar record_zero; //updates_zero + Stats::Scalar record_one; //updates_one Stats::Formula preds_total; Stats::Formula pred_frac_zero; diff --git a/src/base/socket.cc b/src/base/socket.cc index adcc48735..bcc5236b0 100644 --- a/src/base/socket.cc +++ b/src/base/socket.cc @@ -43,6 +43,23 @@ using namespace std; +bool ListenSocket::listeningDisabled = false; +bool ListenSocket::anyListening = false; + +void +ListenSocket::disableAll() +{ + if (anyListening) + panic("Too late to disable all listeners, already have a listener"); + listeningDisabled = true; +} + +bool +ListenSocket::allDisabled() +{ + return listeningDisabled; +} + //////////////////////////////////////////////////////////////////////// // // @@ -92,6 +109,7 @@ ListenSocket::listen(int port, bool reuse) listening = true; + anyListening = true; return true; } diff --git a/src/base/socket.hh b/src/base/socket.hh index 8e55eae72..942318e45 100644 --- a/src/base/socket.hh +++ b/src/base/socket.hh @@ -34,6 +34,14 @@ class ListenSocket { protected: + static bool listeningDisabled; + static bool anyListening; + + public: + static void disableAll(); + static bool allDisabled(); + + protected: bool listening; int fd; diff --git a/src/base/statistics.cc b/src/base/statistics.cc index 2acef83c5..0a59248e7 100644 --- a/src/base/statistics.cc +++ b/src/base/statistics.cc @@ -32,81 +32,106 @@ #include <fstream> #include <list> #include <map> +#include <set> #include <string> #include "base/callback.hh" #include "base/cprintf.hh" +#include "base/debug.hh" #include "base/hostinfo.hh" #include "base/misc.hh" #include "base/statistics.hh" #include "base/str.hh" #include "base/time.hh" #include "base/trace.hh" -#include "base/stats/statdb.hh" using namespace std; namespace Stats { -StatData * -DataAccess::find() const +typedef map<const void *, Info *> MapType; + +// We wrap these in a function to make sure they're built in time. +list<Info *> & +statsList() { - return Database::find(const_cast<void *>((const void *)this)); + static list<Info *> the_list; + return the_list; } -const StatData * -getStatData(const void *stat) +MapType & +statsMap() { - return Database::find(const_cast<void *>(stat)); + static MapType the_map; + return the_map; } void -DataAccess::map(StatData *data) +InfoAccess::setInfo(Info *info) { - Database::regStat(this, data); + if (statsMap().find(this) != statsMap().end()) + panic("shouldn't register stat twice!"); + + statsList().push_back(info); + +#ifndef NDEBUG + pair<MapType::iterator, bool> result = +#endif + statsMap().insert(make_pair(this, info)); + assert(result.second && "this should never fail"); + assert(statsMap().find(this) != statsMap().end()); } -StatData * -DataAccess::statData() +void +InfoAccess::setParams(const StorageParams *params) { - StatData *ptr = find(); - assert(ptr); - return ptr; + info()->storageParams = params; } -const StatData * -DataAccess::statData() const +void +InfoAccess::setInit() { - const StatData *ptr = find(); - assert(ptr); - return ptr; + info()->flags |= init; } -void -DataAccess::setInit() +Info * +InfoAccess::info() { - statData()->flags |= init; + MapType::const_iterator i = statsMap().find(this); + assert(i != statsMap().end()); + return (*i).second; } -void -DataAccess::setPrint() +const Info * +InfoAccess::info() const { - Database::regPrint(this); + MapType::const_iterator i = statsMap().find(this); + assert(i != statsMap().end()); + return (*i).second; } -StatData::StatData() - : flags(none), precision(-1), prereq(0) +StorageParams::~StorageParams() { - static int count = 0; - id = count++; } -StatData::~StatData() +int Info::id_count = 0; + +int debug_break_id = -1; + +Info::Info() + : flags(none), precision(-1), prereq(0), storageParams(NULL) +{ + id = id_count++; + if (debug_break_id >= 0 and debug_break_id == id) + debug_break(); +} + +Info::~Info() { } bool -StatData::less(StatData *stat1, StatData *stat2) +Info::less(Info *stat1, Info *stat2) { const string &name1 = stat1->name; const string &name2 = stat2->name; @@ -117,8 +142,8 @@ StatData::less(StatData *stat1, StatData *stat2) tokenize(v1, name1, '.'); tokenize(v2, name2, '.'); - int last = min(v1.size(), v2.size()) - 1; - for (int i = 0; i < last; ++i) + size_type last = min(v1.size(), v2.size()) - 1; + for (off_type i = 0; i < last; ++i) if (v1[i] != v2[i]) return v1[i] < v2[i]; @@ -132,9 +157,9 @@ StatData::less(StatData *stat1, StatData *stat2) } bool -StatData::baseCheck() const +Info::baseCheck() const { - if (!(flags & init)) { + if (!(flags & Stats::init)) { #ifdef DEBUG cprintf("this is stat number %d\n", id); #endif @@ -150,54 +175,40 @@ StatData::baseCheck() const return true; } - void -FormulaBase::result(VResult &vec) const -{ - if (root) - vec = root->result(); -} - -Result -FormulaBase::total() const -{ - return root ? root->total() : 0.0; -} - -size_t -FormulaBase::size() const +Info::enable() { - if (!root) - return 0; - else - return root->size(); } void -FormulaBase::reset() +VectorInfoBase::enable() { -} - -bool -FormulaBase::zero() const -{ - VResult vec; - result(vec); - for (int i = 0; i < vec.size(); ++i) - if (vec[i] != 0.0) - return false; - return true; + size_type s = size(); + if (subnames.size() < s) + subnames.resize(s); + if (subdescs.size() < s) + subdescs.resize(s); } void -FormulaBase::update(StatData *) +VectorDistInfoBase::enable() { + size_type s = size(); + if (subnames.size() < s) + subnames.resize(s); + if (subdescs.size() < s) + subdescs.resize(s); } -string -FormulaBase::str() const +void +Vector2dInfoBase::enable() { - return root ? root->str() : ""; + if (subnames.size() < x) + subnames.resize(x); + if (subdescs.size() < x) + subdescs.resize(x); + if (y_subnames.size() < y) + y_subnames.resize(y); } Formula::Formula() @@ -232,38 +243,86 @@ Formula::operator+=(Temp r) } void -check() +Formula::result(VResult &vec) const { - typedef Database::stat_list_t::iterator iter_t; - - iter_t i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - assert(data); - if (!data->check() || !data->baseCheck()) - panic("stat check failed for %s\n", data->name); - } + if (root) + vec = root->result(); +} - int j = 0; - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - if (!(data->flags & print)) - data->name = "__Stat" + to_string(j++); - } +Result +Formula::total() const +{ + return root ? root->total() : 0.0; +} + +size_type +Formula::size() const +{ + if (!root) + return 0; + else + return root->size(); +} + +void +Formula::reset() +{ +} + +bool +Formula::zero() const +{ + VResult vec; + result(vec); + for (off_t i = 0; i < vec.size(); ++i) + if (vec[i] != 0.0) + return false; + return true; +} - Database::stats().sort(StatData::less); +string +Formula::str() const +{ + return root ? root->str() : ""; +} - if (i == end) - return; +void +enable() +{ + typedef list<Info *>::iterator iter_t; + + iter_t i, end = statsList().end(); + for (i = statsList().begin(); i != end; ++i) { + Info *info = *i; + assert(info); + if (!info->check() || !info->baseCheck()) + panic("stat check failed for '%s' %d\n", info->name, info->id); + } - iter_t last = i; - ++i; + off_t j = 0; + for (i = statsList().begin(); i != end; ++i) { + Info *info = *i; + if (!(info->flags & print)) + info->name = "__Stat" + to_string(j++); + } - for (i = Database::stats().begin(); i != end; ++i) { - if ((*i)->name == (*last)->name) - panic("same name used twice! name=%s\n", (*i)->name); + statsList().sort(Info::less); + + for (i = statsList().begin(); i != end; ++i) { + Info *info = *i; + info->enable(); + } +} - last = i; +void +prepare() +{ + list<Info *>::iterator i = statsList().begin(); + list<Info *>::iterator end = statsList().end(); + while (i != end) { + Info *info = *i; + info->prepare(); + ++i; } } @@ -272,11 +331,11 @@ CallbackQueue resetQueue; void reset() { - Database::stat_list_t::iterator i = Database::stats().begin(); - Database::stat_list_t::iterator end = Database::stats().end(); + list<Info *>::iterator i = statsList().begin(); + list<Info *>::iterator end = statsList().end(); while (i != end) { - StatData *data = *i; - data->reset(); + Info *info = *i; + info->reset(); ++i; } diff --git a/src/base/statistics.hh b/src/base/statistics.hh index 3a859d364..88704207d 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -26,7 +26,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert - * Erik Hallnor */ /** @file @@ -56,9 +55,11 @@ #include <cmath> #include <functional> #include <iosfwd> +#include <list> #include <string> #include <vector> +#include "base/cast.hh" #include "base/cprintf.hh" #include "base/intmath.hh" #include "base/refcnt.hh" @@ -76,14 +77,19 @@ extern Tick curTick; /* A namespace for all of the Statistics */ namespace Stats { -/* Contains the statistic implementation details */ +struct StorageParams +{ + virtual ~StorageParams(); +}; + ////////////////////////////////////////////////////////////////////// // // Statistics Framework Base classes // ////////////////////////////////////////////////////////////////////// -struct StatData +class Info { + public: /** The name of the stat. */ std::string name; /** The description of the stat. */ @@ -93,18 +99,41 @@ struct StatData /** The display precision. */ int precision; /** A pointer to a prerequisite Stat. */ - const StatData *prereq; + const Info *prereq; /** * A unique stat ID for each stat in the simulator. * Can be used externally for lookups as well as for debugging. */ + static int id_count; int id; - StatData(); - virtual ~StatData(); + public: + const StorageParams *storageParams; + + public: + Info(); + virtual ~Info(); + + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + virtual bool check() const = 0; + bool baseCheck() const; + + /** + * Enable the stat for use + */ + virtual void enable(); + + /** + * Prepare the stat for dumping. + */ + virtual void prepare() = 0; /** - * Reset the corresponding stat to the default state. + * Reset the stat to the default state. */ virtual void reset() = 0; @@ -115,14 +144,6 @@ struct StatData virtual bool zero() const = 0; /** - * Check that this stat has been set up properly and is ready for - * use - * @return true for success - */ - virtual bool check() const = 0; - bool baseCheck() const; - - /** * Visitor entry for outputing statistics data */ virtual void visit(Visit &visitor) = 0; @@ -135,94 +156,95 @@ struct StatData * @param stat2 The second stat. * @return stat1's name is alphabetically before stat2's */ - static bool less(StatData *stat1, StatData *stat2); + static bool less(Info *stat1, Info *stat2); +}; + +template <class Stat, class Base> +class InfoWrap : public Base +{ + protected: + Stat &s; + + public: + InfoWrap(Stat &stat) : s(stat) {} + + bool check() const { return s.check(); } + void prepare() { s.prepare(); } + void reset() { s.reset(); } + void + visit(Visit &visitor) + { + visitor.visit(*static_cast<Base *>(this)); + } + bool zero() const { return s.zero(); } }; -class ScalarData : public StatData +class ScalarInfoBase : public Info { public: virtual Counter value() const = 0; virtual Result result() const = 0; virtual Result total() const = 0; - virtual void visit(Visit &visitor) { visitor.visit(*this); } }; template <class Stat> -class ScalarStatData : public ScalarData +class ScalarInfo : public InfoWrap<Stat, ScalarInfoBase> { - protected: - Stat &s; - public: - ScalarStatData(Stat &stat) : s(stat) {} + ScalarInfo(Stat &stat) : InfoWrap<Stat, ScalarInfoBase>(stat) {} - virtual bool check() const { return s.check(); } - virtual Counter value() const { return s.value(); } - virtual Result result() const { return s.result(); } - virtual Result total() const { return s.total(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } + Counter value() const { return this->s.value(); } + Result result() const { return this->s.result(); } + Result total() const { return this->s.total(); } }; -struct VectorData : public StatData +class VectorInfoBase : public Info { + public: /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; + std::vector<std::string> subnames; + std::vector<std::string> subdescs; + + public: + void enable(); - virtual size_t size() const = 0; + public: + virtual size_type size() const = 0; virtual const VCounter &value() const = 0; virtual const VResult &result() const = 0; - virtual Result total() const = 0; - void update() - { - if (!subnames.empty()) { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } - } + virtual Result total() const = 0; }; template <class Stat> -class VectorStatData : public VectorData +class VectorInfo : public InfoWrap<Stat, VectorInfoBase> { protected: - Stat &s; mutable VCounter cvec; mutable VResult rvec; public: - VectorStatData(Stat &stat) : s(stat) {} + VectorInfo(Stat &stat) : InfoWrap<Stat, VectorInfoBase>(stat) {} - virtual bool check() const { return s.check(); } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } + size_type size() const { return this->s.size(); } - virtual size_t size() const { return s.size(); } - virtual VCounter &value() const + VCounter & + value() const { - s.value(cvec); + this->s.value(cvec); return cvec; } - virtual const VResult &result() const + + const VResult & + result() const { - s.result(rvec); + this->s.result(rvec); return rvec; } - virtual Result total() const { return s.total(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } + + Result total() const { return this->s.total(); } }; -struct DistDataData +struct DistData { Counter min_val; Counter max_val; @@ -232,173 +254,146 @@ struct DistDataData Counter sum; Counter squares; Counter samples; - - Counter min; - Counter max; - Counter bucket_size; - int size; - bool fancy; }; -struct DistData : public StatData +class DistInfoBase : public Info { + public: /** Local storage for the entry values, used for printing. */ - DistDataData data; + DistData data; }; template <class Stat> -class DistStatData : public DistData +class DistInfo : public InfoWrap<Stat, DistInfoBase> { - protected: - Stat &s; - public: - DistStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - s.update(this); - visitor.visit(*this); - } + DistInfo(Stat &stat) : InfoWrap<Stat, DistInfoBase>(stat) {} }; -struct VectorDistData : public StatData +class VectorDistInfoBase : public Info { - std::vector<DistDataData> data; + public: + std::vector<DistData> data; - /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; + /** Names and descriptions of subfields. */ + std::vector<std::string> subnames; + std::vector<std::string> subdescs; + void enable(); + protected: /** Local storage for the entry values, used for printing. */ mutable VResult rvec; - virtual size_t size() const = 0; - void update() - { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } + public: + virtual size_type size() const = 0; }; template <class Stat> -class VectorDistStatData : public VectorDistData +class VectorDistInfo : public InfoWrap<Stat, VectorDistInfoBase> { - protected: - Stat &s; - public: - VectorDistStatData(Stat &stat) : s(stat) {} + VectorDistInfo(Stat &stat) : InfoWrap<Stat, VectorDistInfoBase>(stat) {} - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual size_t size() const { return s.size(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } + size_type size() const { return this->s.size(); } }; -struct Vector2dData : public StatData +class Vector2dInfoBase : public Info { + public: /** Names and descriptions of subfields. */ std::vector<std::string> subnames; std::vector<std::string> subdescs; std::vector<std::string> y_subnames; + size_type x; + size_type y; + /** Local storage for the entry values, used for printing. */ mutable VCounter cvec; - mutable int x; - mutable int y; - void update() - { - if (subnames.size() < x) - subnames.resize(x); - } + void enable(); }; template <class Stat> -class Vector2dStatData : public Vector2dData +class Vector2dInfo : public InfoWrap<Stat, Vector2dInfoBase> { - protected: - Stat &s; - public: - Vector2dStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } + Vector2dInfo(Stat &stat) : InfoWrap<Stat, Vector2dInfoBase>(stat) {} }; -class DataAccess +class InfoAccess { protected: - StatData *find() const; - void map(StatData *data); + /** Set up an info class for this statistic */ + void setInfo(Info *info); + /** Save Storage class parameters if any */ + void setParams(const StorageParams *params); + /** Save Storage class parameters if any */ + void setInit(); - StatData *statData(); - const StatData *statData() const; + /** Grab the information class for this statistic */ + Info *info(); + /** Grab the information class for this statistic */ + const Info *info() const; - void setInit(); - void setPrint(); + public: + /** + * Reset the stat to the default state. + */ + void reset() { } + + /** + * @return true if this stat has a value and satisfies its + * requirement as a prereq + */ + bool zero() const { return true; } + + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + bool check() const { return true; } }; -template <class Parent, class Child, template <class> class Data> -class Wrap : public Child +template <class Derived, template <class> class InfoType> +class DataWrap : public InfoAccess { + public: + typedef InfoType<Derived> Info; + protected: - Parent &self() { return *reinterpret_cast<Parent *>(this); } + Derived &self() { return *static_cast<Derived *>(this); } protected: - Data<Child> *statData() + Info * + info() { - StatData *__data = DataAccess::statData(); - Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data); - assert(ptr); - return ptr; + return safe_cast<Info *>(InfoAccess::info()); } public: - const Data<Child> *statData() const + const Info * + info() const { - const StatData *__data = DataAccess::statData(); - const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data); - assert(ptr); - return ptr; + return safe_cast<const Info *>(InfoAccess::info()); } protected: /** * Copy constructor, copies are not allowed. */ - Wrap(const Wrap &stat); + DataWrap(const DataWrap &stat); + /** * Can't copy stats. */ - void operator=(const Wrap &); + void operator=(const DataWrap &); public: - Wrap() + DataWrap() { - this->map(new Data<Child>(*this)); + this->setInfo(new Info(self())); } /** @@ -406,13 +401,15 @@ class Wrap : public Child * @param name The new name. * @return A reference to this stat. */ - Parent &name(const std::string &_name) + Derived & + name(const std::string &_name) { - Data<Child> *data = this->statData(); - data->name = _name; - this->setPrint(); + Info *info = this->info(); + info->name = _name; + info->flags |= print; return this->self(); } + const std::string &name() const { return this->info()->name; } /** * Set the description and marks this stat to print at the end of @@ -420,20 +417,22 @@ class Wrap : public Child * @param desc The new description. * @return A reference to this stat. */ - Parent &desc(const std::string &_desc) + Derived & + desc(const std::string &_desc) { - this->statData()->desc = _desc; + this->info()->desc = _desc; return this->self(); } /** * Set the precision and marks this stat to print at the end of simulation. - * @param p The new precision + * @param _precision The new precision * @return A reference to this stat. */ - Parent &precision(int _precision) + Derived & + precision(int _precision) { - this->statData()->precision = _precision; + this->info()->precision = _precision; return this->self(); } @@ -442,9 +441,10 @@ class Wrap : public Child * @param f The new flags. * @return A reference to this stat. */ - Parent &flags(StatFlags _flags) + Derived & + flags(StatFlags _flags) { - this->statData()->flags |= _flags; + this->info()->flags |= _flags; return this->self(); } @@ -455,17 +455,20 @@ class Wrap : public Child * @return A reference to this stat. */ template <class Stat> - Parent &prereq(const Stat &prereq) + Derived & + prereq(const Stat &prereq) { - this->statData()->prereq = prereq.statData(); + this->info()->prereq = prereq.info(); return this->self(); } }; -template <class Parent, class Child, template <class Child> class Data> -class WrapVec : public Wrap<Parent, Child, Data> +template <class Derived, template <class> class InfoType> +class DataWrapVec : public DataWrap<Derived, InfoType> { public: + typedef InfoType<Derived> Info; + // The following functions are specific to vectors. If you use them // in a non vector context, you will get a nice compiler error! @@ -476,15 +479,23 @@ class WrapVec : public Wrap<Parent, Child, Data> * @param name The new name of the subfield. * @return A reference to this stat. */ - Parent &subname(int index, const std::string &name) + Derived & + subname(off_type index, const std::string &name) { - std::vector<std::string> &subn = this->statData()->subnames; + Derived &self = this->self(); + Info *info = self.info(); + + std::vector<std::string> &subn = info->subnames; if (subn.size() <= index) subn.resize(index + 1); subn[index] = name; - return this->self(); + return self; } + // The following functions are specific to 2d vectors. If you use + // them in a non vector context, you will get a nice compiler + // error because info doesn't have the right variables. + /** * Set the subfield description for the given index and marks this stat to * print at the end of simulation. @@ -492,9 +503,12 @@ class WrapVec : public Wrap<Parent, Child, Data> * @param desc The new description of the subfield * @return A reference to this stat. */ - Parent &subdesc(int index, const std::string &desc) + Derived & + subdesc(off_type index, const std::string &desc) { - std::vector<std::string> &subd = this->statData()->subdescs; + Info *info = this->info(); + + std::vector<std::string> &subd = info->subdescs; if (subd.size() <= index) subd.resize(index + 1); subd[index] = desc; @@ -502,31 +516,61 @@ class WrapVec : public Wrap<Parent, Child, Data> return this->self(); } + void + prepare() + { + Derived &self = this->self(); + Info *info = this->info(); + + size_t size = self.size(); + for (off_type i = 0; i < size; ++i) + self.data(i)->prepare(info); + } + + void + reset() + { + Derived &self = this->self(); + Info *info = this->info(); + + size_t size = self.size(); + for (off_type i = 0; i < size; ++i) + self.data(i)->reset(info); + } }; -template <class Parent, class Child, template <class Child> class Data> -class WrapVec2d : public WrapVec<Parent, Child, Data> +template <class Derived, template <class> class InfoType> +class DataWrapVec2d : public DataWrapVec<Derived, InfoType> { public: + typedef InfoType<Derived> Info; + /** * @warning This makes the assumption that if you're gonna subnames a 2d * vector, you're subnaming across all y */ - Parent &ysubnames(const char **names) + Derived & + ysubnames(const char **names) { - Data<Child> *data = this->statData(); - data->y_subnames.resize(this->y); - for (int i = 0; i < this->y; ++i) - data->y_subnames[i] = names[i]; - return this->self(); + Derived &self = this->self(); + Info *info = this->info(); + + info->y_subnames.resize(self.y); + for (off_type i = 0; i < self.y; ++i) + info->y_subnames[i] = names[i]; + return self; } - Parent &ysubname(int index, const std::string subname) + + Derived & + ysubname(off_type index, const std::string subname) { - Data<Child> *data = this->statData(); - assert(index < this->y); - data->y_subnames.resize(this->y); - data->y_subnames[index] = subname.c_str(); - return this->self(); + Derived &self = this->self(); + Info *info = this->info(); + + assert(index < self.y); + info->y_subnames.resize(self.y); + info->y_subnames[index] = subname.c_str(); + return self; } }; @@ -539,57 +583,57 @@ class WrapVec2d : public WrapVec<Parent, Child, Data> /** * Templatized storage and interface for a simple scalar stat. */ -struct StatStor +class StatStor { - public: - /** The paramaters for this storage type, none for a scalar. */ - struct Params { }; - private: /** The statistic value. */ Counter data; public: + struct Params : public StorageParams {}; + + public: /** * Builds this storage element and calls the base constructor of the * datatype. */ - StatStor(const Params &) : data(Counter()) {} + StatStor(Info *info) + : data(Counter()) + { } /** * The the stat to the given value. * @param val The new value. - * @param p The paramters of this storage type. */ - void set(Counter val, const Params &p) { data = val; } + void set(Counter val) { data = val; } /** * Increment the stat by the given value. * @param val The new value. - * @param p The paramters of this storage type. */ - void inc(Counter val, const Params &p) { data += val; } + void inc(Counter val) { data += val; } /** * Decrement the stat by the given value. * @param val The new value. - * @param p The paramters of this storage type. */ - void dec(Counter val, const Params &p) { data -= val; } + void dec(Counter val) { data -= val; } /** * Return the value of this stat as its base type. - * @param p The params of this storage type. * @return The value of this stat. */ - Counter value(const Params &p) const { return data; } + Counter value() const { return data; } /** * Return the value of this stat as a result type. - * @param p The parameters of this storage type. * @return The value of this stat. */ - Result result(const Params &p) const { return (Result)data; } + Result result() const { return (Result)data; } + /** + * Prepare stat data for dumping or serialization + */ + void prepare(Info *info) { } /** * Reset stat value to default */ - void reset() { data = Counter(); } + void reset(Info *info) { data = Counter(); } /** * @return true if zero value @@ -604,12 +648,8 @@ struct StatStor * being watched. This is good for keeping track of residencies in structures * among other things. */ -struct AvgStor +class AvgStor { - public: - /** The paramaters for this storage type */ - struct Params { }; - private: /** The current count. */ Counter current; @@ -619,18 +659,24 @@ struct AvgStor mutable Tick last; public: + struct Params : public StorageParams {}; + + public: /** * Build and initializes this stat storage. */ - AvgStor(Params &p) : current(0), total(0), last(0) { } + AvgStor(Info *info) + : current(0), total(0), last(0) + { } /** * Set the current count to the one provided, update the total and last * set values. * @param val The new count. - * @param p The parameters for this storage. */ - void set(Counter val, Params &p) { + void + set(Counter val) + { total += current * (curTick - last); last = curTick; current = val; @@ -639,71 +685,74 @@ struct AvgStor /** * Increment the current count by the provided value, calls set. * @param val The amount to increment. - * @param p The parameters for this storage. */ - void inc(Counter val, Params &p) { set(current + val, p); } + void inc(Counter val) { set(current + val); } /** * Deccrement the current count by the provided value, calls set. * @param val The amount to decrement. - * @param p The parameters for this storage. */ - void dec(Counter val, Params &p) { set(current - val, p); } + void dec(Counter val) { set(current - val); } /** * Return the current count. - * @param p The parameters for this storage. * @return The current count. */ - Counter value(const Params &p) const { return current; } + Counter value() const { return current; } /** * Return the current average. - * @param p The parameters for this storage. * @return The current average. */ - Result result(const Params &p) const + Result + result() const { - total += current * (curTick - last); - last = curTick; + assert(last == curTick); return (Result)(total + current) / (Result)(curTick + 1); } /** - * Reset stat value to default + * @return true if zero value */ - void reset() + bool zero() const { return total == 0.0; } + + /** + * Prepare stat data for dumping or serialization + */ + void + prepare(Info *info) { - total = 0; + total += current * (curTick - last); last = curTick; } /** - * @return true if zero value + * Reset stat value to default */ - bool zero() const { return total == 0.0; } + void + reset(Info *info) + { + total = 0.0; + last = curTick; + } + }; /** * Implementation of a scalar stat. The type of stat is determined by the * Storage template. */ -template <class Stor> -class ScalarBase : public DataAccess +template <class Derived, class Stor> +class ScalarBase : public DataWrap<Derived, ScalarInfo> { public: typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; protected: /** The storage of this stat. */ char storage[sizeof(Storage)] __attribute__ ((aligned (8))); - /** The parameters for this stat. */ - Params params; - protected: /** * Retrieve the storage. @@ -731,8 +780,8 @@ class ScalarBase : public DataAccess void doInit() { - new (storage) Storage(params); - setInit(); + new (storage) Storage(this->info()); + this->setInit(); } public: @@ -740,14 +789,13 @@ class ScalarBase : public DataAccess * Return the current value of this stat as its base type. * @return The current value. */ - Counter value() const { return data()->value(params); } + Counter value() const { return data()->value(); } public: - /** - * Create and initialize this stat, register it with the database. - */ ScalarBase() - { } + { + this->doInit(); + } public: // Common operators for stats @@ -755,12 +803,12 @@ class ScalarBase : public DataAccess * Increment the stat by 1. This calls the associated storage object inc * function. */ - void operator++() { data()->inc(1, params); } + void operator++() { data()->inc(1); } /** * Decrement the stat by 1. This calls the associated storage object dec * function. */ - void operator--() { data()->dec(1, params); } + void operator--() { data()->dec(1); } /** Increment the stat by 1. */ void operator++(int) { ++*this; } @@ -773,7 +821,7 @@ class ScalarBase : public DataAccess * @param v The new value. */ template <typename U> - void operator=(const U &v) { data()->set(v, params); } + void operator=(const U &v) { data()->set(v); } /** * Increment the stat by the given value. This calls the associated @@ -781,7 +829,7 @@ class ScalarBase : public DataAccess * @param v The value to add. */ template <typename U> - void operator+=(const U &v) { data()->inc(v, params); } + void operator+=(const U &v) { data()->inc(v); } /** * Decrement the stat by the given value. This calls the associated @@ -789,99 +837,102 @@ class ScalarBase : public DataAccess * @param v The value to substract. */ template <typename U> - void operator-=(const U &v) { data()->dec(v, params); } + void operator-=(const U &v) { data()->dec(v); } /** * Return the number of elements, always 1 for a scalar. * @return 1. */ - size_t size() const { return 1; } + size_type size() const { return 1; } - bool check() const { return true; } - - /** - * Reset stat value to default - */ - void reset() { data()->reset(); } + Counter value() { return data()->value(); } - Counter value() { return data()->value(params); } - - Result result() { return data()->result(params); } + Result result() { return data()->result(); } Result total() { return result(); } bool zero() { return result() == 0.0; } + void reset() { data()->reset(this->info()); } + void prepare() { data()->prepare(this->info()); } }; -class ProxyData : public ScalarData +class ProxyInfo : public ScalarInfoBase { public: - virtual void visit(Visit &visitor) { visitor.visit(*this); } - virtual std::string str() const { return to_string(value()); } - virtual size_t size() const { return 1; } - virtual bool zero() const { return value() == 0; } - virtual bool check() const { return true; } - virtual void reset() { } + std::string str() const { return to_string(value()); } + size_type size() const { return 1; } + bool check() const { return true; } + void prepare() { } + void reset() { } + bool zero() const { return value() == 0; } + + void visit(Visit &visitor) { visitor.visit(*this); } }; template <class T> -class ValueProxy : public ProxyData +class ValueProxy : public ProxyInfo { private: T *scalar; public: ValueProxy(T &val) : scalar(&val) {} - virtual Counter value() const { return *scalar; } - virtual Result result() const { return *scalar; } - virtual Result total() const { return *scalar; } + Counter value() const { return *scalar; } + Result result() const { return *scalar; } + Result total() const { return *scalar; } }; template <class T> -class FunctorProxy : public ProxyData +class FunctorProxy : public ProxyInfo { private: T *functor; public: FunctorProxy(T &func) : functor(&func) {} - virtual Counter value() const { return (*functor)(); } - virtual Result result() const { return (*functor)(); } - virtual Result total() const { return (*functor)(); } + Counter value() const { return (*functor)(); } + Result result() const { return (*functor)(); } + Result total() const { return (*functor)(); } }; -class ValueBase : public DataAccess +template <class Derived> +class ValueBase : public DataWrap<Derived, ScalarInfo> { private: - ProxyData *proxy; + ProxyInfo *proxy; public: ValueBase() : proxy(NULL) { } ~ValueBase() { if (proxy) delete proxy; } template <class T> - void scalar(T &value) + Derived & + scalar(T &value) { proxy = new ValueProxy<T>(value); - setInit(); + this->setInit(); + return this->self(); } template <class T> - void functor(T &func) + Derived & + functor(T &func) { proxy = new FunctorProxy<T>(func); - setInit(); + this->setInit(); + return this->self(); } Counter value() { return proxy->value(); } Result result() const { return proxy->result(); } Result total() const { return proxy->total(); }; - size_t size() const { return proxy->size(); } + size_type size() const { return proxy->size(); } std::string str() const { return proxy->str(); } bool zero() const { return proxy->zero(); } bool check() const { return proxy != NULL; } + void prepare() { } void reset() { } }; @@ -900,34 +951,32 @@ class ScalarProxy { private: /** Pointer to the parent Vector. */ - Stat *stat; + Stat &stat; /** The index to access in the parent VectorBase. */ - int index; + off_type index; public: /** * Return the current value of this stat as its base type. * @return The current value. */ - Counter value() const { return stat->data(index)->value(stat->params); } + Counter value() const { return stat.data(index)->value(); } /** * Return the current value of this statas a result type. * @return The current value. */ - Result result() const { return stat->data(index)->result(stat->params); } + Result result() const { return stat.data(index)->result(); } public: /** * Create and initialize this proxy, do not register it with the database. - * @param p The params to use. * @param i The index to access. */ - ScalarProxy(Stat *s, int i) + ScalarProxy(Stat &s, off_type i) : stat(s), index(i) { - assert(stat); } /** @@ -943,7 +992,9 @@ class ScalarProxy * @param sp The proxy to copy. * @return A reference to this proxy. */ - const ScalarProxy &operator=(const ScalarProxy &sp) { + const ScalarProxy & + operator=(const ScalarProxy &sp) + { stat = sp.stat; index = sp.index; return *this; @@ -955,12 +1006,12 @@ class ScalarProxy * Increment the stat by 1. This calls the associated storage object inc * function. */ - void operator++() { stat->data(index)->inc(1, stat->params); } + void operator++() { stat.data(index)->inc(1); } /** * Decrement the stat by 1. This calls the associated storage object dec * function. */ - void operator--() { stat->data(index)->dec(1, stat->params); } + void operator--() { stat.data(index)->dec(1); } /** Increment the stat by 1. */ void operator++(int) { ++*this; } @@ -973,7 +1024,11 @@ class ScalarProxy * @param v The new value. */ template <typename U> - void operator=(const U &v) { stat->data(index)->set(v, stat->params); } + void + operator=(const U &v) + { + stat.data(index)->set(v); + } /** * Increment the stat by the given value. This calls the associated @@ -981,7 +1036,11 @@ class ScalarProxy * @param v The value to add. */ template <typename U> - void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); } + void + operator+=(const U &v) + { + stat.data(index)->inc(v); + } /** * Decrement the stat by the given value. This calls the associated @@ -989,25 +1048,23 @@ class ScalarProxy * @param v The value to substract. */ template <typename U> - void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); } + void + operator-=(const U &v) + { + stat.data(index)->dec(v); + } /** * Return the number of elements, always 1 for a scalar. * @return 1. */ - size_t size() const { return 1; } - - /** - * This stat has no state. Nothing to reset - */ - void reset() { } + size_type size() const { return 1; } public: std::string str() const { - return csprintf("%s[%d]", stat->str(), index); - + return csprintf("%s[%d]", stat.info()->name, index); } }; @@ -1015,27 +1072,22 @@ class ScalarProxy * Implementation of a vector of stats. The type of stat is determined by the * Storage class. @sa ScalarBase */ -template <class Stor> -class VectorBase : public DataAccess +template <class Derived, class Stor> +class VectorBase : public DataWrapVec<Derived, VectorInfo> { public: typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; /** Proxy type */ - typedef ScalarProxy<VectorBase<Storage> > Proxy; - - friend class ScalarProxy<VectorBase<Storage> >; + typedef ScalarProxy<Derived> Proxy; + friend class ScalarProxy<Derived>; + friend class DataWrapVec<Derived, VectorInfo>; protected: /** The storage of this stat. */ Storage *storage; - size_t _size; - - /** The parameters for this stat. */ - Params params; + size_type _size; protected: /** @@ -1043,17 +1095,17 @@ class VectorBase : public DataAccess * @param index The vector index to access. * @return The storage object at the given index. */ - Storage *data(int index) { return &storage[index]; } + Storage *data(off_type index) { return &storage[index]; } /** * Retrieve a const pointer to the storage. * @param index The vector index to access. * @return A const pointer to the storage object at the given index. */ - const Storage *data(int index) const { return &storage[index]; } + const Storage *data(off_type index) const { return &storage[index]; } void - doInit(int s) + doInit(size_type s) { assert(s > 0 && "size must be positive!"); assert(!storage && "already initialized"); @@ -1062,51 +1114,55 @@ class VectorBase : public DataAccess char *ptr = new char[_size * sizeof(Storage)]; storage = reinterpret_cast<Storage *>(ptr); - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(this->info()); - setInit(); + this->setInit(); } public: - void value(VCounter &vec) const + void + value(VCounter &vec) const { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->value(params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->value(); } /** * Copy the values to a local vector and return a reference to it. * @return A reference to a vector of the stat values. */ - void result(VResult &vec) const + void + result(VResult &vec) const { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->result(); } /** * Return a total of all entries in this vector. * @return The total of all vector entries. */ - Result total() const { + Result + total() const + { Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(params); + for (off_type i = 0; i < size(); ++i) + total += data(i)->result(); return total; } /** * @return the number of elements in this vector. */ - size_t size() const { return _size; } + size_type size() const { return _size; } bool zero() const { - for (int i = 0; i < size(); ++i) + for (off_type i = 0; i < size(); ++i) if (data(i)->zero()) return false; return true; @@ -1118,13 +1174,6 @@ class VectorBase : public DataAccess return storage != NULL; } - void - reset() - { - for (int i = 0; i < size(); ++i) - data(i)->reset(); - } - public: VectorBase() : storage(NULL) @@ -1135,49 +1184,60 @@ class VectorBase : public DataAccess if (!storage) return; - for (int i = 0; i < _size; ++i) + for (off_type i = 0; i < _size; ++i) data(i)->~Storage(); delete [] reinterpret_cast<char *>(storage); } /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + Derived & + init(size_type size) + { + Derived &self = this->self(); + self.doInit(size); + return self; + } + + /** * Return a reference (ScalarProxy) to the stat at the given index. * @param index The vector index to access. * @return A reference of the stat. */ Proxy - operator[](int index) + operator[](off_type index) { assert (index >= 0 && index < size()); - return Proxy(this, index); + return Proxy(this->self(), index); } - - void update(StatData *data) {} }; template <class Stat> class VectorProxy { private: - Stat *stat; - int offset; - int len; + Stat &stat; + off_type offset; + size_type len; private: mutable VResult vec; typename Stat::Storage * - data(int index) + data(off_type index) { assert(index < len); - return stat->data(offset + index); + return stat.data(offset + index); } const typename Stat::Storage * - data(int index) const + data(off_type index) const { assert(index < len); - return const_cast<Stat *>(stat)->data(offset + index); + return stat.data(offset + index); } public: @@ -1186,8 +1246,8 @@ class VectorProxy { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(stat->params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->result(); return vec; } @@ -1195,14 +1255,14 @@ class VectorProxy Result total() const { - Result total = 0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(stat->params); + Result total = 0.0; + for (off_type i = 0; i < size(); ++i) + total += data(i)->result(); return total; } public: - VectorProxy(Stat *s, int o, int l) + VectorProxy(Stat &s, off_type o, size_type l) : stat(s), offset(o), len(l) { } @@ -1221,63 +1281,38 @@ class VectorProxy return *this; } - ScalarProxy<Stat> operator[](int index) + ScalarProxy<Stat> + operator[](off_type index) { assert (index >= 0 && index < size()); return ScalarProxy<Stat>(stat, offset + index); } - size_t size() const { return len; } - - /** - * This stat has no state. Nothing to reset. - */ - void reset() { } + size_type size() const { return len; } }; -template <class Stor> -class Vector2dBase : public DataAccess +template <class Derived, class Stor> +class Vector2dBase : public DataWrapVec2d<Derived, Vector2dInfo> { public: + typedef Vector2dInfo<Derived> Info; typedef Stor Storage; - typedef typename Storage::Params Params; - typedef VectorProxy<Vector2dBase<Storage> > Proxy; - friend class ScalarProxy<Vector2dBase<Storage> >; - friend class VectorProxy<Vector2dBase<Storage> >; + typedef typename Stor::Params Params; + typedef VectorProxy<Derived> Proxy; + friend class ScalarProxy<Derived>; + friend class VectorProxy<Derived>; + friend class DataWrapVec<Derived, Vector2dInfo>; + friend class DataWrapVec2d<Derived, Vector2dInfo>; protected: - size_t x; - size_t y; - size_t _size; + size_type x; + size_type y; + size_type _size; Storage *storage; - Params params; protected: - Storage *data(int index) { return &storage[index]; } - const Storage *data(int index) const { return &storage[index]; } - - void - doInit(int _x, int _y) - { - assert(_x > 0 && _y > 0 && "sizes must be positive!"); - assert(!storage && "already initialized"); - - Vector2dData *statdata = dynamic_cast<Vector2dData *>(find()); - - x = _x; - y = _y; - statdata->x = _x; - statdata->y = _y; - _size = x * y; - - char *ptr = new char[_size * sizeof(Storage)]; - storage = reinterpret_cast<Storage *>(ptr); - - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); - - setInit(); - } + Storage *data(off_type index) { return &storage[index]; } + const Storage *data(off_type index) const { return &storage[index]; } public: Vector2dBase() @@ -1289,32 +1324,49 @@ class Vector2dBase : public DataAccess if (!storage) return; - for (int i = 0; i < _size; ++i) + for (off_type i = 0; i < _size; ++i) data(i)->~Storage(); delete [] reinterpret_cast<char *>(storage); } - void - update(Vector2dData *newdata) + Derived & + init(size_type _x, size_type _y) { - int size = this->size(); - newdata->cvec.resize(size); - for (int i = 0; i < size; ++i) - newdata->cvec[i] = data(i)->value(params); + assert(_x > 0 && _y > 0 && "sizes must be positive!"); + assert(!storage && "already initialized"); + + Derived &self = this->self(); + Info *info = this->info(); + + x = _x; + y = _y; + info->x = _x; + info->y = _y; + _size = x * y; + + char *ptr = new char[_size * sizeof(Storage)]; + storage = reinterpret_cast<Storage *>(ptr); + + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(info); + + this->setInit(); + + return self; } - std::string ysubname(int i) const { return (*this->y_subnames)[i]; } + std::string ysubname(off_type i) const { return (*this->y_subnames)[i]; } Proxy - operator[](int index) + operator[](off_type index) { - int offset = index * y; + off_type offset = index * y; assert (index >= 0 && offset + index < size()); - return Proxy(this, offset, y); + return Proxy(this->self(), offset, y); } - size_t + size_type size() const { return _size; @@ -1325,25 +1377,41 @@ class Vector2dBase : public DataAccess { return data(0)->zero(); #if 0 - for (int i = 0; i < size(); ++i) + for (off_type i = 0; i < size(); ++i) if (!data(i)->zero()) return false; return true; #endif } + void + prepare() + { + Info *info = this->info(); + size_type size = this->size(); + + for (off_type i = 0; i < size; ++i) + data(i)->prepare(info); + + info->cvec.resize(size); + for (off_type i = 0; i < size; ++i) + info->cvec[i] = data(i)->value(); + } + /** * Reset stat value to default */ void reset() { - for (int i = 0; i < size(); ++i) - data(i)->reset(); + Info *info = this->info(); + size_type size = this->size(); + for (off_type i = 0; i < size; ++i) + data(i)->reset(info); } bool - check() + check() const { return storage != NULL; } @@ -1355,27 +1423,44 @@ class Vector2dBase : public DataAccess // ////////////////////////////////////////////////////////////////////// +struct DistParams : public StorageParams +{ + const bool fancy; + + /** The minimum value to track. */ + Counter min; + /** The maximum value to track. */ + Counter max; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The number of buckets. Equal to (max-min)/bucket_size. */ + size_type buckets; + + explicit DistParams(bool f) : fancy(f) {} +}; + /** * Templatized storage and interface for a distrbution stat. */ -struct DistStor +class DistStor { public: /** The parameters for a distribution stat. */ - struct Params - { - /** The minimum value to track. */ - Counter min; - /** The maximum value to track. */ - Counter max; - /** The number of entries in each bucket. */ - Counter bucket_size; - /** The number of buckets. Equal to (max-min)/bucket_size. */ - int size; + struct Params : public DistParams + { + Params() : DistParams(false) {} }; - enum { fancy = false }; private: + /** The minimum value to track. */ + Counter min_track; + /** The maximum value to track. */ + Counter max_track; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The number of buckets. Equal to (max-min)/bucket_size. */ + size_type buckets; + /** The smallest value sampled. */ Counter min_val; /** The largest value sampled. */ @@ -1394,27 +1479,28 @@ struct DistStor VCounter cvec; public: - DistStor(const Params ¶ms) - : cvec(params.size) + DistStor(Info *info) + : cvec(safe_cast<const Params *>(info->storageParams)->buckets) { - reset(); + reset(info); } /** * Add a value to the distribution for the given number of times. * @param val The value to add. * @param number The number of times to add the value. - * @param params The paramters of the distribution. */ - void sample(Counter val, int number, const Params ¶ms) + void + sample(Counter val, int number) { - if (val < params.min) + if (val < min_track) underflow += number; - else if (val > params.max) + else if (val > max_track) overflow += number; else { - int index = (int)std::floor((val - params.min) / params.bucket_size); - assert(index < size(params)); + size_type index = + (size_type)std::floor((val - min_track) / bucket_size); + assert(index < size()); cvec[index] += number; } @@ -1433,52 +1519,57 @@ struct DistStor /** * Return the number of buckets in this distribution. * @return the number of buckets. - * @todo Is it faster to return the size from the parameters? */ - size_t size(const Params &) const { return cvec.size(); } + size_type size() const { return cvec.size(); } /** * Returns true if any calls to sample have been made. - * @param params The paramters of the distribution. * @return True if any values have been sampled. */ - bool zero(const Params ¶ms) const + bool + zero() const { return samples == Counter(); } - void update(DistDataData *data, const Params ¶ms) + void + prepare(Info *info, DistData &data) { - data->min = params.min; - data->max = params.max; - data->bucket_size = params.bucket_size; - data->size = params.size; + const Params *params = safe_cast<const Params *>(info->storageParams); - data->min_val = (min_val == INT_MAX) ? 0 : min_val; - data->max_val = (max_val == INT_MIN) ? 0 : max_val; - data->underflow = underflow; - data->overflow = overflow; - data->cvec.resize(params.size); - for (int i = 0; i < params.size; ++i) - data->cvec[i] = cvec[i]; + data.min_val = (min_val == CounterLimits::max()) ? 0 : min_val; + data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val; + data.underflow = underflow; + data.overflow = overflow; - data->sum = sum; - data->squares = squares; - data->samples = samples; + int buckets = params->buckets; + data.cvec.resize(buckets); + for (off_type i = 0; i < buckets; ++i) + data.cvec[i] = cvec[i]; + + data.sum = sum; + data.squares = squares; + data.samples = samples; } /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { - min_val = INT_MAX; - max_val = INT_MIN; + const Params *params = safe_cast<const Params *>(info->storageParams); + min_track = params->min; + max_track = params->max; + bucket_size = params->bucket_size; + + min_val = CounterLimits::max(); + max_val = CounterLimits::min(); underflow = 0; overflow = 0; - int size = cvec.size(); - for (int i = 0; i < size; ++i) + size_type size = cvec.size(); + for (off_type i = 0; i < size; ++i) cvec[i] = Counter(); sum = Counter(); @@ -1491,14 +1582,13 @@ struct DistStor * Templatized storage and interface for a distribution that calculates mean * and variance. */ -struct FancyStor +class FancyStor { public: - /** - * No paramters for this storage. - */ - struct Params {}; - enum { fancy = true }; + struct Params : public DistParams + { + Params() : DistParams(true) {} + }; private: /** The current sum. */ @@ -1512,7 +1602,7 @@ struct FancyStor /** * Create and initialize this storage. */ - FancyStor(const Params &) + FancyStor(Info *info) : sum(Counter()), squares(Counter()), samples(Counter()) { } @@ -1522,9 +1612,9 @@ struct FancyStor * values seen by the given number. * @param val The value to add. * @param number The number of times to add the value. - * @param p The parameters of this stat. */ - void sample(Counter val, int number, const Params &p) + void + sample(Counter val, int number) { Counter value = val * number; sum += value; @@ -1532,29 +1622,31 @@ struct FancyStor samples += number; } - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = samples; - } - /** * Return the number of entries in this stat, 1 * @return 1. */ - size_t size(const Params &) const { return 1; } + size_type size() const { return 1; } /** * Return true if no samples have been added. * @return True if no samples have been added. */ - bool zero(const Params &) const { return samples == Counter(); } + bool zero() const { return samples == Counter(); } + + void + prepare(Info *info, DistData &data) + { + data.sum = sum; + data.squares = squares; + data.samples = samples; + } /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { sum = Counter(); squares = Counter(); @@ -1566,12 +1658,13 @@ struct FancyStor * Templatized storage for distribution that calculates per tick mean and * variance. */ -struct AvgFancy +class AvgFancy { public: - /** No parameters for this storage. */ - struct Params {}; - enum { fancy = true }; + struct Params : public DistParams + { + Params() : DistParams(true) {} + }; private: /** Current total. */ @@ -1583,43 +1676,49 @@ struct AvgFancy /** * Create and initialize this storage. */ - AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} + AvgFancy(Info *info) + : sum(Counter()), squares(Counter()) + {} /** * Add a value to the distribution for the given number of times. * Update the running sum and sum of squares. * @param val The value to add. * @param number The number of times to add the value. - * @param p The paramters of the distribution. */ - void sample(Counter val, int number, const Params &p) + void + sample(Counter val, int number) { Counter value = val * number; sum += value; squares += value * value; } - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = curTick; - } - /** * Return the number of entries, in this case 1. * @return 1. */ - size_t size(const Params ¶ms) const { return 1; } + size_type size() const { return 1; } + /** * Return true if no samples have been added. * @return True if the sum is zero. */ - bool zero(const Params ¶ms) const { return sum == Counter(); } + bool zero() const { return sum == Counter(); } + + void + prepare(Info *info, DistData &data) + { + data.sum = sum; + data.squares = squares; + data.samples = curTick; + } + /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { sum = Counter(); squares = Counter(); @@ -1630,27 +1729,25 @@ struct AvgFancy * Implementation of a distribution stat. The type of distribution is * determined by the Storage template. @sa ScalarBase */ -template <class Stor> -class DistBase : public DataAccess +template <class Derived, class Stor> +class DistBase : public DataWrap<Derived, DistInfo> { public: + typedef DistInfo<Derived> Info; typedef Stor Storage; - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; protected: /** The storage for this stat. */ char storage[sizeof(Storage)] __attribute__ ((aligned (8))); - /** The parameters for this stat. */ - Params params; - protected: /** * Retrieve the storage. * @return The storage object for this stat. */ - Storage *data() + Storage * + data() { return reinterpret_cast<Storage *>(storage); } @@ -1668,8 +1765,8 @@ class DistBase : public DataAccess void doInit() { - new (storage) Storage(params); - setInit(); + new (storage) Storage(this->info()); + this->setInit(); } public: @@ -1682,23 +1779,24 @@ class DistBase : public DataAccess * @param n The number of times to add it, defaults to 1. */ template <typename U> - void sample(const U &v, int n = 1) { data()->sample(v, n, params); } + void sample(const U &v, int n = 1) { data()->sample(v, n); } /** * Return the number of entries in this stat. * @return The number of entries. */ - size_t size() const { return data()->size(params); } + size_type size() const { return data()->size(); } /** * Return true if no samples have been added. * @return True if there haven't been any samples. */ - bool zero() const { return data()->zero(params); } + bool zero() const { return data()->zero(); } - void update(DistData *base) + void + prepare() { - base->data.fancy = Storage::fancy; - data()->update(&(base->data), params); + Info *info = this->info(); + data()->prepare(info, info->data); } /** @@ -1707,48 +1805,43 @@ class DistBase : public DataAccess void reset() { - data()->reset(); - } - - bool - check() - { - return true; + data()->reset(this->info()); } }; template <class Stat> class DistProxy; -template <class Stor> -class VectorDistBase : public DataAccess +template <class Derived, class Stor> +class VectorDistBase : public DataWrapVec<Derived, VectorDistInfo> { public: + typedef VectorDistInfo<Derived> Info; typedef Stor Storage; - typedef typename Storage::Params Params; - typedef DistProxy<VectorDistBase<Storage> > Proxy; - friend class DistProxy<VectorDistBase<Storage> >; + typedef typename Stor::Params Params; + typedef DistProxy<Derived> Proxy; + friend class DistProxy<Derived>; + friend class DataWrapVec<Derived, VectorDistInfo>; protected: Storage *storage; - size_t _size; - Params params; + size_type _size; protected: Storage * - data(int index) + data(off_type index) { return &storage[index]; } const Storage * - data(int index) const + data(off_type index) const { return &storage[index]; } void - doInit(int s) + doInit(size_type s) { assert(s > 0 && "size must be positive!"); assert(!storage && "already initialized"); @@ -1757,10 +1850,11 @@ class VectorDistBase : public DataAccess char *ptr = new char[_size * sizeof(Storage)]; storage = reinterpret_cast<Storage *>(ptr); - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); + Info *info = this->info(); + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(info); - setInit(); + this->setInit(); } public: @@ -1773,14 +1867,14 @@ class VectorDistBase : public DataAccess if (!storage) return ; - for (int i = 0; i < _size; ++i) + for (off_type i = 0; i < _size; ++i) data(i)->~Storage(); delete [] reinterpret_cast<char *>(storage); } - Proxy operator[](int index); + Proxy operator[](off_type index); - size_t + size_type size() const { return _size; @@ -1791,39 +1885,28 @@ class VectorDistBase : public DataAccess { return false; #if 0 - for (int i = 0; i < size(); ++i) - if (!data(i)->zero(params)) + for (off_type i = 0; i < size(); ++i) + if (!data(i)->zero()) return false; return true; #endif } - /** - * Reset stat value to default - */ void - reset() + prepare() { - for (int i = 0; i < size(); ++i) - data(i)->reset(); + Info *info = this->info(); + size_type size = this->size(); + info->data.resize(size); + for (off_type i = 0; i < size; ++i) + data(i)->prepare(info, info->data[i]); } bool - check() + check() const { return storage != NULL; } - - void - update(VectorDistData *base) - { - int size = this->size(); - base->data.resize(size); - for (int i = 0; i < size; ++i) { - base->data[i].fancy = Storage::fancy; - data(i)->update(&(base->data[i]), params); - } - } }; template <class Stat> @@ -1831,14 +1914,14 @@ class DistProxy { private: Stat *stat; - int index; + off_type index; protected: typename Stat::Storage *data() { return stat->data(index); } const typename Stat::Storage *data() const { return stat->data(index); } public: - DistProxy(Stat *s, int i) + DistProxy(Stat *s, off_type i) : stat(s), index(i) {} @@ -1846,7 +1929,8 @@ class DistProxy : stat(sp.stat), index(sp.index) {} - const DistProxy &operator=(const DistProxy &sp) + const DistProxy & + operator=(const DistProxy &sp) { stat = sp.stat; index = sp.index; @@ -1858,10 +1942,10 @@ class DistProxy void sample(const U &v, int n = 1) { - data()->sample(v, n, stat->params); + data()->sample(v, n); } - size_t + size_type size() const { return 1; @@ -1870,7 +1954,7 @@ class DistProxy bool zero() const { - return data()->zero(stat->params); + return data()->zero(); } /** @@ -1879,23 +1963,23 @@ class DistProxy void reset() { } }; -template <class Storage> -inline typename VectorDistBase<Storage>::Proxy -VectorDistBase<Storage>::operator[](int index) +template <class Derived, class Stor> +inline typename VectorDistBase<Derived, Stor>::Proxy +VectorDistBase<Derived, Stor>::operator[](off_type index) { assert (index >= 0 && index < size()); - return typename VectorDistBase<Storage>::Proxy(this, index); + typedef typename VectorDistBase<Derived, Stor>::Proxy Proxy; + return Proxy(this, index); } #if 0 template <class Storage> Result -VectorDistBase<Storage>::total(int index) const +VectorDistBase<Storage>::total(off_type index) const { - int total = 0; - for (int i = 0; i < x_size(); ++i) { - total += data(i)->result(stat->params); - } + Result total = 0.0; + for (off_type i = 0; i < x_size(); ++i) + total += data(i)->result(); } #endif @@ -1916,7 +2000,7 @@ class Node : public RefCounted * Return the number of nodes in the subtree starting at this node. * @return the number of nodes in this subtree. */ - virtual size_t size() const = 0; + virtual size_type size() const = 0; /** * Return the result vector of this subtree. * @return The result vector of this subtree. @@ -1940,24 +2024,27 @@ typedef RefCountingPtr<Node> NodePtr; class ScalarStatNode : public Node { private: - const ScalarData *data; + const ScalarInfoBase *data; mutable VResult vresult; public: - ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} - virtual const VResult &result() const + ScalarStatNode(const ScalarInfoBase *d) : data(d), vresult(1) {} + + const VResult & + result() const { vresult[0] = data->result(); return vresult; } - virtual Result total() const { return data->result(); }; - virtual size_t size() const { return 1; } + Result total() const { return data->result(); }; + + size_type size() const { return 1; } /** * */ - virtual std::string str() const { return data->name; } + std::string str() const { return data->name; } }; template <class Stat> @@ -1972,20 +2059,20 @@ class ScalarProxyNode : public Node : proxy(p), vresult(1) { } - virtual const VResult & + const VResult & result() const { vresult[0] = proxy.result(); return vresult; } - virtual Result + Result total() const { return proxy.result(); } - virtual size_t + size_type size() const { return 1; @@ -1994,7 +2081,7 @@ class ScalarProxyNode : public Node /** * */ - virtual std::string + std::string str() const { return proxy.str(); @@ -2004,16 +2091,16 @@ class ScalarProxyNode : public Node class VectorStatNode : public Node { private: - const VectorData *data; + const VectorInfoBase *data; public: - VectorStatNode(const VectorData *d) : data(d) { } - virtual const VResult &result() const { return data->result(); } - virtual Result total() const { return data->total(); }; + VectorStatNode(const VectorInfoBase *d) : data(d) { } + const VResult &result() const { return data->result(); } + Result total() const { return data->total(); }; - virtual size_t size() const { return data->size(); } + size_type size() const { return data->size(); } - virtual std::string str() const { return data->name; } + std::string str() const { return data->name; } }; template <class T> @@ -2025,9 +2112,9 @@ class ConstNode : public Node public: ConstNode(T s) : vresult(1, (Result)s) {} const VResult &result() const { return vresult; } - virtual Result total() const { return vresult[0]; }; - virtual size_t size() const { return 1; } - virtual std::string str() const { return to_string(vresult[0]); } + Result total() const { return vresult[0]; }; + size_type size() const { return 1; } + std::string str() const { return to_string(vresult[0]); } }; template <class T> @@ -2039,25 +2126,25 @@ class ConstVectorNode : public Node public: ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {} const VResult &result() const { return vresult; } - virtual Result total() const + + Result + total() const { - int size = this->size(); + size_type size = this->size(); Result tmp = 0; - for (int i = 0; i < size; i++) - { + for (off_type i = 0; i < size; i++) tmp += vresult[i]; - } return tmp; } - virtual size_t size() const { return vresult.size(); } - virtual std::string str() const + + size_type size() const { return vresult.size(); } + std::string + str() const { - int size = this->size(); + size_type size = this->size(); std::string tmp = "("; - for (int i = 0; i < size; i++) - { + for (off_type i = 0; i < size; i++) tmp += csprintf("%s ",to_string(vresult[i])); - } tmp += ")"; return tmp; } @@ -2112,33 +2199,36 @@ class UnaryNode : public Node public: UnaryNode(NodePtr &p) : l(p) {} - const VResult &result() const + const VResult & + result() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); vresult.resize(size); Op op; - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i]); return vresult; } - Result total() const + Result + total() const { const VResult &vec = this->result(); - Result total = 0; - for (int i = 0; i < size(); i++) + Result total = 0.0; + for (off_type i = 0; i < size(); i++) total += vec[i]; return total; } - virtual size_t size() const { return l->size(); } + size_type size() const { return l->size(); } - virtual std::string str() const + std::string + str() const { return OpString<Op>::str() + l->str(); } @@ -2155,7 +2245,8 @@ class BinaryNode : public Node public: BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} - const VResult &result() const + const VResult & + result() const { Op op; const VResult &lvec = l->result(); @@ -2167,48 +2258,52 @@ class BinaryNode : public Node vresult.resize(1); vresult[0] = op(lvec[0], rvec[0]); } else if (lvec.size() == 1) { - int size = rvec.size(); + size_type size = rvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[0], rvec[i]); } else if (rvec.size() == 1) { - int size = lvec.size(); + size_type size = lvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i], rvec[0]); } else if (rvec.size() == lvec.size()) { - int size = rvec.size(); + size_type size = rvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i], rvec[i]); } return vresult; } - Result total() const + Result + total() const { const VResult &vec = this->result(); - Result total = 0; - for (int i = 0; i < size(); i++) + Result total = 0.0; + for (off_type i = 0; i < size(); i++) total += vec[i]; return total; } - virtual size_t size() const { - int ls = l->size(); - int rs = r->size(); - if (ls == 1) + size_type + size() const + { + size_type ls = l->size(); + size_type rs = r->size(); + if (ls == 1) { return rs; - else if (rs == 1) + } else if (rs == 1) { return ls; - else { + } else { assert(ls == rs && "Node vector sizes are not equal"); return ls; } } - virtual std::string str() const + std::string + str() const { return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); } @@ -2224,39 +2319,42 @@ class SumNode : public Node public: SumNode(NodePtr &p) : l(p), vresult(1) {} - const VResult &result() const + const VResult & + result() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); vresult[0] = 0.0; Op op; - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[0] = op(vresult[0], lvec[i]); return vresult; } - Result total() const + Result + total() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); Result vresult = 0.0; Op op; - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult = op(vresult, lvec[i]); return vresult; } - virtual size_t size() const { return 1; } + size_type size() const { return 1; } - virtual std::string str() const + std::string + str() const { return csprintf("total(%s)", l->str()); } @@ -2278,145 +2376,57 @@ class SumNode : public Node * This is a simple scalar statistic, like a counter. * @sa Stat, ScalarBase, StatStor */ -template<int N = 0> -class Scalar : public Wrap<Scalar<N>, ScalarBase<StatStor>, ScalarStatData> +class Scalar : public ScalarBase<Scalar, StatStor> { public: - /** The base implementation. */ - typedef ScalarBase<StatStor> Base; - - Scalar() - { - this->doInit(); - } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } -}; - -class Value : public Wrap<Value, ValueBase, ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ValueBase Base; - - template <class T> - Value &scalar(T &value) - { - Base::scalar(value); - return *this; - } - - template <class T> - Value &functor(T &func) - { - Base::functor(func); - return *this; - } + using ScalarBase<Scalar, StatStor>::operator=; }; /** * A stat that calculates the per tick average of a value. * @sa Stat, ScalarBase, AvgStor */ -template<int N = 0> -class Average : public Wrap<Average<N>, ScalarBase<AvgStor>, ScalarStatData> +class Average : public ScalarBase<Average, AvgStor> { public: - /** The base implementation. */ - typedef ScalarBase<AvgStor> Base; - - Average() - { - this->doInit(); - } + using ScalarBase<Average, AvgStor>::operator=; +}; - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } +class Value : public ValueBase<Value> +{ }; /** * A vector of scalar stats. * @sa Stat, VectorBase, StatStor */ -template<int N = 0> -class Vector : public WrapVec<Vector<N>, VectorBase<StatStor>, VectorStatData> +class Vector : public VectorBase<Vector, StatStor> { - public: - /** The base implementation. */ - typedef ScalarBase<StatStor> Base; - - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - Vector &init(size_t size) { - this->doInit(size); - return *this; - } }; /** * A vector of Average stats. * @sa Stat, VectorBase, AvgStor */ -template<int N = 0> -class AverageVector - : public WrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorStatData> +class AverageVector : public VectorBase<AverageVector, AvgStor> { - public: - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - AverageVector &init(size_t size) { - this->doInit(size); - return *this; - } }; /** * A 2-Dimensional vecto of scalar stats. * @sa Stat, Vector2dBase, StatStor */ -template<int N = 0> -class Vector2d - : public WrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dStatData> +class Vector2d : public Vector2dBase<Vector2d, StatStor> { - public: - Vector2d &init(size_t x, size_t y) { - this->doInit(x, y); - return *this; - } }; /** * A simple distribution stat. * @sa Stat, DistBase, DistStor */ -template<int N = 0> -class Distribution - : public Wrap<Distribution<N>, DistBase<DistStor>, DistStatData> +class Distribution : public DistBase<Distribution, DistStor> { public: - /** Base implementation. */ - typedef DistBase<DistStor> Base; - /** The Parameter type. */ - typedef DistStor::Params Params; - - public: /** * Set the parameters of this distribution. @sa DistStor::Params * @param min The minimum value of the distribution. @@ -2424,13 +2434,17 @@ class Distribution * @param bkt The number of values in each bucket. * @return A reference to this distribution. */ - Distribution &init(Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); + Distribution & + init(Counter min, Counter max, Counter bkt) + { + DistStor::Params *params = new DistStor::Params; + params->min = min; + params->max = max; + params->bucket_size = bkt; + params->buckets = (size_type)rint((max - min) / bkt + 1.0); + this->setParams(params); this->doInit(); - return *this; + return this->self(); } }; @@ -2438,21 +2452,14 @@ class Distribution * Calculates the mean and variance of all the samples. * @sa Stat, DistBase, FancyStor */ -template<int N = 0> -class StandardDeviation - : public Wrap<StandardDeviation<N>, DistBase<FancyStor>, DistStatData> +class StandardDeviation : public DistBase<StandardDeviation, FancyStor> { public: - /** The base implementation */ - typedef DistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: /** * Construct and initialize this distribution. */ - StandardDeviation() { + StandardDeviation() + { this->doInit(); } }; @@ -2461,17 +2468,9 @@ class StandardDeviation * Calculates the per tick mean and variance of the samples. * @sa Stat, DistBase, AvgFancy */ -template<int N = 0> -class AverageDeviation - : public Wrap<AverageDeviation<N>, DistBase<AvgFancy>, DistStatData> +class AverageDeviation : public DistBase<AverageDeviation, AvgFancy> { public: - /** The base implementation */ - typedef DistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: /** * Construct and initialize this distribution. */ @@ -2485,19 +2484,9 @@ class AverageDeviation * A vector of distributions. * @sa Stat, VectorDistBase, DistStor */ -template<int N = 0> -class VectorDistribution - : public WrapVec<VectorDistribution<N>, - VectorDistBase<DistStor>, - VectorDistStatData> +class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor> { public: - /** The base implementation */ - typedef VectorDistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: /** * Initialize storage and parameters for this distribution. * @param size The size of the vector (the number of distributions). @@ -2506,13 +2495,17 @@ class VectorDistribution * @param bkt The number of values in each bucket. * @return A reference to this distribution. */ - VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); + VectorDistribution & + init(size_type size, Counter min, Counter max, Counter bkt) + { + DistStor::Params *params = new DistStor::Params; + params->min = min; + params->max = max; + params->bucket_size = bkt; + params->buckets = (size_type)rint((max - min) / bkt + 1.0); + this->setParams(params); this->doInit(size); - return *this; + return this->self(); } }; @@ -2520,27 +2513,20 @@ class VectorDistribution * This is a vector of StandardDeviation stats. * @sa Stat, VectorDistBase, FancyStor */ -template<int N = 0> class VectorStandardDeviation - : public WrapVec<VectorStandardDeviation<N>, - VectorDistBase<FancyStor>, - VectorDistStatData> + : public VectorDistBase<VectorStandardDeviation, FancyStor> { public: - /** The base implementation */ - typedef VectorDistBase<FancyStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: /** * Initialize storage for this distribution. * @param size The size of the vector. * @return A reference to this distribution. */ - VectorStandardDeviation &init(int size) { + VectorStandardDeviation & + init(size_type size) + { this->doInit(size); - return *this; + return this->self(); } }; @@ -2548,36 +2534,60 @@ class VectorStandardDeviation * This is a vector of AverageDeviation stats. * @sa Stat, VectorDistBase, AvgFancy */ -template<int N = 0> class VectorAverageDeviation - : public WrapVec<VectorAverageDeviation<N>, - VectorDistBase<AvgFancy>, - VectorDistStatData> + : public VectorDistBase<VectorAverageDeviation, AvgFancy> { public: - /** The base implementation */ - typedef VectorDistBase<AvgFancy> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: /** * Initialize storage for this distribution. * @param size The size of the vector. * @return A reference to this distribution. */ - VectorAverageDeviation &init(int size) { + VectorAverageDeviation & + init(size_type size) + { this->doInit(size); - return *this; + return this->self(); + } +}; + +class FormulaInfoBase : public VectorInfoBase +{ + public: + virtual std::string str() const = 0; +}; + +template <class Stat> +class FormulaInfo : public InfoWrap<Stat, FormulaInfoBase> +{ + protected: + mutable VResult vec; + mutable VCounter cvec; + + public: + FormulaInfo(Stat &stat) : InfoWrap<Stat, FormulaInfoBase>(stat) {} + + size_type size() const { return this->s.size(); } + + const VResult & + result() const + { + this->s.result(vec); + return vec; } + Result total() const { return this->s.total(); } + VCounter &value() const { return cvec; } + + std::string str() const { return this->s.str(); } }; +class Temp; /** * A formula for statistics that is calculated when printed. A formula is * stored as a tree of Nodes that represent the equation to calculate. * @sa Stat, ScalarStat, VectorStat, Node, Temp */ -class FormulaBase : public DataAccess +class Formula : public DataWrapVec<Formula, FormulaInfo> { protected: /** The root of the tree which represents the Formula */ @@ -2586,6 +2596,31 @@ class FormulaBase : public DataAccess public: /** + * Create and initialize thie formula, and register it with the database. + */ + Formula(); + + /** + * Create a formula with the given root node, register it with the + * database. + * @param r The root of the expression tree. + */ + Formula(Temp r); + + /** + * Set an unitialized Formula to the given root. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator=(Temp r); + + /** + * Add the given tree to the existing one. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator+=(Temp r); + /** * Return the result of the Fomula in a vector. If there were no Vector * components to the Formula, then the vector is size 1. If there were, * like x/y with x being a vector of size 3, then the result returned will @@ -2609,9 +2644,9 @@ class FormulaBase : public DataAccess /** * Return the number of elements in the tree. */ - size_t size() const; + size_type size() const; - bool check() const { return true; } + void prepare() { } /** * Formulas don't need to be reset @@ -2623,86 +2658,9 @@ class FormulaBase : public DataAccess */ bool zero() const; - /** - * - */ - void update(StatData *); - std::string str() const; }; -class FormulaData : public VectorData -{ - public: - virtual std::string str() const = 0; - virtual bool check() const { return true; } -}; - -template <class Stat> -class FormulaStatData : public FormulaData -{ - protected: - Stat &s; - mutable VResult vec; - mutable VCounter cvec; - - public: - FormulaStatData(Stat &stat) : s(stat) {} - - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } - - virtual size_t size() const { return s.size(); } - virtual const VResult &result() const - { - s.result(vec); - return vec; - } - virtual Result total() const { return s.total(); } - virtual VCounter &value() const { return cvec; } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } - virtual std::string str() const { return s.str(); } -}; - -class Temp; -class Formula - : public WrapVec<Formula, - FormulaBase, - FormulaStatData> -{ - public: - /** - * Create and initialize thie formula, and register it with the database. - */ - Formula(); - - /** - * Create a formula with the given root node, register it with the - * database. - * @param r The root of the expression tree. - */ - Formula(Temp r); - - /** - * Set an unitialized Formula to the given root. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator=(Temp r); - - /** - * Add the given tree to the existing one. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator+=(Temp r); -}; - class FormulaNode : public Node { private: @@ -2712,11 +2670,11 @@ class FormulaNode : public Node public: FormulaNode(const Formula &f) : formula(f) {} - virtual size_t size() const { return formula.size(); } - virtual const VResult &result() const { formula.result(vec); return vec; } - virtual Result total() const { return formula.total(); } + size_type size() const { return formula.size(); } + const VResult &result() const { formula.result(vec); return vec; } + Result total() const { return formula.total(); } - virtual std::string str() const { return formula.str(); } + std::string str() const { return formula.str(); } }; /** @@ -2741,45 +2699,47 @@ class Temp * Return the node pointer. * @return the node pointer. */ - operator NodePtr&() { return node;} + operator NodePtr&() { return node; } public: /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template <int N> - Temp(const Scalar<N> &s) - : node(new ScalarStatNode(s.statData())) { } + Temp(const Scalar &s) + : node(new ScalarStatNode(s.info())) + { } /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ Temp(const Value &s) - : node(new ScalarStatNode(s.statData())) { } + : node(new ScalarStatNode(s.info())) + { } /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template <int N> - Temp(const Average<N> &s) - : node(new ScalarStatNode(s.statData())) { } + Temp(const Average &s) + : node(new ScalarStatNode(s.info())) + { } /** * Create a new VectorStatNode. * @param s The VectorStat to place in a node. */ - template <int N> - Temp(const Vector<N> &s) - : node(new VectorStatNode(s.statData())) { } + Temp(const Vector &s) + : node(new VectorStatNode(s.info())) + { } /** * */ Temp(const Formula &f) - : node(new FormulaNode(f)) { } + : node(new FormulaNode(f)) + { } /** * Create a new ScalarProxyNode. @@ -2787,91 +2747,104 @@ class Temp */ template <class Stat> Temp(const ScalarProxy<Stat> &p) - : node(new ScalarProxyNode<Stat>(p)) { } + : node(new ScalarProxyNode<Stat>(p)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed char value) - : node(new ConstNode<signed char>(value)) {} + : node(new ConstNode<signed char>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned char value) - : node(new ConstNode<unsigned char>(value)) {} + : node(new ConstNode<unsigned char>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed short value) - : node(new ConstNode<signed short>(value)) {} + : node(new ConstNode<signed short>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned short value) - : node(new ConstNode<unsigned short>(value)) {} + : node(new ConstNode<unsigned short>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed int value) - : node(new ConstNode<signed int>(value)) {} + : node(new ConstNode<signed int>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned int value) - : node(new ConstNode<unsigned int>(value)) {} + : node(new ConstNode<unsigned int>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed long value) - : node(new ConstNode<signed long>(value)) {} + : node(new ConstNode<signed long>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned long value) - : node(new ConstNode<unsigned long>(value)) {} + : node(new ConstNode<unsigned long>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed long long value) - : node(new ConstNode<signed long long>(value)) {} + : node(new ConstNode<signed long long>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned long long value) - : node(new ConstNode<unsigned long long>(value)) {} + : node(new ConstNode<unsigned long long>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(float value) - : node(new ConstNode<float>(value)) {} + : node(new ConstNode<float>(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(double value) - : node(new ConstNode<double>(value)) {} + : node(new ConstNode<double>(value)) + { } }; @@ -2879,11 +2852,6 @@ class Temp * @} */ -void check(); -void dump(); -void reset(); -void registerResetCallback(Callback *cb); - inline Temp operator+(Temp l, Temp r) { @@ -2934,6 +2902,36 @@ sum(Temp val) return NodePtr(new SumNode<std::plus<Result> >(val)); } +/** + * Enable the statistics package. Before the statistics package is + * enabled, all statistics must be created and initialized and once + * the package is enabled, no more statistics can be created. + */ +void enable(); + +/** + * Prepare all stats for data access. This must be done before + * dumping and serialization. + */ +void prepare(); + +/** + * Dump all statistics data to the registered outputs + */ +void dump(); + +/** + * Reset all statistics to the base state + */ +void reset(); +/** + * Register a callback that should be called whenever statistics are + * reset + */ +void registerResetCallback(Callback *cb); + +std::list<Info *> &statsList(); + /* namespace Stats */ } #endif // __BASE_STATISTICS_HH__ diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc index dc56fe75f..dcf52e6d8 100644 --- a/src/base/stats/events.cc +++ b/src/base/stats/events.cc @@ -38,7 +38,7 @@ using namespace std; namespace Stats { -Tick EventStart = ULL(0x7fffffffffffffff); +Tick EventStart = MaxTick; extern list<Output *> OutputList; diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh index 69f73f66a..77eedaee8 100644 --- a/src/base/stats/flags.hh +++ b/src/base/stats/flags.hh @@ -30,6 +30,7 @@ #ifndef __BASE_STATS_FLAGS_HH__ #define __BASE_STATS_FLAGS_HH__ + namespace Stats { /** @@ -39,28 +40,28 @@ namespace Stats { typedef uint32_t StatFlags; /** Nothing extra to print. */ -const StatFlags none = 0x00000000; +const StatFlags none = 0x00000000; /** This Stat is Initialized */ -const StatFlags init = 0x00000001; +const StatFlags init = 0x00000001; /** Print this stat. */ -const StatFlags print = 0x00000002; +const StatFlags print = 0x00000002; /** Print the total. */ -const StatFlags total = 0x00000010; +const StatFlags total = 0x00000010; /** Print the percent of the total that this entry represents. */ -const StatFlags pdf = 0x00000020; +const StatFlags pdf = 0x00000020; /** Print the cumulative percentage of total upto this entry. */ -const StatFlags cdf = 0x00000040; +const StatFlags cdf = 0x00000040; /** Print the distribution. */ -const StatFlags dist = 0x00000080; +const StatFlags dist = 0x00000080; /** Don't print if this is zero. */ -const StatFlags nozero = 0x00000100; +const StatFlags nozero = 0x00000100; /** Don't print if this is NAN */ -const StatFlags nonan = 0x00000200; +const StatFlags nonan = 0x00000200; /** Used for SS compatability. */ -const StatFlags __substat = 0x80000000; +const StatFlags __substat = 0x80000000; /** Mask of flags that can't be set directly */ -const StatFlags __reserved = init | print | __substat; +const StatFlags __reserved = init | print | __substat; enum DisplayMode { diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc index 39a687fff..1e0c923f1 100644 --- a/src/base/stats/mysql.cc +++ b/src/base/stats/mysql.cc @@ -40,7 +40,6 @@ #include "base/stats/flags.hh" #include "base/stats/mysql.hh" #include "base/stats/mysql_run.hh" -#include "base/stats/statdb.hh" #include "base/stats/types.hh" #include "base/str.hh" #include "base/userinfo.hh" @@ -458,7 +457,7 @@ InsertSubData::setup(MySqlRun *run) mysql.query(insert); // if (mysql.error) -// panic("could not insert subdata\n%s\n", mysql.error); +// panic("could not insert subdata\n%s\n", mysql.error); if (mysql.commit()) panic("could not commit transaction\n%s\n", mysql.error); @@ -493,21 +492,19 @@ MySql::configure() /* * set up all stats! */ - using namespace Database; - MySQL::Connection &mysql = run->conn(); - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) { + list<Info *>::const_iterator i, end = statsList().end(); + for (i = statsList().begin(); i != end; ++i) { (*i)->visit(*this); } - for (i = stats().begin(); i != end; ++i) { - StatData *data = *i; - if (data->prereq) { + for (i = statsList().begin(); i != end; ++i) { + Info *info = *i; + if (info->prereq) { // update the prerequisite - uint16_t stat_id = find(data->id); - uint16_t prereq_id = find(data->prereq->id); + uint16_t stat_id = find(info->id); + uint16_t prereq_id = find(info->prereq->id); assert(stat_id && prereq_id); stringstream update; @@ -528,153 +525,156 @@ MySql::configure() configured = true; } - bool -MySql::configure(const StatData &data, string type) +MySql::configure(const Info &info, string type) { stat.init(); - stat.name = data.name; - stat.descr = data.desc; + stat.name = info.name; + stat.descr = info.desc; stat.type = type; - stat.print = data.flags & print; - stat.prec = data.precision; - stat.nozero = data.flags & nozero; - stat.nonan = data.flags & nonan; - stat.total = data.flags & total; - stat.pdf = data.flags & pdf; - stat.cdf = data.flags & cdf; + stat.print = info.flags & print; + stat.prec = info.precision; + stat.nozero = info.flags & nozero; + stat.nonan = info.flags & nonan; + stat.total = info.flags & total; + stat.pdf = info.flags & pdf; + stat.cdf = info.flags & cdf; return stat.print; } void -MySql::configure(const ScalarData &data) +MySql::configure(const ScalarInfoBase &info) { - if (!configure(data, "SCALAR")) + if (!configure(info, "SCALAR")) return; - insert(data.id, stat.setup(run)); + insert(info.id, stat.setup(run)); } void -MySql::configure(const VectorData &data) +MySql::configure(const VectorInfoBase &info) { - if (!configure(data, "VECTOR")) + if (!configure(info, "VECTOR")) return; uint16_t statid = stat.setup(run); - if (!data.subnames.empty()) { + if (!info.subnames.empty()) { InsertSubData subdata; subdata.stat = statid; subdata.y = 0; - for (int i = 0; i < data.subnames.size(); ++i) { + for (off_type i = 0; i < info.subnames.size(); ++i) { subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + subdata.name = info.subnames[i]; + subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) subdata.setup(run); } } - insert(data.id, statid); + insert(info.id, statid); } void -MySql::configure(const DistData &data) +MySql::configure(const DistInfoBase &info) { - if (!configure(data, "DIST")) + if (!configure(info, "DIST")) return; - if (!data.data.fancy) { - stat.size = data.data.size; - stat.min = data.data.min; - stat.max = data.data.max; - stat.bktsize = data.data.bucket_size; + const DistParams *params = + safe_cast<const DistParams *>(info.storageParams); + if (!params->fancy) { + stat.size = params->buckets; + stat.min = params->min; + stat.max = params->max; + stat.bktsize = params->bucket_size; } - insert(data.id, stat.setup(run)); + insert(info.id, stat.setup(run)); } void -MySql::configure(const VectorDistData &data) +MySql::configure(const VectorDistInfoBase &info) { - if (!configure(data, "VECTORDIST")) + if (!configure(info, "VECTORDIST")) return; - if (!data.data[0].fancy) { - stat.size = data.data[0].size; - stat.min = data.data[0].min; - stat.max = data.data[0].max; - stat.bktsize = data.data[0].bucket_size; + const DistParams *params = + safe_cast<const DistParams *>(info.storageParams); + if (!params->fancy) { + stat.size = params->buckets; + stat.min = params->min; + stat.max = params->max; + stat.bktsize = params->bucket_size; } uint16_t statid = stat.setup(run); - if (!data.subnames.empty()) { + if (!info.subnames.empty()) { InsertSubData subdata; subdata.stat = statid; subdata.y = 0; - for (int i = 0; i < data.subnames.size(); ++i) { + for (off_type i = 0; i < info.subnames.size(); ++i) { subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + subdata.name = info.subnames[i]; + subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) subdata.setup(run); } } - insert(data.id, statid); + insert(info.id, statid); } void -MySql::configure(const Vector2dData &data) +MySql::configure(const Vector2dInfoBase &info) { - if (!configure(data, "VECTOR2D")) + if (!configure(info, "VECTOR2D")) return; uint16_t statid = stat.setup(run); - if (!data.subnames.empty()) { + if (!info.subnames.empty()) { InsertSubData subdata; subdata.stat = statid; subdata.y = -1; - for (int i = 0; i < data.subnames.size(); ++i) { + for (off_type i = 0; i < info.subnames.size(); ++i) { subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + subdata.name = info.subnames[i]; + subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) subdata.setup(run); } } - if (!data.y_subnames.empty()) { + if (!info.y_subnames.empty()) { InsertSubData subdata; subdata.stat = statid; subdata.x = -1; subdata.descr = ""; - for (int i = 0; i < data.y_subnames.size(); ++i) { + for (off_type i = 0; i < info.y_subnames.size(); ++i) { subdata.y = i; - subdata.name = data.y_subnames[i]; + subdata.name = info.y_subnames[i]; if (!subdata.name.empty()) subdata.setup(run); } } - insert(data.id, statid); + insert(info.id, statid); } void -MySql::configure(const FormulaData &data) +MySql::configure(const FormulaInfoBase &info) { MySQL::Connection &mysql = run->conn(); assert(mysql.connected()); - configure(data, "FORMULA"); - insert(data.id, stat.setup(run)); + configure(info, "FORMULA"); + insert(info.id, stat.setup(run)); - uint16_t stat = find(data.id); - string formula = data.str(); + uint16_t stat = find(info.id); + string formula = info.str(); stringstream insert_formula; ccprintf(insert_formula, @@ -683,7 +683,7 @@ MySql::configure(const FormulaData &data) mysql.query(insert_formula); // if (mysql.error) -// panic("could not insert formula\n%s\n", mysql.error); +// panic("could not insert formula\n%s\n", mysql.error); stringstream insert_ref; ccprintf(insert_ref, @@ -692,7 +692,7 @@ MySql::configure(const FormulaData &data) mysql.query(insert_ref); // if (mysql.error) -// panic("could not insert formula reference\n%s\n", mysql.error); +// panic("could not insert formula reference\n%s\n", mysql.error); if (mysql.commit()) panic("could not commit transaction\n%s\n", mysql.error); @@ -707,7 +707,6 @@ MySql::valid() const void MySql::output() { - using namespace Database; assert(valid()); if (!configured) @@ -718,9 +717,9 @@ MySql::output() MySQL::Connection &mysql = run->conn(); - Database::stat_list_t::const_iterator i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *stat = *i; + list<Info *>::const_iterator i, end = statsList().end(); + for (i = statsList().begin(); i != end; ++i) { + Info *stat = *i; stat->visit(*this); if (mysql.commit()) panic("could not commit transaction\n%s\n", mysql.error); @@ -735,33 +734,32 @@ MySql::event(const std::string &event) newevent.insert(event); } - void -MySql::output(const ScalarData &data) +MySql::output(const ScalarInfoBase &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return; - newdata.stat = find(data.id); + newdata.stat = find(info.id); newdata.x = 0; newdata.y = 0; - newdata.data = data.value(); + newdata.data = info.value(); newdata.insert(); } void -MySql::output(const VectorData &data) +MySql::output(const VectorInfoBase &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return; - newdata.stat = find(data.id); + newdata.stat = find(info.id); newdata.y = 0; - const VCounter &cvec = data.value(); - int size = data.size(); - for (int x = 0; x < size; x++) { + const VCounter &cvec = info.value(); + size_type size = info.size(); + for (off_type x = 0; x < size; x++) { newdata.x = x; newdata.data = cvec[x]; newdata.insert(); @@ -769,7 +767,7 @@ MySql::output(const VectorData &data) } void -MySql::output(const DistDataData &data) +MySql::output(const DistData &data, const DistParams *params) { const int db_sum = -1; const int db_squares = -2; @@ -791,7 +789,7 @@ MySql::output(const DistDataData &data) newdata.data = data.samples; newdata.insert(); - if (data.samples && !data.fancy) { + if (data.samples && !params->fancy) { newdata.x = db_min_val; newdata.data = data.min_val; newdata.insert(); @@ -808,8 +806,8 @@ MySql::output(const DistDataData &data) newdata.data = data.overflow; newdata.insert(); - int size = data.cvec.size(); - for (int x = 0; x < size; x++) { + size_type size = data.cvec.size(); + for (off_type x = 0; x < size; x++) { newdata.x = x; newdata.data = data.cvec[x]; newdata.insert(); @@ -817,54 +815,54 @@ MySql::output(const DistDataData &data) } } - void -MySql::output(const DistData &data) +MySql::output(const DistInfoBase &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return; - newdata.stat = find(data.id); + newdata.stat = find(info.id); newdata.y = 0; - output(data.data); + output(info.data, safe_cast<const DistParams *>(info.storageParams)); } void -MySql::output(const VectorDistData &data) +MySql::output(const VectorDistInfoBase &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return; - newdata.stat = find(data.id); + newdata.stat = find(info.id); - int size = data.data.size(); - for (int y = 0; y < size; ++y) { + size_type size = info.data.size(); + for (off_type y = 0; y < size; ++y) { newdata.y = y; - output(data.data[y]); + output(info.data[y], + safe_cast<const DistParams *>(info.storageParams)); } } void -MySql::output(const Vector2dData &data) +MySql::output(const Vector2dInfoBase &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return; - newdata.stat = find(data.id); + newdata.stat = find(info.id); - int index = 0; - for (int x = 0; x < data.x; x++) { + off_type index = 0; + for (off_type x = 0; x < info.x; x++) { newdata.x = x; - for (int y = 0; y < data.y; y++) { + for (off_type y = 0; y < info.y; y++) { newdata.y = y; - newdata.data = data.cvec[index++]; + newdata.data = info.cvec[index++]; newdata.insert(); } } } void -MySql::output(const FormulaData &data) +MySql::output(const FormulaInfoBase &info) { } @@ -872,65 +870,65 @@ MySql::output(const FormulaData &data) * Implement the visitor */ void -MySql::visit(const ScalarData &data) +MySql::visit(const ScalarInfoBase &info) { if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } void -MySql::visit(const VectorData &data) +MySql::visit(const VectorInfoBase &info) { if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } void -MySql::visit(const DistData &data) +MySql::visit(const DistInfoBase &info) { return; if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } void -MySql::visit(const VectorDistData &data) +MySql::visit(const VectorDistInfoBase &info) { return; if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } void -MySql::visit(const Vector2dData &data) +MySql::visit(const Vector2dInfoBase &info) { return; if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } void -MySql::visit(const FormulaData &data) +MySql::visit(const FormulaInfoBase &info) { if (!configured) - configure(data); + configure(info); else - output(data); + output(info); } bool initMySQL(string host, string user, string password, string database, - string project, string name, string sample) + string project, string name, string sample) { extern list<Output *> OutputList; static MySql mysql; diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh index 0ce381c2f..86a4d6d23 100644 --- a/src/base/stats/mysql.hh +++ b/src/base/stats/mysql.hh @@ -40,7 +40,7 @@ namespace MySQL { class Connection; } namespace Stats { -class DistDataData; +class DistInfoBase; class MySqlRun; struct SetupStat @@ -56,6 +56,7 @@ struct SetupStat bool total; bool pdf; bool cdf; + double min; double max; double bktsize; @@ -69,9 +70,9 @@ class InsertData { private: char *query; - int size; + size_type size; bool first; - static const int maxsize = 1024*1024; + static const size_type maxsize = 1024*1024; public: MySqlRun *run; @@ -95,9 +96,9 @@ class InsertEvent { private: char *query; - int size; + size_type size; bool first; - static const int maxsize = 1024*1024; + static const size_type maxsize = 1024*1024; typedef std::map<std::string, uint32_t> event_map_t; event_map_t events; @@ -121,19 +122,21 @@ class MySql : public Output SetupStat stat; InsertData newdata; InsertEvent newevent; - std::list<FormulaData *> formulas; + std::list<FormulaInfoBase *> formulas; bool configured; protected: std::map<int, int> idmap; - void insert(int sim_id, int db_id) + void + insert(int sim_id, int db_id) { using namespace std; idmap.insert(make_pair(sim_id, db_id)); } - int find(int sim_id) + int + find(int sim_id) { using namespace std; map<int,int>::const_iterator i = idmap.find(sim_id); @@ -146,19 +149,19 @@ class MySql : public Output ~MySql(); void connect(const std::string &host, const std::string &user, - const std::string &passwd, const std::string &db, - const std::string &name, const std::string &sample, - const std::string &project); + const std::string &passwd, const std::string &db, + const std::string &name, const std::string &sample, + const std::string &project); bool connected() const; public: // Implement Visit - virtual void visit(const ScalarData &data); - virtual void visit(const VectorData &data); - virtual void visit(const DistData &data); - virtual void visit(const VectorDistData &data); - virtual void visit(const Vector2dData &data); - virtual void visit(const FormulaData &data); + virtual void visit(const ScalarInfoBase &info); + virtual void visit(const VectorInfoBase &info); + virtual void visit(const DistInfoBase &info); + virtual void visit(const VectorDistInfoBase &info); + virtual void visit(const Vector2dInfoBase &info); + virtual void visit(const FormulaInfoBase &info); // Implement Output virtual bool valid() const; @@ -169,33 +172,33 @@ class MySql : public Output protected: // Output helper - void output(const DistDataData &data); - void output(const ScalarData &data); - void output(const VectorData &data); - void output(const DistData &data); - void output(const VectorDistData &data); - void output(const Vector2dData &data); - void output(const FormulaData &data); + void output(const ScalarInfoBase &info); + void output(const VectorInfoBase &info); + void output(const DistInfoBase &info); + void output(const VectorDistInfoBase &info); + void output(const Vector2dInfoBase &info); + void output(const FormulaInfoBase &info); + void output(const DistData &data, const DistParams *params); void configure(); - bool configure(const StatData &data, std::string type); - void configure(const ScalarData &data); - void configure(const VectorData &data); - void configure(const DistData &data); - void configure(const VectorDistData &data); - void configure(const Vector2dData &data); - void configure(const FormulaData &data); + bool configure(const Info &info, std::string type); + void configure(const ScalarInfoBase &info); + void configure(const VectorInfoBase &info); + void configure(const DistInfoBase &info); + void configure(const VectorDistInfoBase &info); + void configure(const Vector2dInfoBase &info); + void configure(const FormulaInfoBase &info); }; bool initMySQL(std::string host, std::string database, std::string user, - std::string passwd, std::string project, std::string name, - std::string sample); + std::string passwd, std::string project, std::string name, + std::string sample); #if !USE_MYSQL inline bool initMySQL(std::string host, std::string user, std::string password, - std::string database, std::string project, std::string name, - std::string sample) + std::string database, std::string project, std::string name, + std::string sample) { return false; } diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh index 487224551..7c606370e 100644 --- a/src/base/stats/mysql_run.hh +++ b/src/base/stats/mysql_run.hh @@ -46,7 +46,7 @@ struct MySqlRun protected: void setup(const std::string &name, const std::string &sample, - const std::string &user, const std::string &project); + const std::string &user, const std::string &project); void remove(const std::string &name); void cleanup(); @@ -54,9 +54,9 @@ struct MySqlRun public: bool connected() const { return mysql.connected(); } void connect(const std::string &host, const std::string &user, - const std::string &passwd, const std::string &db, - const std::string &name, const std::string &sample, - const std::string &project); + const std::string &passwd, const std::string &db, + const std::string &name, const std::string &sample, + const std::string &project); MySQL::Connection &conn() { return mysql; } uint16_t run() const { return run_id; } diff --git a/src/base/stats/output.cc b/src/base/stats/output.cc index 9f2b91c77..31aa21c45 100644 --- a/src/base/stats/output.cc +++ b/src/base/stats/output.cc @@ -30,6 +30,7 @@ #include <list> +#include "base/statistics.hh" #include "base/stats/output.hh" #include "sim/eventq.hh" #include "sim/host.hh" @@ -49,6 +50,8 @@ dump() return; lastDump = curTick; + prepare(); + list<Output *>::iterator i = OutputList.begin(); list<Output *>::iterator end = OutputList.end(); for (; i != end; ++i) { diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index a018c4837..c3e484cf4 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -43,7 +43,6 @@ #include "base/misc.hh" #include "base/statistics.hh" -#include "base/stats/statdb.hh" #include "base/stats/text.hh" #include "base/stats/visit.hh" @@ -107,7 +106,8 @@ Text::open(std::ostream &_stream) mystream = false; stream = &_stream; - assert(valid()); + if (!valid()) + fatal("Unable to open output stream for writing\n"); } void @@ -118,35 +118,34 @@ Text::open(const std::string &file) mystream = true; stream = new ofstream(file.c_str(), ios::trunc); - assert(valid()); + if (!valid()) + fatal("Unable to open statistics file for writing\n"); } bool Text::valid() const { - return stream != NULL; + return stream != NULL && stream->good(); } void Text::output() { - using namespace Database; - ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) + list<Info *>::const_iterator i, end = statsList().end(); + for (i = statsList().begin(); i != end; ++i) (*i)->visit(*this); ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); stream->flush(); } bool -Text::noOutput(const StatData &data) +Text::noOutput(const Info &info) { - if (!(data.flags & print)) + if (!(info.flags & print)) return true; - if (data.prereq && data.prereq->zero()) + if (info.prereq && info.prereq->zero()) return true; return false; @@ -191,8 +190,8 @@ struct ScalarPrint void ScalarPrint::operator()(ostream &stream) const { - if (flags & nozero && value == 0.0 || - flags & nonan && isnan(value)) + if ((flags & nozero && value == 0.0) || + (flags & nonan && isnan(value))) return; stringstream pdfstr, cdfstr; @@ -237,11 +236,11 @@ struct VectorPrint void VectorPrint::operator()(std::ostream &stream) const { - int _size = vec.size(); + size_type _size = vec.size(); Result _total = 0.0; if (flags & (pdf | cdf)) { - for (int i = 0; i < _size; ++i) { + for (off_type i = 0; i < _size; ++i) { _total += vec[i]; } } @@ -264,7 +263,7 @@ VectorPrint::operator()(std::ostream &stream) const print.value = vec[0]; print(stream); } else if (!compat) { - for (int i = 0; i < _size; ++i) { + for (off_type i = 0; i < _size; ++i) { if (havesub && (i >= subnames.size() || subnames[i].empty())) continue; @@ -296,7 +295,7 @@ VectorPrint::operator()(std::ostream &stream) const Result _cdf = 0.0; if (flags & dist) { ccprintf(stream, "%s.start_dist\n", name); - for (int i = 0; i < _size; ++i) { + for (off_type i = 0; i < _size; ++i) { print.name = havesub ? subnames[i] : to_string(i); print.desc = subdescs.empty() ? desc : subdescs[i]; print.flags |= __substat; @@ -316,7 +315,7 @@ VectorPrint::operator()(std::ostream &stream) const } ccprintf(stream, "%s.end_dist\n", name); } else { - for (int i = 0; i < _size; ++i) { + for (off_type i = 0; i < _size; ++i) { if (havesub && subnames[i].empty()) continue; @@ -352,27 +351,63 @@ struct DistPrint bool descriptions; int precision; - Result min_val; - Result max_val; - Result underflow; - Result overflow; - VResult vec; - Result sum; - Result squares; - Result samples; - Counter min; Counter max; Counter bucket_size; - int size; + size_type size; bool fancy; + const DistData &data; + + DistPrint(const DistInfoBase &info); + DistPrint(const VectorDistInfoBase &info, int i); + void init(const Info &info, const DistParams *params); void operator()(ostream &stream) const; }; +DistPrint::DistPrint(const DistInfoBase &info) + : data(info.data) +{ + init(info, safe_cast<const DistParams *>(info.storageParams)); +} + +DistPrint::DistPrint(const VectorDistInfoBase &info, int i) + : data(info.data[i]) +{ + init(info, safe_cast<const DistParams *>(info.storageParams)); + + name = info.name + "_" + + (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); + + if (!info.subdescs[i].empty()) + desc = info.subdescs[i]; +} + +void +DistPrint::init(const Info &info, const DistParams *params) +{ + name = info.name; + desc = info.desc; + flags = info.flags; + compat = compat; + descriptions = descriptions; + precision = info.precision; + + fancy = params->fancy; + min = params->min; + max = params->max; + bucket_size = params->bucket_size; + size = params->buckets; +} + void DistPrint::operator()(ostream &stream) const { + Result stdev = NAN; + if (data.samples) + stdev = sqrt((data.samples * data.squares - data.sum * data.sum) / + (data.samples * (data.samples - 1.0))); + if (fancy) { ScalarPrint print; string base = name + (compat ? "_" : "::"); @@ -386,28 +421,27 @@ DistPrint::operator()(ostream &stream) const print.cdf = NAN; print.name = base + "mean"; - print.value = samples ? sum / samples : NAN; + print.value = data.samples ? data.sum / data.samples : NAN; print(stream); print.name = base + "stdev"; - print.value = samples ? sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))) : NAN; + print.value = stdev; print(stream); print.name = "**Ignore: " + base + "TOT"; - print.value = samples; + print.value = data.samples; print(stream); return; } - assert(size == vec.size()); + assert(size == data.cvec.size()); Result total = 0.0; - total += underflow; - for (int i = 0; i < size; ++i) - total += vec[i]; - total += overflow; + total += data.underflow; + for (off_type i = 0; i < size; ++i) + total += data.cvec[i]; + total += data.overflow; string base = name + (compat ? "." : "::"); @@ -428,28 +462,27 @@ DistPrint::operator()(ostream &stream) const } print.name = base + "samples"; - print.value = samples; + print.value = data.samples; print(stream); print.name = base + "min_value"; - print.value = min_val; + print.value = data.min_val; print(stream); - if (!compat || underflow > 0.0) { + if (!compat || data.underflow > 0.0) { print.name = base + "underflows"; - print.value = underflow; + print.value = data.underflow; if (!compat && total) { - print.pdf = underflow / total; + print.pdf = data.underflow / total; print.cdf += print.pdf; } print(stream); } - if (!compat) { - for (int i = 0; i < size; ++i) { + for (off_type i = 0; i < size; ++i) { stringstream namestr; - namestr << name; + namestr << base; Counter low = i * bucket_size + min; Counter high = ::min(low + bucket_size, max); @@ -458,14 +491,13 @@ DistPrint::operator()(ostream &stream) const namestr << "-" << high; print.name = namestr.str(); - print.value = vec[i]; + print.value = data.cvec[i]; if (total) { - print.pdf = vec[i] / total; + print.pdf = data.cvec[i] / total; print.cdf += print.pdf; } print(stream); } - } else { Counter _min; Result _pdf; @@ -473,18 +505,18 @@ DistPrint::operator()(ostream &stream) const print.flags = flags | __substat; - for (int i = 0; i < size; ++i) { - if (flags & nozero && vec[i] == 0.0 || - flags & nonan && isnan(vec[i])) + for (off_type i = 0; i < size; ++i) { + if ((flags & nozero && data.cvec[i] == 0.0) || + (flags & nonan && isnan(data.cvec[i]))) continue; _min = i * bucket_size + min; - _pdf = vec[i] / total * 100.0; + _pdf = data.cvec[i] / total * 100.0; _cdf += _pdf; print.name = ValueToString(_min, 0, compat); - print.value = vec[i]; + print.value = data.cvec[i]; print.pdf = (flags & pdf) ? _pdf : NAN; print.cdf = (flags & cdf) ? _cdf : NAN; print(stream); @@ -493,11 +525,11 @@ DistPrint::operator()(ostream &stream) const print.flags = flags; } - if (!compat || overflow > 0.0) { + if (!compat || data.overflow > 0.0) { print.name = base + "overflows"; - print.value = overflow; + print.value = data.overflow; if (!compat && total) { - print.pdf = overflow / total; + print.pdf = data.overflow / total; print.cdf += print.pdf; } else { print.pdf = NAN; @@ -516,17 +548,16 @@ DistPrint::operator()(ostream &stream) const } print.name = base + "max_value"; - print.value = max_val; + print.value = data.max_val; print(stream); - if (!compat && samples != 0) { + if (!compat && data.samples != 0) { print.name = base + "mean"; - print.value = sum / samples; + print.value = data.sum / data.samples; print(stream); print.name = base + "stdev"; - print.value = sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))); + print.value = stdev; print(stream); } @@ -535,19 +566,19 @@ DistPrint::operator()(ostream &stream) const } void -Text::visit(const ScalarData &data) +Text::visit(const ScalarInfoBase &info) { - if (noOutput(data)) + if (noOutput(info)) return; ScalarPrint print; - print.value = data.result(); - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; + print.value = info.result(); + print.name = info.name; + print.desc = info.desc; + print.flags = info.flags; print.compat = compat; print.descriptions = descriptions; - print.precision = data.precision; + print.precision = info.precision; print.pdf = NAN; print.cdf = NAN; @@ -555,32 +586,32 @@ Text::visit(const ScalarData &data) } void -Text::visit(const VectorData &data) +Text::visit(const VectorInfoBase &info) { - if (noOutput(data)) + if (noOutput(info)) return; - int size = data.size(); + size_type size = info.size(); VectorPrint print; - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; + print.name = info.name; + print.desc = info.desc; + print.flags = info.flags; print.compat = compat; print.descriptions = descriptions; - print.precision = data.precision; - print.vec = data.result(); - print.total = data.total(); - - if (!data.subnames.empty()) { - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty()) { - print.subnames = data.subnames; + print.precision = info.precision; + print.vec = info.result(); + print.total = info.total(); + + if (!info.subnames.empty()) { + for (off_type i = 0; i < size; ++i) { + if (!info.subnames[i].empty()) { + print.subnames = info.subnames; print.subnames.resize(size); - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty() && - !data.subdescs[i].empty()) { - print.subdescs = data.subdescs; + for (off_type i = 0; i < size; ++i) { + if (!info.subnames[i].empty() && + !info.subdescs[i].empty()) { + print.subdescs = info.subdescs; print.subdescs.resize(size); break; } @@ -594,53 +625,54 @@ Text::visit(const VectorData &data) } void -Text::visit(const Vector2dData &data) +Text::visit(const Vector2dInfoBase &info) { - if (noOutput(data)) + if (noOutput(info)) return; bool havesub = false; VectorPrint print; - print.subnames = data.y_subnames; - print.flags = data.flags; + print.subnames = info.y_subnames; + print.flags = info.flags; print.compat = compat; print.descriptions = descriptions; - print.precision = data.precision; + print.precision = info.precision; - if (!data.subnames.empty()) { - for (int i = 0; i < data.x; ++i) - if (!data.subnames[i].empty()) + if (!info.subnames.empty()) { + for (off_type i = 0; i < info.x; ++i) + if (!info.subnames[i].empty()) havesub = true; } - VResult tot_vec(data.y); + VResult tot_vec(info.y); Result super_total = 0.0; - for (int i = 0; i < data.x; ++i) { - if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) + for (off_type i = 0; i < info.x; ++i) { + if (havesub && (i >= info.subnames.size() || info.subnames[i].empty())) continue; - int iy = i * data.y; - VResult yvec(data.y); + off_type iy = i * info.y; + VResult yvec(info.y); Result total = 0.0; - for (int j = 0; j < data.y; ++j) { - yvec[j] = data.cvec[iy + j]; + for (off_type j = 0; j < info.y; ++j) { + yvec[j] = info.cvec[iy + j]; tot_vec[j] += yvec[j]; total += yvec[j]; super_total += yvec[j]; } - print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); - print.desc = data.desc; + print.name = info.name + "_" + + (havesub ? info.subnames[i] : to_string(i)); + print.desc = info.desc; print.vec = yvec; print.total = total; print(*stream); } - if ((data.flags & ::Stats::total) && (data.x > 1)) { - print.name = data.name; - print.desc = data.desc; + if ((info.flags & ::Stats::total) && (info.x > 1)) { + print.name = info.name; + print.desc = info.desc; print.vec = tot_vec; print.total = super_total; print(*stream); @@ -648,82 +680,31 @@ Text::visit(const Vector2dData &data) } void -Text::visit(const DistData &data) +Text::visit(const DistInfoBase &info) { - if (noOutput(data)) + if (noOutput(info)) return; - DistPrint print; - - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data.min_val; - print.max_val = data.data.max_val; - print.underflow = data.data.underflow; - print.overflow = data.data.overflow; - print.vec.resize(data.data.cvec.size()); - for (int i = 0; i < print.vec.size(); ++i) - print.vec[i] = (Result)data.data.cvec[i]; - print.sum = data.data.sum; - print.squares = data.data.squares; - print.samples = data.data.samples; - - print.min = data.data.min; - print.max = data.data.max; - print.bucket_size = data.data.bucket_size; - print.size = data.data.size; - print.fancy = data.data.fancy; - + DistPrint print(info); print(*stream); } void -Text::visit(const VectorDistData &data) +Text::visit(const VectorDistInfoBase &info) { - if (noOutput(data)) + if (noOutput(info)) return; - for (int i = 0; i < data.size(); ++i) { - DistPrint print; - - print.name = data.name + - (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); - print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data[i].min_val; - print.max_val = data.data[i].max_val; - print.underflow = data.data[i].underflow; - print.overflow = data.data[i].overflow; - print.vec.resize(data.data[i].cvec.size()); - for (int j = 0; j < print.vec.size(); ++j) - print.vec[j] = (Result)data.data[i].cvec[j]; - print.sum = data.data[i].sum; - print.squares = data.data[i].squares; - print.samples = data.data[i].samples; - - print.min = data.data[i].min; - print.max = data.data[i].max; - print.bucket_size = data.data[i].bucket_size; - print.size = data.data[i].size; - print.fancy = data.data[i].fancy; - + for (off_type i = 0; i < info.size(); ++i) { + DistPrint print(info, i); print(*stream); } } void -Text::visit(const FormulaData &data) +Text::visit(const FormulaInfoBase &info) { - visit((const VectorData &)data); + visit((const VectorInfoBase &)info); } bool @@ -746,5 +727,4 @@ initText(const string &filename, bool desc, bool compat) return true; } - /* namespace Stats */ } diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh index 781d1083d..38e0202eb 100644 --- a/src/base/stats/text.hh +++ b/src/base/stats/text.hh @@ -46,7 +46,7 @@ class Text : public Output std::ostream *stream; protected: - bool noOutput(const StatData &data); + bool noOutput(const Info &info); public: bool compat; @@ -62,12 +62,12 @@ class Text : public Output void open(const std::string &file); // Implement Visit - virtual void visit(const ScalarData &data); - virtual void visit(const VectorData &data); - virtual void visit(const DistData &data); - virtual void visit(const VectorDistData &data); - virtual void visit(const Vector2dData &data); - virtual void visit(const FormulaData &data); + virtual void visit(const ScalarInfoBase &info); + virtual void visit(const VectorInfoBase &info); + virtual void visit(const DistInfoBase &info); + virtual void visit(const VectorDistInfoBase &info); + virtual void visit(const Vector2dInfoBase &info); + virtual void visit(const FormulaInfoBase &info); // Implement Output virtual bool valid() const; diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh index b64e8fb17..e561f94ad 100644 --- a/src/base/stats/types.hh +++ b/src/base/stats/types.hh @@ -31,7 +31,9 @@ #ifndef __BASE_STATS_TYPES_HH__ #define __BASE_STATS_TYPES_HH__ +#include <limits> #include <vector> + #include "sim/host.hh" namespace Stats { @@ -41,11 +43,16 @@ typedef double Counter; /** vector of counters. */ typedef std::vector<Counter> VCounter; +typedef std::numeric_limits<Counter> CounterLimits; + /** All results are doubles. */ typedef double Result; /** vector of results. */ typedef std::vector<Result> VResult; +typedef unsigned int size_type; +typedef unsigned int off_type; + /* namespace Stats */ } #endif // __BASE_STATS_TYPES_HH__ diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh index 0087c227c..9d6996689 100644 --- a/src/base/stats/visit.hh +++ b/src/base/stats/visit.hh @@ -38,26 +38,26 @@ namespace Stats { -class StatData; -class ScalarData; -class VectorData; -class DistDataData; -class DistData; -class VectorDistData; -class Vector2dData; -class FormulaData; +class Info; +class ScalarInfoBase; +class VectorInfoBase; +class DistInfoBase; +class DistInfoBase; +class VectorDistInfoBase; +class Vector2dInfoBase; +class FormulaInfoBase; struct Visit { Visit(); virtual ~Visit(); - virtual void visit(const ScalarData &data) = 0; - virtual void visit(const VectorData &data) = 0; - virtual void visit(const DistData &data) = 0; - virtual void visit(const VectorDistData &data) = 0; - virtual void visit(const Vector2dData &data) = 0; - virtual void visit(const FormulaData &data) = 0; + virtual void visit(const ScalarInfoBase &info) = 0; + virtual void visit(const VectorInfoBase &info) = 0; + virtual void visit(const DistInfoBase &info) = 0; + virtual void visit(const VectorDistInfoBase &info) = 0; + virtual void visit(const Vector2dInfoBase &info) = 0; + virtual void visit(const FormulaInfoBase &info) = 0; }; /* namespace Stats */ } diff --git a/src/base/str.cc b/src/base/str.cc index 0a517dff5..2df1c103c 100644 --- a/src/base/str.cc +++ b/src/base/str.cc @@ -28,10 +28,10 @@ * Authors: Nathan Binkert */ -#include <ctype.h> - +#include <cctype> #include <cstring> #include <iostream> +#include <limits> #include <string> #include <vector> @@ -117,12 +117,11 @@ inline bool __to_number(string value, T &retval) { static const T maxnum = ((T)-1); - static const bool sign = maxnum < 0; - static const int bits = sizeof(T) * 8; - static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1); - static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1); - static const T signmax = - (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum; + static const bool sign = numeric_limits<T>::is_signed; + static const int bits = numeric_limits<T>::digits; + static const T hexmax = maxnum & (((T)1 << (bits - 4)) - 1); + static const T octmax = maxnum & (((T)1 << (bits - 3)) - 1); + static const T signmax = numeric_limits<T>::max(); static const T decmax = signmax / 10; #if 0 diff --git a/src/base/time.cc b/src/base/time.cc index 76ba355b7..a1732773e 100644 --- a/src/base/time.cc +++ b/src/base/time.cc @@ -28,9 +28,9 @@ * Authors: Nathan Binkert */ -#include <sys/types.h> -#include <sys/time.h> -#include <time.h> +#include <cctype> +#include <cstring> +#include <ctime> #include <iostream> #include <string> diff --git a/src/base/time.hh b/src/base/time.hh index f10cc5d6c..565ea0aac 100644 --- a/src/base/time.hh +++ b/src/base/time.hh @@ -68,7 +68,7 @@ std::ostream &operator<<(std::ostream &out, const Time &time); /* * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -94,7 +94,7 @@ std::ostream &operator<<(std::ostream &out, const Time &time); * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)time.h 8.2 (Berkeley) 7/10/94 + * @(#)time.h 8.2 (Berkeley) 7/10/94 */ #if defined(__sun) diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh index 348f7a673..9f9fc32b5 100644 --- a/src/base/timebuf.hh +++ b/src/base/timebuf.hh @@ -43,6 +43,7 @@ class TimeBuffer int past; int future; int size; + int _id; char *data; std::vector<char *> index; @@ -148,6 +149,8 @@ class TimeBuffer new (ptr) T; ptr += sizeof(T); } + + _id = -1; } TimeBuffer() @@ -162,6 +165,16 @@ class TimeBuffer delete [] data; } + void id(int id) + { + _id = id; + } + + int id() + { + return _id; + } + void advance() { diff --git a/src/base/trace.hh b/src/base/trace.hh index c1b506187..fa24e9c48 100644 --- a/src/base/trace.hh +++ b/src/base/trace.hh @@ -97,6 +97,12 @@ inline const std::string &name() { return Trace::DefaultName; } Trace::dprintf(curTick, name(), __VA_ARGS__); \ } while (0) +#define DPRINTFS(x,s, ...) do { \ + if (DTRACE(x)) \ + Trace::dprintf(curTick, s->name(), __VA_ARGS__); \ +} while (0) + + #define DPRINTFR(x, ...) do { \ if (DTRACE(x)) \ Trace::dprintf((Tick)-1, std::string(), __VA_ARGS__); \ @@ -119,11 +125,12 @@ inline const std::string &name() { return Trace::DefaultName; } #define DTRACE(x) (false) #define DDUMP(x, data, count) do {} while (0) #define DPRINTF(x, ...) do {} while (0) +#define DPRINTFS(x, ...) do {} while (0) #define DPRINTFR(...) do {} while (0) #define DDUMPN(data, count) do {} while (0) #define DPRINTFN(...) do {} while (0) #define DPRINTFNR(...) do {} while (0) -#endif // TRACING_ON +#endif // TRACING_ON #endif // __BASE_TRACE_HH__ diff --git a/src/base/varargs.hh b/src/base/varargs.hh index 2ba8c240a..4328f2057 100644 --- a/src/base/varargs.hh +++ b/src/base/varargs.hh @@ -147,15 +147,31 @@ struct Any : public Base<RECV> } }; +template <typename T, class RECV> +struct Any<T *, RECV> : public Base<RECV> +{ + const T *argument; + + Any(const T *arg) : argument(arg) {} + + virtual void + add_arg(RECV &receiver) const + { + receiver.add_arg(argument); + } +}; + template <class RECV> struct Argument : public RefCountingPtr<Base<RECV> > { - typedef RefCountingPtr<Base<RECV> > Base; + typedef RefCountingPtr<VarArgs::Base<RECV> > Base; Argument() { } Argument(const Null &null) { } template <typename T> Argument(const T& arg) : Base(new Any<T, RECV>(arg)) { } + template <typename T> + Argument(const T* arg) : Base(new Any<T *, RECV>(arg)) { } void add_arg(RECV &receiver) const @@ -169,7 +185,7 @@ template<class RECV> class List { public: - typedef Argument<RECV> Argument; + typedef VarArgs::Argument<RECV> Argument; typedef std::list<Argument> list; typedef typename list::iterator iterator; typedef typename list::const_iterator const_iterator; diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index c2a865113..f3688e991 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -26,7 +26,7 @@ # # Authors: Nathan Binkert -from m5.SimObject import SimObject +from MemObject import MemObject from m5.params import * from m5.proxy import * from m5 import build_env @@ -39,50 +39,84 @@ default_tracer = ExeTracer() if build_env['TARGET_ISA'] == 'alpha': from AlphaTLB import AlphaDTB, AlphaITB + if build_env['FULL_SYSTEM']: + from AlphaInterrupts import AlphaInterrupts elif build_env['TARGET_ISA'] == 'sparc': from SparcTLB import SparcDTB, SparcITB + if build_env['FULL_SYSTEM']: + from SparcInterrupts import SparcInterrupts elif build_env['TARGET_ISA'] == 'x86': from X86TLB import X86DTB, X86ITB + if build_env['FULL_SYSTEM']: + from X86LocalApic import X86LocalApic elif build_env['TARGET_ISA'] == 'mips': from MipsTLB import MipsTLB,MipsDTB, MipsITB, MipsUTB + if build_env['FULL_SYSTEM']: + from MipsInterrupts import MipsInterrupts elif build_env['TARGET_ISA'] == 'arm': from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB + if build_env['FULL_SYSTEM']: + from ArmInterrupts import ArmInterrupts -class BaseCPU(SimObject): +class BaseCPU(MemObject): type = 'BaseCPU' abstract = True system = Param.System(Parent.any, "system object") - cpu_id = Param.Int("CPU identifier") + cpu_id = Param.Int(-1, "CPU identifier") + numThreads = Param.Unsigned(1, "number of HW thread contexts") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") + + checker = Param.BaseCPU(NULL, "checker CPU") + + do_checkpoint_insts = Param.Bool(True, + "enable checkpoint pseudo instructions") + do_statistics_insts = Param.Bool(True, + "enable statistics pseudo instructions") if build_env['FULL_SYSTEM']: + profile = Param.Latency('0ns', "trace the kernel stack") do_quiesce = Param.Bool(True, "enable quiesce instructions") - do_checkpoint_insts = Param.Bool(True, - "enable checkpoint pseudo instructions") - do_statistics_insts = Param.Bool(True, - "enable statistics pseudo instructions") else: workload = VectorParam.Process("processes to run") if build_env['TARGET_ISA'] == 'sparc': dtb = Param.SparcDTB(SparcDTB(), "Data TLB") itb = Param.SparcITB(SparcITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.SparcInterrupts( + SparcInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'alpha': dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB") itb = Param.AlphaITB(AlphaITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.AlphaInterrupts( + AlphaInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'x86': dtb = Param.X86DTB(X86DTB(), "Data TLB") itb = Param.X86ITB(X86ITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + _localApic = X86LocalApic(pio_addr=0x2000000000000000) + interrupts = \ + Param.X86LocalApic(_localApic, "Interrupt Controller") elif build_env['TARGET_ISA'] == 'mips': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.MipsDTB(MipsDTB(), "Data TLB") itb = Param.MipsITB(MipsITB(), "Instruction TLB") tlb = Param.MipsUTB(MipsUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.MipsInterrupts( + MipsInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'arm': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.ArmDTB(ArmDTB(), "Data TLB") itb = Param.ArmITB(ArmITB(), "Instruction TLB") tlb = Param.ArmUTB(ArmUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.ArmInterrupts( + ArmInterrupts(), "Interrupt Controller") else: print "Don't know what TLB to use for ISA %s" % \ build_env['TARGET_ISA'] @@ -109,7 +143,10 @@ class BaseCPU(SimObject): _mem_ports = [] if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']: - _mem_ports = ["itb.walker.port", "dtb.walker.port"] + _mem_ports = ["itb.walker.port", + "dtb.walker.port", + "interrupts.pio", + "interrupts.int_port"] def connectMemPorts(self, bus): for p in self._mem_ports: diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py new file mode 100644 index 000000000..bff9af62d --- /dev/null +++ b/src/cpu/CheckerCPU.py @@ -0,0 +1,42 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from m5.params import * +from m5 import build_env +from BaseCPU import BaseCPU + +class CheckerCPU(BaseCPU): + type = 'CheckerCPU' + abstract = True + exitOnError = Param.Bool(False, "Exit on an error") + updateOnError = Param.Bool(False, + "Update the checker with the main CPU's state on an error") + warnOnlyOnLoadError = Param.Bool(False, + "If a load result is incorrect, only print a warning and do not exit") + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py index e904f9e7d..5754f5d5b 100644 --- a/src/cpu/ExeTracer.py +++ b/src/cpu/ExeTracer.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class ExeTracer(InstTracer): type = 'ExeTracer' - cxx_namespace = 'Trace' - cxx_class = 'ExeTracer' + cxx_class = 'Trace::ExeTracer' diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py index 6e8f567b3..3642f3174 100644 --- a/src/cpu/IntelTrace.py +++ b/src/cpu/IntelTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class IntelTrace(InstTracer): type = 'IntelTrace' - cxx_namespace = 'Trace' - cxx_class = 'IntelTrace' + cxx_class = 'Trace::IntelTrace' diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py index f9b6470a6..d450dd00e 100644 --- a/src/cpu/LegionTrace.py +++ b/src/cpu/LegionTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class LegionTrace(InstTracer): type = 'LegionTrace' - cxx_namespace = 'Trace' - cxx_class = 'LegionTrace' + cxx_class = 'Trace::LegionTrace' diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py index 96b4e991b..f410b5473 100644 --- a/src/cpu/NativeTrace.py +++ b/src/cpu/NativeTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class NativeTrace(InstTracer): type = 'NativeTrace' - cxx_namespace = 'Trace' - cxx_class = 'NativeTrace' + cxx_class = 'Trace::NativeTrace' diff --git a/src/cpu/SConscript b/src/cpu/SConscript index c7d0c33bd..eee8edca4 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -48,12 +48,14 @@ execfile(models_db.srcnode().abspath) # Template for execute() signature. exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const { panic("initiateAcc not defined!"); M5_DUMMY_RETURN }; -virtual Fault completeAcc(Packet *pkt, %s *xc, +virtual Fault completeAcc(Packet *pkt, %(type)s *xc, Trace::InstRecord *traceData) const { panic("completeAcc not defined!"); M5_DUMMY_RETURN }; +virtual int memAccSize(%(type)s *xc) +{ panic("memAccSize not defined!"); M5_DUMMY_RETURN }; ''' mem_ini_sig_template = ''' @@ -71,6 +73,7 @@ temp_cpu_list = env['CPU_MODELS'][:] if env['USE_CHECKER']: temp_cpu_list.append('CheckerCPU') + SimObject('CheckerCPU.py') # Generate header. def gen_cpu_exec_signatures(target, source, env): @@ -81,7 +84,7 @@ def gen_cpu_exec_signatures(target, source, env): ''' for cpu in temp_cpu_list: xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % (xc_type, xc_type, xc_type) + print >> f, exec_sig_template % { 'type' : xc_type } print >> f, ''' #endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ ''' @@ -165,10 +168,12 @@ TraceFlag('ExecSpeculative') TraceFlag('ExecSymbol') TraceFlag('ExecThread') TraceFlag('ExecTicks') +TraceFlag('ExecMicro') +TraceFlag('ExecMacro') TraceFlag('Fetch') TraceFlag('IntrControl') TraceFlag('PCEvent') TraceFlag('Quiesce') CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread', - 'ExecEffAddr', 'ExecResult', 'ExecSymbol' ]) + 'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro' ]) diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc index 15e0556ad..a2a34edf9 100644 --- a/src/cpu/activity.cc +++ b/src/cpu/activity.cc @@ -28,15 +28,18 @@ * Authors: Kevin Lim */ -#include <cstring> +#include <string> #include "base/timebuf.hh" #include "cpu/activity.hh" -ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency, - int activity) - : activityBuffer(longest_latency, 0), longestLatency(longest_latency), - activityCount(activity), numStages(num_stages) +using namespace std; + +ActivityRecorder::ActivityRecorder(const string &name, int num_stages, + int longest_latency, int activity) + : _name(name), activityBuffer(longest_latency, 0), + longestLatency(longest_latency), activityCount(activity), + numStages(num_stages) { stageActive = new bool[numStages]; std::memset(stageActive, 0, numStages); diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh index e99927339..d75ff150e 100644 --- a/src/cpu/activity.hh +++ b/src/cpu/activity.hh @@ -49,9 +49,11 @@ * idle. If count is zero, then the CPU can safely idle as it has no * more outstanding work to do. */ -class ActivityRecorder { +class ActivityRecorder +{ public: - ActivityRecorder(int num_stages, int longest_latency, int count); + ActivityRecorder(const std::string &name, int num_stages, + int longest_latency, int count); /** Records that there is activity this cycle. */ void activity(); @@ -92,6 +94,10 @@ class ActivityRecorder { void validate(); private: + // provide name() for DPRINTF. + std::string _name; + const std::string &name() { return _name; } + /** Time buffer that tracks if any cycles has active communication * in them. It should be as long as the longest communication * latency in the system. Each time any time buffer is written, diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 23195f720..0ef206d90 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -37,17 +37,17 @@ #include "base/loader/symtab.hh" #include "base/misc.hh" #include "base/output.hh" +#include "base/trace.hh" #include "cpu/base.hh" #include "cpu/cpuevent.hh" #include "cpu/thread_context.hh" #include "cpu/profile.hh" +#include "params/BaseCPU.hh" #include "sim/sim_exit.hh" #include "sim/process.hh" #include "sim/sim_events.hh" #include "sim/system.hh" -#include "base/trace.hh" - // Hack #include "sim/stat_control.hh" @@ -60,13 +60,12 @@ vector<BaseCPU *> BaseCPU::cpuList; // been initialized int maxThreadsPerCPU = 1; -CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival, - BaseCPU *_cpu) - : Event(q, Event::Progress_Event_Pri), interval(ival), - lastNumInst(0), cpu(_cpu) +CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) + : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0), + cpu(_cpu) { if (interval) - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } void @@ -84,7 +83,7 @@ CPUProgressEvent::process() curTick, cpu->name(), temp - lastNumInst); #endif lastNumInst = temp; - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } const char * @@ -95,21 +94,29 @@ CPUProgressEvent::description() const #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0), - params(p), number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id), + interrupts(p->interrupts), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #else BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), _cpuId(p->cpu_id), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #endif { // currentTick = curTick; + // if Python did not provide a valid ID, do it here + if (_cpuId == -1 ) { + _cpuId = cpuList.size(); + } + // add self to global list of CPUs cpuList.push_back(this); + DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId); + if (number_of_threads > maxThreadsPerCPU) maxThreadsPerCPU = number_of_threads; @@ -121,22 +128,26 @@ BaseCPU::BaseCPU(Params *p) // // set up instruction-count-based termination events, if any // - if (p->max_insts_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - schedExitSimLoop("a thread reached the max instruction count", - p->max_insts_any_thread, 0, - comInstEventQueue[i]); + if (p->max_insts_any_thread != 0) { + const char *cause = "a thread reached the max instruction count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } + } if (p->max_insts_all_threads != 0) { + const char *cause = "all threads reached the max instruction count"; + // allocate & initialize shared downcounter: each event will // decrement this when triggered; simulation will terminate // when counter reaches 0 int *counter = new int; *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comInstEventQueue[i], - "all threads reached the max instruction count", - p->max_insts_all_threads, *counter); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } } // allocate per-thread load-based event queues @@ -147,53 +158,49 @@ BaseCPU::BaseCPU(Params *p) // // set up instruction-count-based termination events, if any // - if (p->max_loads_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - schedExitSimLoop("a thread reached the max load count", - p->max_loads_any_thread, 0, - comLoadEventQueue[i]); + if (p->max_loads_any_thread != 0) { + const char *cause = "a thread reached the max load count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread); + } + } if (p->max_loads_all_threads != 0) { + const char *cause = "all threads reached the max load count"; // allocate & initialize shared downcounter: each event will // decrement this when triggered; simulation will terminate // when counter reaches 0 int *counter = new int; *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comLoadEventQueue[i], - "all threads reached the max load count", - p->max_loads_all_threads, *counter); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads); + } } functionTracingEnabled = false; - if (p->functionTrace) { + if (p->function_trace) { functionTraceStream = simout.find(csprintf("ftrace.%s", name())); currentFunctionStart = currentFunctionEnd = 0; - functionEntryTick = p->functionTraceStart; + functionEntryTick = p->function_trace_start; - if (p->functionTraceStart == 0) { + if (p->function_trace_start == 0) { functionTracingEnabled = true; } else { - new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, - p->functionTraceStart, - true); + typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap; + Event *event = new wrap(this, true); + schedule(event, p->function_trace_start); } } #if FULL_SYSTEM - profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - tracer = params->tracer; -} + interrupts->setCPU(this); -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; + profileEvent = NULL; + if (params()->profile) + profileEvent = new ProfileEvent(this, params()->profile); #endif - checker = NULL; - tracer = NULL; + tracer = params()->tracer; } void @@ -209,7 +216,7 @@ BaseCPU::~BaseCPU() void BaseCPU::init() { - if (!params->deferRegistration) + if (!params()->defer_registration) registerThreadContexts(); } @@ -217,14 +224,14 @@ void BaseCPU::startup() { #if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) - profileEvent->schedule(curTick); + if (!params()->defer_registration && profileEvent) + schedule(profileEvent, curTick); #endif - if (params->progress_interval) { - new CPUProgressEvent(&mainEventQueue, - ticks(params->progress_interval), - this); + if (params()->progress_interval) { + Tick num_ticks = ticks(params()->progress_interval); + Event *event = new CPUProgressEvent(this, num_ticks); + schedule(event, curTick + num_ticks); } } @@ -280,14 +287,19 @@ BaseCPU::registerThreadContexts() for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; -#if FULL_SYSTEM - int id = params->cpu_id; - if (id != -1) - id += i; - - tc->setCpuId(system->registerThreadContext(tc, id)); -#else - tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc)); + /** This is so that contextId and cpuId match where there is a + * 1cpu:1context relationship. Otherwise, the order of registration + * could affect the assignment and cpu 1 could have context id 3, for + * example. We may even want to do something like this for SMT so that + * cpu 0 has the lowest thread contexts and cpu N has the highest, but + * I'll just do this for now + */ + if (number_of_threads == 1) + tc->setContextId(system->registerThreadContext(tc, _cpuId)); + else + tc->setContextId(system->registerThreadContext(tc)); +#if !FULL_SYSTEM + tc->getProcessPtr()->assignThreadContext(tc->contextId()); #endif } } @@ -309,7 +321,7 @@ BaseCPU::switchOut() // panic("This CPU doesn't support sampling!"); #if FULL_SYSTEM if (profileEvent && profileEvent->scheduled()) - profileEvent->deschedule(); + deschedule(profileEvent); #endif } @@ -318,6 +330,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) { assert(threadContexts.size() == oldCPU->threadContexts.size()); + _cpuId = oldCPU->cpuId(); + for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *newTC = threadContexts[i]; ThreadContext *oldTC = oldCPU->threadContexts[i]; @@ -326,53 +340,49 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); - assert(newTC->readCpuId() == oldTC->readCpuId()); -#if FULL_SYSTEM - system->replaceThreadContext(newTC, newTC->readCpuId()); -#else - assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); - newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId()); -#endif + assert(newTC->contextId() == oldTC->contextId()); + assert(newTC->threadId() == oldTC->threadId()); + system->replaceThreadContext(newTC, newTC->contextId()); - if (DTRACE(Context)) + /* This code no longer works since the zero register (e.g., + * r31 on Alpha) doesn't necessarily contain zero at this + * point. + if (DTRACE(Context)) ThreadContext::compare(oldTC, newTC); + */ } #if FULL_SYSTEM interrupts = oldCPU->interrupts; + interrupts->setCPU(this); for (int i = 0; i < threadContexts.size(); ++i) threadContexts[i]->profileClear(); if (profileEvent) - profileEvent->schedule(curTick); + schedule(profileEvent, curTick); #endif // Connect new CPU to old CPU's memory only if new CPU isn't // connected to anything. Also connect old CPU's memory to new // CPU. - Port *peer; - if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("icache_port")->getPeer(); + if (!ic->isConnected()) { + Port *peer = oldCPU->getPort("icache_port")->getPeer(); ic->setPeer(peer); - } else { - peer = ic->getPeer(); + peer->setPeer(ic); } - peer->setPeer(ic); - if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("dcache_port")->getPeer(); + if (!dc->isConnected()) { + Port *peer = oldCPU->getPort("dcache_port")->getPeer(); dc->setPeer(peer); - } else { - peer = dc->getPeer(); + peer->setPeer(dc); } - peer->setPeer(dc); } #if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) +BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) + : cpu(_cpu), interval(_interval) { } void @@ -383,45 +393,21 @@ BaseCPU::ProfileEvent::process() tc->profileSample(); } - schedule(curTick + interval); -} - -void -BaseCPU::post_interrupt(int int_num, int index) -{ - interrupts.post(int_num, index); -} - -void -BaseCPU::clear_interrupt(int int_num, int index) -{ - interrupts.clear(int_num, index); -} - -void -BaseCPU::clear_interrupts() -{ - interrupts.clear_all(); -} - -uint64_t -BaseCPU::get_interrupts(int int_num) -{ - return interrupts.get_vec(int_num); + cpu->schedule(this, curTick + interval); } void BaseCPU::serialize(std::ostream &os) { SERIALIZE_SCALAR(instCnt); - interrupts.serialize(os); + interrupts->serialize(os); } void BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(instCnt); - interrupts.unserialize(cp, section); + interrupts->unserialize(cp, section); } #endif // FULL_SYSTEM diff --git a/src/cpu/base.hh b/src/cpu/base.hh index bdc7d7c8b..8af3295eb 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -35,6 +35,7 @@ #include <vector> #include "arch/isa_traits.hh" +#include "arch/microcode_rom.hh" #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" @@ -45,6 +46,7 @@ #include "arch/interrupts.hh" #endif +class BaseCPUParams; class BranchPred; class CheckerCPU; class ThreadContext; @@ -64,7 +66,7 @@ class CPUProgressEvent : public Event BaseCPU *cpu; public: - CPUProgressEvent(EventQueue *q, Tick ival, BaseCPU *_cpu); + CPUProgressEvent(BaseCPU *_cpu, Tick ival); void process(); @@ -78,8 +80,16 @@ class BaseCPU : public MemObject Tick clock; // @todo remove me after debugging with legion done Tick instCnt; + // every cpu has an id, put it in the base cpu + // Set at initialization, only time a cpuId might change is during a + // takeover (which should be done from within the BaseCPU anyway, + // therefore no setCpuId() method is provided + int _cpuId; public: + /** Reads this CPU's ID. */ + int cpuId() { return _cpuId; } + // Tick currentTick; inline Tick frequency() const { return Clock::Frequency / clock; } inline Tick ticks(int numCycles) const { return clock * numCycles; } @@ -102,29 +112,54 @@ class BaseCPU : public MemObject */ Tick nextCycle(Tick begin_tick); + TheISA::MicrocodeRom microcodeRom; + #if FULL_SYSTEM protected: -// uint64_t interrupts[TheISA::NumInterruptLevels]; -// uint64_t intstatus; - TheISA::Interrupts interrupts; + TheISA::Interrupts *interrupts; public: - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); - virtual uint64_t get_interrupts(int int_num); + TheISA::Interrupts * + getInterruptController() + { + return interrupts; + } + + virtual void wakeup() = 0; + + void + postInterrupt(int int_num, int index) + { + interrupts->post(int_num, index); + wakeup(); + } + + void + clearInterrupt(int int_num, int index) + { + interrupts->clear(int_num, index); + } + + void + clearInterrupts() + { + interrupts->clearAll(); + } - bool check_interrupts(ThreadContext * tc) const - { return interrupts.check_interrupts(tc); } + bool + checkInterrupts(ThreadContext *tc) const + { + return interrupts->checkInterrupts(tc); + } class ProfileEvent : public Event { private: BaseCPU *cpu; - int interval; + Tick interval; public: - ProfileEvent(BaseCPU *cpu, int interval); + ProfileEvent(BaseCPU *cpu, Tick interval); void process(); }; ProfileEvent *profileEvent; @@ -162,40 +197,9 @@ class BaseCPU : public MemObject ThreadContext *getContext(int tn) { return threadContexts[tn]; } public: - struct Params - { - std::string name; - int numberOfThreads; - bool deferRegistration; - Counter max_insts_any_thread; - Counter max_insts_all_threads; - Counter max_loads_any_thread; - Counter max_loads_all_threads; - Tick clock; - bool functionTrace; - Tick functionTraceStart; - System *system; - int cpu_id; - Trace::InstTracer * tracer; - - Tick phase; -#if FULL_SYSTEM - Tick profile; - - bool do_statistics_insts; - bool do_checkpoint_insts; - bool do_quiesce; -#endif - Tick progress_interval; - BaseCPU *checker; - - TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core - - Params(); - }; - - const Params *params; - + typedef BaseCPUParams Params; + const Params *params() const + { return reinterpret_cast<const Params *>(_params); } BaseCPU(Params *params); virtual ~BaseCPU(); @@ -221,6 +225,8 @@ class BaseCPU : public MemObject */ int number_of_threads; + TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core + /** * Vector of per-thread instruction-based event queues. Used for * scheduling events based on number of instructions committed by @@ -298,7 +304,7 @@ class BaseCPU : public MemObject public: // Number of CPU cycles simulated - Stats::Scalar<> numCycles; + Stats::Scalar numCycles; }; #endif // __CPU_BASE_HH__ diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index bea680fac..41c57cf39 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -77,8 +77,8 @@ class BaseDynInst : public FastAlloc, public RefCounted typedef typename std::list<DynInstPtr>::iterator ListIt; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs }; /** The StaticInst used by this BaseDynInst. */ @@ -115,9 +115,6 @@ class BaseDynInst : public FastAlloc, public RefCounted template <class T> Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Does a write to a given address. * @param data The data to be written. @@ -130,9 +127,6 @@ class BaseDynInst : public FastAlloc, public RefCounted Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void prefetch(Addr addr, unsigned flags); void writeHint(Addr addr, int size, unsigned flags); Fault copySrcTranslate(Addr src); @@ -258,9 +252,6 @@ class BaseDynInst : public FastAlloc, public RefCounted public: - /** Count of total number of dynamic instructions. */ - static int instcount; - #ifdef DEBUG void dumpSNList(); #endif @@ -412,7 +403,10 @@ class BaseDynInst : public FastAlloc, public RefCounted void dump(std::string &outstring); /** Read this CPU's ID. */ - int readCpuId() { return cpu->readCpuId(); } + int cpuId() { return cpu->cpuId(); } + + /** Read this context's system-wide ID **/ + int contextId() { return thread->contextId(); } /** Returns the fault type. */ Fault getFault() { return fault; } @@ -486,24 +480,24 @@ class BaseDynInst : public FastAlloc, public RefCounted // // Instruction types. Forward checks to StaticInst object. // - bool isNop() const { return staticInst->isNop(); } - bool isMemRef() const { return staticInst->isMemRef(); } - bool isLoad() const { return staticInst->isLoad(); } - bool isStore() const { return staticInst->isStore(); } + bool isNop() const { return staticInst->isNop(); } + bool isMemRef() const { return staticInst->isMemRef(); } + bool isLoad() const { return staticInst->isLoad(); } + bool isStore() const { return staticInst->isStore(); } bool isStoreConditional() const { return staticInst->isStoreConditional(); } bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } bool isCopy() const { return staticInst->isCopy(); } - bool isInteger() const { return staticInst->isInteger(); } - bool isFloating() const { return staticInst->isFloating(); } - bool isControl() const { return staticInst->isControl(); } - bool isCall() const { return staticInst->isCall(); } - bool isReturn() const { return staticInst->isReturn(); } - bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } + bool isInteger() const { return staticInst->isInteger(); } + bool isFloating() const { return staticInst->isFloating(); } + bool isControl() const { return staticInst->isControl(); } + bool isCall() const { return staticInst->isCall(); } + bool isReturn() const { return staticInst->isReturn(); } + bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } - bool isCondCtrl() const { return staticInst->isCondCtrl(); } - bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } + bool isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } bool isThreadSync() const { return staticInst->isThreadSync(); } bool isSerializing() const { return staticInst->isSerializing(); } @@ -560,7 +554,7 @@ class BaseDynInst : public FastAlloc, public RefCounted Addr branchTarget() const { return staticInst->branchTarget(PC); } /** Returns the number of source registers. */ - int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } /** Returns the number of destination registers. */ int8_t numDestRegs() const { return staticInst->numDestRegs(); } @@ -857,29 +851,6 @@ class BaseDynInst : public FastAlloc, public RefCounted }; template<class Impl> -Fault -BaseDynInst<Impl>::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); - - fault = cpu->translateDataReadReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - -template<class Impl> template<class T> inline Fault BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) @@ -887,9 +858,9 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataReadReq(req, thread); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), false); if (req->isUncacheable()) isUncacheable = true; @@ -931,29 +902,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) } template<class Impl> -Fault -BaseDynInst<Impl>::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); - - fault = cpu->translateDataWriteReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - -template<class Impl> template<class T> inline Fault BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) @@ -966,9 +914,9 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataWriteReq(req, thread); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), true); if (req->isUncacheable()) isUncacheable = true; diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 5c18ae694..4ee7d2f2c 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -168,18 +168,21 @@ BaseDynInst<Impl>::initVars() // Initialize the fault to be NoFault. fault = NoFault; - ++instcount; +#ifndef NDEBUG + ++cpu->instcount; - if (instcount > 1500) { - cpu->dumpInsts(); + if (cpu->instcount > 1500) { #ifdef DEBUG + cpu->dumpInsts(); dumpSNList(); #endif - assert(instcount <= 1500); + assert(cpu->instcount <= 1500); } - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.insert(seqNum); @@ -199,10 +202,13 @@ BaseDynInst<Impl>::~BaseDynInst() fault = NoFault; - --instcount; +#ifndef NDEBUG + --cpu->instcount; - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction destroyed. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.erase(seqNum); #endif diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc index a6af98d66..14777bc12 100644 --- a/src/cpu/checker/cpu.cc +++ b/src/cpu/checker/cpu.cc @@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - translateDataReadReq(memReq); + dtb->translateAtomic(memReq, tc, false); PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); @@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - thread->translateDataWriteReq(memReq); + dtb->translateAtomic(memReq, tc, true); // Can compare the write data and result only if it's cacheable, // not a store conditional, or is a store conditional that @@ -325,57 +325,6 @@ CheckerCPU::dbg_vtophys(Addr addr) #endif // FULL_SYSTEM bool -CheckerCPU::translateInstReq(Request *req) -{ -#if FULL_SYSTEM - return (thread->translateInstReq(req) == NoFault); -#else - thread->translateInstReq(req); - return true; -#endif -} - -void -CheckerCPU::translateDataReadReq(Request *req) -{ - thread->translateDataReadReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - -void -CheckerCPU::translateDataWriteReq(Request *req) -{ - thread->translateDataWriteReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - -bool CheckerCPU::checkFlags(Request *req) { // Remove any dynamic flags that don't have to do with the request itself. diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 35dc59ff4..0d3dddded 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -65,6 +65,7 @@ class Process; #endif // FULL_SYSTEM template <class> class BaseDynInst; +class CheckerCPUParams; class ThreadContext; class MemInterface; class Checkpoint; @@ -96,20 +97,10 @@ class CheckerCPU : public BaseCPU public: virtual void init(); - struct Params : public BaseCPU::Params - { -#if FULL_SYSTEM - TheISA::ITB *itb; - TheISA::DTB *dtb; -#else - Process *process; -#endif - bool exitOnError; - bool updateOnError; - bool warnOnlyOnLoadError; - }; - public: + typedef CheckerCPUParams Params; + const Params *params() const + { return reinterpret_cast<const Params *>(_params); } CheckerCPU(Params *p); virtual ~CheckerCPU(); @@ -189,7 +180,7 @@ class CheckerCPU : public BaseCPU // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } + Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } void prefetch(Addr addr, unsigned flags) { @@ -340,10 +331,6 @@ class CheckerCPU : public BaseCPU this->dtb->demapPage(vaddr, asn); } - bool translateInstReq(Request *req); - void translateDataWriteReq(Request *req); - void translateDataReadReq(Request *req); - #if FULL_SYSTEM Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index f3f8a0bb3..26571ed68 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -141,9 +141,9 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) // Try to fetch the instruction #if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 #else -#define IFETCH_FLAGS(pc) 0 +#define IFETCH_FLAGS(pc) 0 #endif uint64_t fetch_PC = thread->readPC() & ~3; @@ -152,9 +152,10 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) memReq = new Request(inst->threadNumber, fetch_PC, sizeof(uint32_t), IFETCH_FLAGS(thread->readPC()), - fetch_PC, thread->readCpuId(), inst->threadNumber); + fetch_PC, thread->contextId(), + inst->threadNumber); - bool succeeded = translateInstReq(memReq); + bool succeeded = itb->translateAtomic(memReq, thread); if (!succeeded) { if (inst->getFault() == NoFault) { diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 15454c3fe..3c87f841f 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -82,7 +82,7 @@ class CheckerThreadContext : public ThreadContext checkerTC->setCpuId(id); } - int readCpuId() { return actualTC->readCpuId(); } + int cpuId() { return actualTC->cpuId(); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } @@ -98,10 +98,8 @@ class CheckerThreadContext : public ThreadContext FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } - - void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } @@ -155,7 +153,7 @@ class CheckerThreadContext : public ThreadContext void profileSample() { return actualTC->profileSample(); } #endif - int getThreadNum() { return actualTC->getThreadNum(); } + int threadId() { return actualTC->threadId(); } // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } @@ -279,29 +277,8 @@ class CheckerThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { - checkerTC->setSyscallArg(i, val); - actualTC->setSyscallArg(i, val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - checkerTC->setSyscallReturn(return_value); - actualTC->setSyscallReturn(return_value); - } - Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - checkerTC->changeRegFileContext(param, val); - } }; #endif // __CPU_CHECKER_EXEC_CONTEXT_HH__ diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py index 5b0c6c4da..793f8c646 100644 --- a/src/cpu/cpu_models.py +++ b/src/cpu/cpu_models.py @@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc', CpuModel('O3CPU', 'o3_cpu_exec.cc', '#include "cpu/o3/isa_specific.hh"', { 'CPU_exec_context': 'O3DynInst' }) +CpuModel('InOrderCPU', 'inorder_cpu_exec.cc', + '#include "cpu/inorder/inorder_dyn_inst.hh"', + { 'CPU_exec_context': 'InOrderDynInst' }) diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh index 5816c6ca1..65f0e87e1 100644 --- a/src/cpu/cpuevent.hh +++ b/src/cpu/cpuevent.hh @@ -58,8 +58,8 @@ class CpuEvent : public Event ThreadContext *tc; public: - CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri) - : Event(q, p), tc(_tc) + CpuEvent(ThreadContext *_tc, Priority p = Default_Pri) + : Event(p), tc(_tc) { cpuEventList.push_back(this); } /** delete the cpu event from the global list. */ @@ -81,9 +81,8 @@ class CpuEventWrapper : public CpuEvent T *object; public: - CpuEventWrapper(T *obj, ThreadContext *_tc, - EventQueue *q = &mainEventQueue, Priority p = Default_Pri) - : CpuEvent(q, _tc, p), object(obj) + CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri) + : CpuEvent(_tc, p), object(obj) { } void process() { (object->*F)(tc); } }; diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 0118dbde1..ea53fb6f5 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -46,12 +46,18 @@ using namespace TheISA; namespace Trace { void -Trace::ExeTracerRecord::dump() +ExeTracerRecord::dumpTicks(ostream &outs) +{ + ccprintf(outs, "%7d: ", when); +} + +void +Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran) { ostream &outs = Trace::output(); if (IsOn(ExecTicks)) - ccprintf(outs, "%7d: ", when); + dumpTicks(outs); outs << thread->getCpuPtr()->name() << " "; @@ -59,46 +65,59 @@ Trace::ExeTracerRecord::dump() outs << (misspeculating ? "-" : "+") << " "; if (IsOn(ExecThread)) - outs << "T" << thread->getThreadNum() << " : "; - + outs << "T" << thread->threadId() << " : "; std::string sym_str; Addr sym_addr; if (debugSymbolTable && IsOn(ExecSymbol) +#if FULL_SYSTEM + && !inUserMode(thread) +#endif && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { if (PC != sym_addr) sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; + outs << "@" << sym_str; } else { - outs << "0x" << hex << PC << " : "; + outs << "0x" << hex << PC; } + if (inst->isMicroop()) { + outs << "." << setw(2) << dec << upc; + } else { + outs << " "; + } + + outs << " : "; + // // Print decoded instruction // outs << setw(26) << left; - outs << staticInst->disassemble(PC, debugSymbolTable); - outs << " : "; + outs << inst->disassemble(PC, debugSymbolTable); - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } + if (ran) { + outs << " : "; - if (IsOn(ExecResult) && data_status != DataInvalid) { - ccprintf(outs, " D=%#018x", data.as_int); - } + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[inst->opClass()] << " : "; + } + + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; - if (IsOn(ExecFetchSeq) && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; - if (IsOn(ExecCPSeq) && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + } // // End of line... @@ -106,6 +125,29 @@ Trace::ExeTracerRecord::dump() outs << endl; } +void +Trace::ExeTracerRecord::dump() +{ + /* + * The behavior this check tries to achieve is that if ExecMacro is on, + * the macroop will be printed. If it's on and microops are also on, it's + * printed before the microops start printing to give context. If the + * microops aren't printed, then it's printed only when the final microop + * finishes. Macroops then behave like regular instructions and don't + * complete/print when they fault. + */ + if (IsOn(ExecMacro) && staticInst->isMicroop() && + ((IsOn(ExecMicro) && + macroStaticInst && staticInst->isFirstMicroop()) || + (!IsOn(ExecMicro) && + macroStaticInst && staticInst->isLastMicroop()))) { + traceInst(macroStaticInst, false); + } + if (IsOn(ExecMicro) || !staticInst->isMicroop()) { + traceInst(staticInst, true); + } +} + /* namespace Trace */ } //////////////////////////////////////////////////////////////////////// diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index 84660432b..e49a2bb59 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -47,12 +47,17 @@ class ExeTracerRecord : public InstRecord { public: ExeTracerRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } + void traceInst(StaticInstPtr inst, bool ran); + void dump(); + virtual void dumpTicks(std::ostream &outs); }; class ExeTracer : public InstTracer @@ -64,7 +69,8 @@ class ExeTracer : public InstTracer InstRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +82,7 @@ class ExeTracer : public InstTracer return NULL; return new ExeTracerRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py new file mode 100644 index 000000000..9faadc68c --- /dev/null +++ b/src/cpu/inorder/InOrderCPU.py @@ -0,0 +1,79 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Korey Sewell + +from m5.params import * +from m5.proxy import * +from m5 import build_env +from BaseCPU import BaseCPU + +class InOrderCPU(BaseCPU): + type = 'InOrderCPU' + activity = Param.Unsigned(0, "Initial count") + + cachePorts = Param.Unsigned(2, "Cache Ports") + stageWidth = Param.Unsigned(1, "Stage width") + + fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from") + dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from") + icache_port = Port("Instruction Port") + dcache_port = Port("Data Port") + _mem_ports = ['icache_port', 'dcache_port'] + + predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')") + localPredictorSize = Param.Unsigned(2048, "Size of local predictor") + localCtrBits = Param.Unsigned(2, "Bits per counter") + localHistoryTableSize = Param.Unsigned(2048, "Size of local history table") + localHistoryBits = Param.Unsigned(11, "Bits for the local history") + globalPredictorSize = Param.Unsigned(8192, "Size of global predictor") + globalCtrBits = Param.Unsigned(2, "Bits per counter") + globalHistoryBits = Param.Unsigned(13, "Bits of history") + choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor") + choiceCtrBits = Param.Unsigned(2, "Bits of choice counters") + + BTBEntries = Param.Unsigned(4096, "Number of BTB entries") + BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits") + + RASSize = Param.Unsigned(16, "RAS size") + + instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") + functionTrace = Param.Bool(False, "Enable function trace") + functionTraceStart = Param.Tick(0, "Cycle to start function trace") + stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU") + + memBlockSize = Param.Unsigned(64, "Memory Block Size") + + multLatency = Param.Unsigned(1, "Latency for Multiply Operations") + multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations") + div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations") + div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations") + div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations") + div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations") + div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations") + div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations") + div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations") + div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations") diff --git a/src/cpu/inorder/InOrderTrace.py b/src/cpu/inorder/InOrderTrace.py new file mode 100644 index 000000000..3453fa675 --- /dev/null +++ b/src/cpu/inorder/InOrderTrace.py @@ -0,0 +1,35 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Korey Sewell + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class InOrderTrace(InstTracer): + type = 'InOrderTrace' + cxx_class = 'Trace::InOrderTrace' diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript new file mode 100644 index 000000000..af237a777 --- /dev/null +++ b/src/cpu/inorder/SConscript @@ -0,0 +1,90 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Korey Sewell + +Import('*') + +if 'InOrderCPU' in env['CPU_MODELS']: + SimObject('InOrderCPU.py') + SimObject('InOrderTrace.py') + + TraceFlag('ResReqCount') + TraceFlag('FreeList') + TraceFlag('InOrderStage') + TraceFlag('InOrderStall') + TraceFlag('InOrderCPU') + TraceFlag('RegDepMap') + TraceFlag('InOrderDynInst') + TraceFlag('Resource') + TraceFlag('InOrderAGEN') + TraceFlag('InOrderFetchSeq') + TraceFlag('InOrderTLB') + TraceFlag('InOrderCachePort') + TraceFlag('InOrderBPred') + TraceFlag('InOrderDecode') + TraceFlag('InOrderExecute') + TraceFlag('InOrderInstBuffer') + TraceFlag('InOrderUseDef') + TraceFlag('InOrderMDU') + TraceFlag('InOrderGraduation') + TraceFlag('RefCount') + + CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', + 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred', + 'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef', + 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource']) + + Source('pipeline_traits.cc') + Source('inorder_dyn_inst.cc') + Source('inorder_cpu_builder.cc') + Source('inorder_trace.cc') + Source('pipeline_stage.cc') + Source('first_stage.cc') + Source('resource.cc') + Source('resources/agen_unit.cc') + Source('resources/execution_unit.cc') + Source('resources/bpred_unit.cc') + Source('resources/branch_predictor.cc') + Source('resources/cache_unit.cc') + Source('resources/use_def.cc') + Source('resources/decode_unit.cc') + Source('resources/inst_buffer.cc') + Source('resources/graduation_unit.cc') + Source('resources/tlb_unit.cc') + Source('resources/fetch_seq_unit.cc') + Source('resources/mult_div_unit.cc') + Source('resource_pool.cc') + Source('reg_dep_map.cc') + Source('../o3/btb.cc') + Source('../o3/tournament_pred.cc') + Source('../o3/2bit_local_pred.cc') + Source('../o3/ras.cc') + Source('thread_context.cc') + Source('cpu.cc') + diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts new file mode 100644 index 000000000..82ebd18ea --- /dev/null +++ b/src/cpu/inorder/SConsopts @@ -0,0 +1,33 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Korey Sewell + +Import('*') + +all_cpu_list.append('InOrderCPU') diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh new file mode 100644 index 000000000..18bb24169 --- /dev/null +++ b/src/cpu/inorder/comm.hh @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_COMM_HH__ +#define __CPU_INORDER_COMM_HH__ + +#include <vector> + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inst_seq.hh" +#include "sim/host.hh" + +/** Struct that defines the information passed from in between stages */ +/** This information mainly goes forward through the pipeline. */ +struct InterStageStruct { + int size; + ThePipeline::DynInstPtr insts[ThePipeline::StageWidth]; + bool squash; + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + InstSeqNum squashedSeqNum; + bool includeSquashInst; + + InterStageStruct() + :size(0), squash(false), + branchMispredict(false), branchTaken(false), + mispredPC(0), nextPC(0), + squashedSeqNum(0), includeSquashInst(false) + { } + +}; + +/** Turn This into a Class */ +/** Struct that defines all backwards communication. */ +struct TimeStruct { + struct stageComm { + bool squash; + bool predIncorrect; + uint64_t branchAddr; + + // @todo: Might want to package this kind of branch stuff into a single + // struct as it is used pretty frequently. + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + + unsigned branchCount; + + // Represents the instruction that has either been retired or + // squashed. Similar to having a single bus that broadcasts the + // retired or squashed sequence number. + InstSeqNum doneSeqNum; + InstSeqNum bdelayDoneSeqNum; + bool squashDelaySlot; + + //Just in case we want to do a commit/squash on a cycle + //(necessary for multiple ROBs?) + bool commitInsts; + InstSeqNum squashSeqNum; + + // Communication specifically to the IQ to tell the IQ that it can + // schedule a non-speculative instruction. + InstSeqNum nonSpecSeqNum; + + bool uncached; + ThePipeline::DynInstPtr uncachedLoad; + + bool interruptPending; + bool clearInterrupt; + }; + + stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads]; + + bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads]; + bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads]; +}; + +#endif //__CPU_INORDER_COMM_HH__ diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc new file mode 100644 index 000000000..70877aae4 --- /dev/null +++ b/src/cpu/inorder/cpu.cc @@ -0,0 +1,1253 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/activity.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "mem/translating_port.hh" +#include "sim/process.hh" +#include "sim/stat_control.hh" +#include <algorithm> + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderCPU::TickEvent::TickEvent(InOrderCPU *c) + : Event(CPU_Tick_Pri), cpu(c) +{ } + + +void +InOrderCPU::TickEvent::process() +{ + cpu->tick(); +} + + +const char * +InOrderCPU::TickEvent::description() +{ + return "InOrderCPU tick event"; +} + +InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, + Fault fault, unsigned _tid, unsigned _vpe) + : Event(CPU_Tick_Pri), cpu(_cpu) +{ + setEvent(e_type, fault, _tid, _vpe); +} + +void +InOrderCPU::CPUEvent::process() +{ + switch (cpuEventType) + { + case ActivateThread: + cpu->activateThread(tid); + break; + + //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate + case SuspendThread: // Suspend & Deallocate are same for now. + //cpu->suspendThread(tid); + //break; + case DeallocateThread: + cpu->deallocateThread(tid); + break; + + case EnableVPEs: + cpu->enableVPEs(vpe); + break; + + case DisableVPEs: + cpu->disableVPEs(tid, vpe); + break; + + case EnableThreads: + cpu->enableThreads(vpe); + break; + + case DisableThreads: + cpu->disableThreads(tid, vpe); + break; + + case Trap: + cpu->trapCPU(fault, tid); + break; + + default: + fatal("Unrecognized Event Type %d", cpuEventType); + } + + cpu->cpuEventRemoveList.push(this); +} + +const char * +InOrderCPU::CPUEvent::description() +{ + return "InOrderCPU event"; +} + +void +InOrderCPU::CPUEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + cpu->ticks(delay)); +} + +void +InOrderCPU::CPUEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} + +InOrderCPU::InOrderCPU(Params *params) + : BaseCPU(params), + cpu_id(params->cpu_id), + coreType("default"), + _status(Idle), + tickEvent(this), + miscRegFile(this), + timeBuffer(2 , 2), + removeInstsThisCycle(false), + activityRec(params->name, NumStages, 10, params->activity), + switchCount(0), + deferRegistration(false/*params->deferRegistration*/), + stageTracing(params->stageTracing), + numThreads(params->numThreads), + numVirtProcs(1) +{ + cpu_params = params; + + resPool = new ResourcePool(this, params); + + // Resize for Multithreading CPUs + thread.resize(numThreads); + + int active_threads = params->workload.size(); + + if (active_threads > MaxThreads) { + panic("Workload Size too large. Increase the 'MaxThreads'" + "in your InOrder implementation or " + "edit your workload size."); + } + + // Bind the fetch & data ports from the resource pool. + fetchPortIdx = resPool->getPortIdx(params->fetchMemPort); + if (fetchPortIdx == 0) { + warn("Unable to find port to fetch instructions from.\n"); + } + + dataPortIdx = resPool->getPortIdx(params->dataMemPort); + if (dataPortIdx == 0) { + warn("Unable to find port for data.\n"); + } + + + for (int i = 0; i < numThreads; ++i) { + if (i < params->workload.size()) { + DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], + i); + + // Start thread's off in "Suspended" status + this->thread[i]->setStatus(ThreadContext::Suspended); + + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = params->workload[0]; + this->thread[i] = new Thread(this, i, dummy_proc, i); + } + + // Setup the TC that will serve as the interface to the threads/CPU. + InOrderThreadContext *tc = new InOrderThreadContext; + tc->cpu = this; + tc->thread = this->thread[i]; + + // Give the thread the TC. + thread[i]->tc = tc; + thread[i]->setFuncExeInst(0); + globalSeqNum[i] = 1; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + // Initialize TimeBuffer Stage Queues + for (int stNum=0; stNum < NumStages - 1; stNum++) { + stageQueue[stNum] = new StageQueue(NumStages, NumStages); + stageQueue[stNum]->id(stNum); + } + + + // Set Up Pipeline Stages + for (int stNum=0; stNum < NumStages; stNum++) { + if (stNum == 0) + pipelineStage[stNum] = new FirstStage(params, stNum); + else + pipelineStage[stNum] = new PipelineStage(params, stNum); + + pipelineStage[stNum]->setCPU(this); + pipelineStage[stNum]->setActiveThreads(&activeThreads); + pipelineStage[stNum]->setTimeBuffer(&timeBuffer); + + // Take Care of 1st/Nth stages + if (stNum > 0) + pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]); + if (stNum < NumStages - 1) + pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]); + } + + // Initialize thread specific variables + for (int tid=0; tid < numThreads; tid++) { + archRegDepMap[tid].setCPU(this); + + nonSpecInstActive[tid] = false; + nonSpecSeqNum[tid] = 0; + + squashSeqNum[tid] = MaxAddr; + lastSquashCycle[tid] = 0; + + intRegFile[tid].clear(); + floatRegFile[tid].clear(); + } + + // Update miscRegFile if necessary + if (numThreads > 1) { + miscRegFile.expandForMultithreading(numThreads, numVirtProcs); + } + + miscRegFile.clear(); + + lastRunningCycle = curTick; + contextSwitch = false; + + // Define dummy instructions and resource requests to be used. + DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0); + dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0); + + // Reset CPU to reset state. +#if FULL_SYSTEM + Fault resetFault = new ResetFault(); + resetFault->invoke(tcBase()); +#else + reset(); +#endif + + // Schedule First Tick Event, CPU will reschedule itself from here on out. + scheduleTickEvent(0); +} + + +void +InOrderCPU::regStats() +{ + /* Register the Resource Pool's stats here.*/ + resPool->regStats(); + + /* Register any of the InOrderCPU's stats here.*/ + timesIdled + .name(name() + ".timesIdled") + .desc("Number of times that the entire CPU went into an idle state and" + " unscheduled itself") + .prereq(timesIdled); + + idleCycles + .name(name() + ".idleCycles") + .desc("Total number of cycles that the CPU has spent unscheduled due " + "to idling") + .prereq(idleCycles); + + threadCycles + .init(numThreads) + .name(name() + ".threadCycles") + .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)"); + + smtCycles + .name(name() + ".smtCycles") + .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)"); + + committedInsts + .init(numThreads) + .name(name() + ".committedInsts") + .desc("Number of Instructions Simulated (Per-Thread)"); + + smtCommittedInsts + .init(numThreads) + .name(name() + ".smtCommittedInsts") + .desc("Number of SMT Instructions Simulated (Per-Thread)"); + + totalCommittedInsts + .name(name() + ".committedInsts_total") + .desc("Number of Instructions Simulated (Total)"); + + cpi + .name(name() + ".cpi") + .desc("CPI: Cycles Per Instruction (Per-Thread)") + .precision(6); + cpi = threadCycles / committedInsts; + + smtCpi + .name(name() + ".smt_cpi") + .desc("CPI: Total SMT-CPI") + .precision(6); + smtCpi = smtCycles / smtCommittedInsts; + + totalCpi + .name(name() + ".cpi_total") + .desc("CPI: Total CPI of All Threads") + .precision(6); + totalCpi = numCycles / totalCommittedInsts; + + ipc + .name(name() + ".ipc") + .desc("IPC: Instructions Per Cycle (Per-Thread)") + .precision(6); + ipc = committedInsts / threadCycles; + + smtIpc + .name(name() + ".smt_ipc") + .desc("IPC: Total SMT-IPC") + .precision(6); + smtIpc = smtCommittedInsts / smtCycles; + + totalIpc + .name(name() + ".ipc_total") + .desc("IPC: Total IPC of All Threads") + .precision(6); + totalIpc = totalCommittedInsts / numCycles; + + BaseCPU::regStats(); +} + + +void +InOrderCPU::tick() +{ + DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n"); + + ++numCycles; + + //Tick each of the stages + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->tick(); + } + + // Now advance the time buffers one tick + timeBuffer.advance(); + for (int sqNum=0; sqNum < NumStages - 1; sqNum++) { + stageQueue[sqNum]->advance(); + } + activityRec.advance(); + + // Any squashed requests, events, or insts then remove them now + cleanUpRemovedReqs(); + cleanUpRemovedEvents(); + cleanUpRemovedInsts(); + + // Re-schedule CPU for this cycle + if (!tickEvent.scheduled()) { + if (_status == SwitchedOut) { + // increment stat + lastRunningCycle = curTick; + } else if (!activityRec.active()) { + DPRINTF(InOrderCPU, "sleeping CPU.\n"); + lastRunningCycle = curTick; + timesIdled++; + } else { + //Tick next_tick = curTick + cycles(1); + //tickEvent.schedule(next_tick); + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1)); + DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick); + } + } + + tickThreadStats(); + updateThreadPriority(); +} + + +void +InOrderCPU::init() +{ + if (!deferRegistration) { + registerThreadContexts(); + } + + // Set inSyscall so that the CPU doesn't squash when initially + // setting up registers. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = true; + + for (int tid=0; tid < number_of_threads; tid++) { + + ThreadContext *src_tc = thread[tid]->getTC(); + + // Threads start in the Suspended State + if (src_tc->status() != ThreadContext::Suspended) { + continue; + } + + } + + // Clear inSyscall. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = false; + + // Call Initializiation Routine for Resource Pool + resPool->init(); +} + +void +InOrderCPU::readFunctional(Addr addr, uint32_t &buffer) +{ + tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t)); + buffer = gtoh(buffer); +} + +void +InOrderCPU::reset() +{ + miscRegFile.reset(coreType, numThreads, numVirtProcs, dynamic_cast<BaseCPU*>(this)); +} + +Port* +InOrderCPU::getPort(const std::string &if_name, int idx) +{ + return resPool->getPort(if_name, idx); +} + +void +InOrderCPU::trap(Fault fault, unsigned tid, int delay) +{ + scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::trapCPU(Fault fault, unsigned tid) +{ + fault->invoke(tcBase(tid)); +} + +void +InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault, + unsigned tid, unsigned vpe, unsigned delay) +{ + CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe); + + if (delay >= 0) { + DPRINTF(InOrderCPU, "Scheduling CPU Event Type #%i for cycle %i.\n", + c_event, curTick + delay); + mainEventQueue.schedule(cpu_event,curTick + delay); + } else { + cpu_event->process(); + cpuEventRemoveList.push(cpu_event); + } + + // Broadcast event to the Resource Pool + DynInstPtr dummy_inst = new InOrderDynInst(this, NULL, getNextEventNum(), tid); + resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid); +} + +inline bool +InOrderCPU::isThreadActive(unsigned tid) +{ + list<unsigned>::iterator isActive = std::find( + activeThreads.begin(), activeThreads.end(), tid); + + return (isActive != activeThreads.end()); +} + + +void +InOrderCPU::activateThread(unsigned tid) +{ + if (!isThreadActive(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to active threads list in CPU.\n", + tid); + activeThreads.push_back(tid); + + wakeCPU(); + } +} + +void +InOrderCPU::deactivateThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid); + + if (isThreadActive(tid)) { + DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n", + tid); + list<unsigned>::iterator thread_it = std::find(activeThreads.begin(), + activeThreads.end(), tid); + + removePipelineStalls(*thread_it); + + //@TODO: change stage status' to Idle? + + activeThreads.erase(thread_it); + } +} + +void +InOrderCPU::removePipelineStalls(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n", + tid); + + for (int stNum = 0; stNum < NumStages ; stNum++) { + pipelineStage[stNum]->removeStalls(tid); + } + +} +bool +InOrderCPU::isThreadInCPU(unsigned tid) +{ + list<unsigned>::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + + return (isCurrent != currentThreads.end()); +} + +void +InOrderCPU::addToCurrentThreads(unsigned tid) +{ + if (!isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + currentThreads.push_back(tid); + } +} + +void +InOrderCPU::removeFromCurrentThreads(unsigned tid) +{ + if (isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + list<unsigned>::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + currentThreads.erase(isCurrent); + } +} + +bool +InOrderCPU::isThreadSuspended(unsigned tid) +{ + list<unsigned>::iterator isSuspended = std::find( + suspendedThreads.begin(), suspendedThreads.end(), tid); + + return (isSuspended!= suspendedThreads.end()); +} + +void +InOrderCPU::enableVirtProcElement(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Enabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableVPEs(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution " + "virtual processors %i", vpe); + + list<unsigned>::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + thread_it++; + } +} + +void +InOrderCPU::disableVirtProcElement(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Disabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::disableVPEs(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of " + "virtual processors %i", vpe); + + unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid)); + + list<unsigned>::iterator thread_it = activeThreads.begin(); + + std::vector<list<unsigned>::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (base_vpe != vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::enableMultiThreading(unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on " + "virtual processor %i", vpe); + + scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableThreads(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on " + "virtual processor %i", vpe); + + list<unsigned>::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + } + thread_it++; + } +} +void +InOrderCPU::disableMultiThreading(unsigned tid, unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on " + "virtual processor %i", tid, vpe); + + scheduleCpuEvent(DisableThreads, NoFault, tid, vpe); +} + +void +InOrderCPU::disableThreads(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on " + "virtual processor %i", tid, vpe); + + list<unsigned>::iterator thread_it = activeThreads.begin(); + + std::vector<list<unsigned>::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::updateThreadPriority() +{ + if (activeThreads.size() > 1) + { + //DEFAULT TO ROUND ROBIN SCHEME + //e.g. Move highest priority to end of thread list + list<unsigned>::iterator list_begin = activeThreads.begin(); + list<unsigned>::iterator list_end = activeThreads.end(); + + unsigned high_thread = *list_begin; + + activeThreads.erase(list_begin); + + activeThreads.push_back(high_thread); + } +} + +inline void +InOrderCPU::tickThreadStats() +{ + /** Keep track of cycles that each thread is active */ + list<unsigned>::iterator thread_it = activeThreads.begin(); + while (thread_it != activeThreads.end()) { + threadCycles[*thread_it]++; + thread_it++; + } + + // Keep track of cycles where SMT is active + if (activeThreads.size() > 1) { + smtCycles++; + } +} + +void +InOrderCPU::activateContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid); + + scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay); + + // Be sure to signal that there's some activity so the CPU doesn't + // deschedule itself. + activityRec.activity(); + + _status = Running; +} + + +void +InOrderCPU::suspendContext(unsigned tid, int delay) +{ + scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay); + //_status = Idle; +} + +void +InOrderCPU::suspendThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid); + deactivateThread(tid); +} + +void +InOrderCPU::deallocateContext(unsigned tid, int delay) +{ + scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::deallocateThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid); + + removeFromCurrentThreads(tid); + + deactivateThread(tid); + + squashThreadInPipeline(tid); +} + +void +InOrderCPU::squashThreadInPipeline(unsigned tid) +{ + //Squash all instructions in each stage + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->squash(0 /*seq_num*/, tid); + } +} + +void +InOrderCPU::haltContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid); + + // Halt is same thing as deallocate for now + // @TODO: Differentiate between halt & deallocate in the CPU + // model + deallocateContext(tid, delay); +} + +void +InOrderCPU::insertThread(unsigned tid) +{ + panic("Unimplemented Function\n."); +} + +void +InOrderCPU::removeThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid); + + /** Broadcast to CPU resources*/ +} + +void +InOrderCPU::activateWhenReady(int tid) +{ + panic("Unimplemented Function\n."); +} + + +uint64_t +InOrderCPU::readPC(unsigned tid) +{ + return PC[tid]; +} + + +void +InOrderCPU::setPC(Addr new_PC, unsigned tid) +{ + PC[tid] = new_PC; +} + + +uint64_t +InOrderCPU::readNextPC(unsigned tid) +{ + return nextPC[tid]; +} + + +void +InOrderCPU::setNextPC(uint64_t new_NPC, unsigned tid) +{ + nextPC[tid] = new_NPC; +} + + +uint64_t +InOrderCPU::readNextNPC(unsigned tid) +{ + return nextNPC[tid]; +} + + +void +InOrderCPU::setNextNPC(uint64_t new_NNPC, unsigned tid) +{ + nextNPC[tid] = new_NNPC; +} + +uint64_t +InOrderCPU::readIntReg(int reg_idx, unsigned tid) +{ + return intRegFile[tid].readReg(reg_idx); +} + +FloatReg +InOrderCPU::readFloatReg(int reg_idx, unsigned tid, int width) +{ + + return floatRegFile[tid].readReg(reg_idx, width); +} + +FloatRegBits +InOrderCPU::readFloatRegBits(int reg_idx, unsigned tid, int width) +{; + return floatRegFile[tid].readRegBits(reg_idx, width); +} + +void +InOrderCPU::setIntReg(int reg_idx, uint64_t val, unsigned tid) +{ + intRegFile[tid].setReg(reg_idx, val); +} + + +void +InOrderCPU::setFloatReg(int reg_idx, FloatReg val, unsigned tid, int width) +{ + floatRegFile[tid].setReg(reg_idx, val, width); +} + + +void +InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, int width) +{ + floatRegFile[tid].setRegBits(reg_idx, val, width); +} + +uint64_t +InOrderCPU::readRegOtherThread(unsigned reg_idx, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return readMiscReg(reg_idx, tid); // Misc. Register File + } +} +void +InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +MiscReg +InOrderCPU::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return miscRegFile.readRegNoEffect(misc_reg, tid); +} + +MiscReg +InOrderCPU::readMiscReg(int misc_reg, unsigned tid) +{ + return miscRegFile.readReg(misc_reg, tcBase(tid), tid); +} + +void +InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setRegNoEffect(misc_reg, val, tid); +} + +void +InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setReg(misc_reg, val, tcBase(tid), tid); +} + + +InOrderCPU::ListIt +InOrderCPU::addInst(DynInstPtr &inst) +{ + int tid = inst->readTid(); + + instList[tid].push_back(inst); + + return --(instList[tid].end()); +} + +void +InOrderCPU::instDone(DynInstPtr inst, unsigned tid) +{ + // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used + // when restoring a thread to the CPU after a fork or after an exception + // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not + setPC(inst->readPC(), tid); + setNextPC(inst->readNextPC(), tid); + setNextNPC(inst->readNextNPC(), tid); + + // Finalize Trace Data For Instruction + if (inst->traceData) { + //inst->traceData->setCycle(curTick); + inst->traceData->setFetchSeq(inst->seqNum); + //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst); + inst->traceData->dump(); + delete inst->traceData; + inst->traceData = NULL; + } + + // Set Last Graduated Instruction In Thread State + //thread[tid]->lastGradInst = inst; + + // Increment thread-state's instruction count + thread[tid]->numInst++; + + // Increment thread-state's instruction stats + thread[tid]->numInsts++; + + // Count committed insts per thread stats + committedInsts[tid]++; + + // Count total insts committed stat + totalCommittedInsts++; + + // Count SMT-committed insts per thread stat + if (numActiveThreads() > 1) { + smtCommittedInsts[tid]++; + } + + // Check for instruction-count-based events. + comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); + + // Broadcast to other resources an instruction + // has been completed + resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid); + + // Finally, remove instruction from CPU + removeInst(inst); +} + +void +InOrderCPU::addToRemoveList(DynInstPtr &inst) +{ + removeInstsThisCycle = true; + + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInst(DynInstPtr &inst) +{ + DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x " + "[sn:%lli]\n", + inst->threadNumber, inst->readPC(), inst->seqNum); + + removeInstsThisCycle = true; + + // Remove the instruction. + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num, + unsigned tid) +{ + //assert(!instList[tid].empty()); + + removeInstsThisCycle = true; + + ListIt inst_iter = instList[tid].end(); + + inst_iter--; + + DPRINTF(InOrderCPU, "Deleting instructions from CPU instruction " + "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", + tid, seq_num, (*inst_iter)->seqNum); + + while ((*inst_iter)->seqNum > seq_num) { + + bool break_loop = (inst_iter == instList[tid].begin()); + + squashInstIt(inst_iter, tid); + + inst_iter--; + + if (break_loop) + break; + } +} + + +inline void +InOrderCPU::squashInstIt(const ListIt &instIt, const unsigned &tid) +{ + if ((*instIt)->threadNumber == tid) { + DPRINTF(InOrderCPU, "Squashing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*instIt)->threadNumber, + (*instIt)->seqNum, + (*instIt)->readPC()); + + (*instIt)->setSquashed(); + + removeList.push(instIt); + } +} + + +void +InOrderCPU::cleanUpRemovedInsts() +{ + while (!removeList.empty()) { + DPRINTF(InOrderCPU, "Removing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*removeList.front())->threadNumber, + (*removeList.front())->seqNum, + (*removeList.front())->readPC()); + + DynInstPtr inst = *removeList.front(); + int tid = inst->threadNumber; + + // Make Sure Resource Schedule Is Emptied Out + ThePipeline::ResSchedule *inst_sched = &inst->resSched; + while (!inst_sched->empty()) { + ThePipeline::ScheduleEntry* sch_entry = inst_sched->top(); + inst_sched->pop(); + delete sch_entry; + } + + // Remove From Register Dependency Map, If Necessary + archRegDepMap[(*removeList.front())->threadNumber]. + remove((*removeList.front())); + + + // Clear if Non-Speculative + if (inst->staticInst && + inst->seqNum == nonSpecSeqNum[tid] && + nonSpecInstActive[tid] == true) { + nonSpecInstActive[tid] = false; + } + + instList[tid].erase(removeList.front()); + + removeList.pop(); + + DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n", + inst->seqNum, + 0/*inst->curCount()*/); + + } + + removeInstsThisCycle = false; +} + +void +InOrderCPU::cleanUpRemovedReqs() +{ + while (!reqRemoveList.empty()) { + ResourceRequest *res_req = reqRemoveList.front(); + + DPRINTF(RefCount, "[tid:%i]: Removing Request, " + "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n", + res_req->inst->threadNumber, + res_req->inst->seqNum, + res_req->getSlot(), + res_req->getStageNum(), + res_req->res->name(), + 0/*res_req->inst->curCount()*/); + + reqRemoveList.pop(); + + delete res_req; + + DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n", + res_req->inst->seqNum, + 0/*res_req->inst->curCount()*/); + } +} + +void +InOrderCPU::cleanUpRemovedEvents() +{ + while (!cpuEventRemoveList.empty()) { + Event *cpu_event = cpuEventRemoveList.front(); + cpuEventRemoveList.pop(); + delete cpu_event; + } +} + + +void +InOrderCPU::dumpInsts() +{ + int num = 0; + + ListIt inst_list_it = instList[0].begin(); + + cprintf("Dumping Instruction List\n"); + + while (inst_list_it != instList[0].end()) { + cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, + (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } +} + +void +InOrderCPU::wakeCPU() +{ + if (/*activityRec.active() || */tickEvent.scheduled()) { + DPRINTF(Activity, "CPU already running.\n"); + return; + } + + DPRINTF(Activity, "Waking up CPU\n"); + + //@todo: figure out how to count idleCycles correctly + //idleCycles += (curTick - 1) - lastRunningCycle; + + mainEventQueue.schedule(&tickEvent, curTick); +} + +void +InOrderCPU::syscall(int64_t callnum, int tid) +{ + DPRINTF(InOrderCPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); + + // Clear Non-Speculative Block Variable + nonSpecInstActive[tid] = false; +} + +Fault +InOrderCPU::read(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} + +Fault +InOrderCPU::write(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh new file mode 100644 index 000000000..adcd28019 --- /dev/null +++ b/src/cpu/inorder/cpu.hh @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CPU_HH__ +#define __CPU_INORDER_CPU_HH__ + +#include <iostream> +#include <list> +#include <queue> +#include <set> +#include <vector> + +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/activity.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/o3/dep_graph.hh" +#include "cpu/o3/rename_map.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" +#include "sim/process.hh" + +class ThreadContext; +class MemInterface; +class MemObject; +class Process; +class ResourcePool; + +class InOrderCPU : public BaseCPU +{ + + protected: + typedef ThePipeline::Params Params; + typedef InOrderThreadState Thread; + + //ISA TypeDefs + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + + //DynInstPtr TypeDefs + typedef ThePipeline::DynInstPtr DynInstPtr; + typedef std::list<DynInstPtr>::iterator ListIt; + + //TimeBuffer TypeDefs + typedef TimeBuffer<InterStageStruct> StageQueue; + + friend class Resource; + + public: + /** Constructs a CPU with the given parameters. */ + InOrderCPU(Params *params); + + /** CPU ID */ + int cpu_id; + + /** Type of core that this is */ + std::string coreType; + + int readCpuId() { return cpu_id; } + + void setCpuId(int val) { cpu_id = val; } + + Params *cpu_params; + + TheISA::ITB * itb; + TheISA::DTB * dtb; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + /** Define TickEvent for the CPU */ + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(InOrderCPU *c); + + /** Processes a tick event, calling tick() on the CPU. */ + void process(); + + /** Returns the description of the tick event. */ + const char *description(); + }; + + /** The tick event used for scheduling CPU ticks. */ + TickEvent tickEvent; + + /** Schedule tick event, regardless of its current state. */ + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay))); + else if (!tickEvent.scheduled()) + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay))); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + // List of Events That can be scheduled from + // within the CPU. + // NOTE(1): The Resource Pool also uses this event list + // to schedule events broadcast to all resources interfaces + // NOTE(2): CPU Events usually need to schedule a corresponding resource + // pool event. + enum CPUEventType { + ActivateThread, + DeallocateThread, + SuspendThread, + DisableThreads, + EnableThreads, + DisableVPEs, + EnableVPEs, + Trap, + InstGraduated, + SquashAll, + UpdatePCs, + NumCPUEvents + }; + + /** Define CPU Event */ + class CPUEvent : public Event + { + protected: + InOrderCPU *cpu; + + public: + CPUEventType cpuEventType; + unsigned tid; + unsigned vpe; + Fault fault; + + public: + /** Constructs a CPU event. */ + CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault, + unsigned _tid, unsigned _vpe); + + /** Set Type of Event To Be Scheduled */ + void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe) + { + fault = _fault; + cpuEventType = e_type; + tid = _tid; + vpe = _vpe; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + /** Schedule a CPU Event */ + void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid, + unsigned vpe, unsigned delay = 0); + + public: + /** Interface between the CPU and CPU resources. */ + ResourcePool *resPool; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** Used by resources to signify a denied access to a resource. */ + ResourceRequest *dummyReq; + + /** Identifies the resource id that identifies a fetch + * access unit. + */ + unsigned fetchPortIdx; + + /** Identifies the resource id that identifies a data + * access unit. + */ + unsigned dataPortIdx; + + /** The Pipeline Stages for the CPU */ + PipelineStage *pipelineStage[ThePipeline::NumStages]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** The Register File for the CPU */ + TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];; + TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];; + TheISA::MiscRegFile miscRegFile; + + /** Dependency Tracker for Integer & Floating Point Regs */ + RegDepMap archRegDepMap[ThePipeline::MaxThreads]; + + /** Global communication structure */ + TimeBuffer<TimeStruct> timeBuffer; + + /** Communication structure that sits in between pipeline stages */ + StageQueue *stageQueue[ThePipeline::NumStages-1]; + + public: + + /** Registers statistics. */ + void regStats(); + + /** Ticks CPU, calling tick() on each stage, and checking the overall + * activity to see if the CPU should deschedule itself. + */ + void tick(); + + /** Initialize the CPU */ + void init(); + + /** Reset State in the CPU */ + void reset(); + + /** Get a Memory Port */ + Port* getPort(const std::string &if_name, int idx = 0); + + /** trap() - sets up a trap event on the cpuTraps to handle given fault. + * trapCPU() - Traps to handle given fault + */ + void trap(Fault fault, unsigned tid, int delay = 0); + void trapCPU(Fault fault, unsigned tid); + + /** Setup CPU to insert a thread's context */ + void insertThread(unsigned tid); + + /** Remove all of a thread's context from CPU */ + void removeThread(unsigned tid); + + /** Add Thread to Active Threads List. */ + void activateContext(unsigned tid, int delay = 0); + void activateThread(unsigned tid); + + /** Remove Thread from Active Threads List */ + void suspendContext(unsigned tid, int delay = 0); + void suspendThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(unsigned tid, int delay = 0); + void deallocateThread(unsigned tid); + void deactivateThread(unsigned tid); + + int + contextId() + { + hack_once("return a bogus context id"); + return 0; + } + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(unsigned tid, int delay = 0); + + void removePipelineStalls(unsigned tid); + + void squashThreadInPipeline(unsigned tid); + + /// Notify the CPU to enable a virtual processor element. + virtual void enableVirtProcElement(unsigned vpe); + void enableVPEs(unsigned vpe); + + /// Notify the CPU to disable a virtual processor element. + virtual void disableVirtProcElement(unsigned tid, unsigned vpe); + void disableVPEs(unsigned tid, unsigned vpe); + + /// Notify the CPU that multithreading is enabled. + virtual void enableMultiThreading(unsigned vpe); + void enableThreads(unsigned vpe); + + /// Notify the CPU that multithreading is disabled. + virtual void disableMultiThreading(unsigned tid, unsigned vpe); + void disableThreads(unsigned tid, unsigned vpe); + + // Sets a thread-rescheduling condition. + void setThreadRescheduleCondition(uint32_t tid) + { + //@TODO: IMPLEMENT ME + } + + /** Activate a Thread When CPU Resources are Available. */ + void activateWhenReady(int tid); + + /** Add or Remove a Thread Context in the CPU. */ + void doContextSwitch(); + + /** Update The Order In Which We Process Threads. */ + void updateThreadPriority(); + + /** Switches a Pipeline Stage to Active. (Unused currently) */ + void switchToActive(int stage_idx) + { /*pipelineStage[stage_idx]->switchToActive();*/ } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq(unsigned tid) + { return globalSeqNum[tid]++; } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum nextInstSeqNum(unsigned tid) + { return globalSeqNum[tid]; } + + /** Increment Instruction Sequence Number */ + void incrInstSeqNum(unsigned tid) + { globalSeqNum[tid]++; } + + /** Set Instruction Sequence Number */ + void setInstSeqNum(unsigned tid, InstSeqNum seq_num) + { + globalSeqNum[tid] = seq_num; + } + + /** Get & Update Next Event Number */ + InstSeqNum getNextEventNum() + { + return cpuEventNum++; + } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } + + /** Register file accessors */ + uint64_t readIntReg(int reg_idx, unsigned tid); + + FloatReg readFloatReg(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + FloatRegBits readFloatRegBits(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + void setIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setFloatReg(int reg_idx, FloatReg val, unsigned tid, + int width = TheISA::SingleWidth); + + void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, + int width = TheISA::SingleWidth); + + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg, unsigned tid = 0); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0); + + /** Reads a int/fp/misc reg. from another thread depending on ISA-defined + * target thread + */ + uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1); + + /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined + * target thread + */ + void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid); + + /** Reads the commit PC of a specific thread. */ + uint64_t readPC(unsigned tid); + + /** Sets the commit PC of a specific thread. */ + void setPC(Addr new_PC, unsigned tid); + + /** Reads the next PC of a specific thread. */ + uint64_t readNextPC(unsigned tid); + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid); + + /** Reads the next NPC of a specific thread. */ + uint64_t readNextNPC(unsigned tid); + + /** Sets the next NPC of a specific thread. */ + void setNextNPC(uint64_t val, unsigned tid); + + /** Function to add instruction onto the head of the list of the + * instructions. Used when new instructions are fetched. + */ + ListIt addInst(DynInstPtr &inst); + + /** Function to tell the CPU that an instruction has completed. */ + void instDone(DynInstPtr inst, unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from CPU */ + void removeInst(DynInstPtr &inst); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + /** Cleans up all instructions on the instruction remove list. */ + void cleanUpRemovedInsts(); + + /** Cleans up all instructions on the request remove list. */ + void cleanUpRemovedReqs(); + + /** Cleans up all instructions on the CPU event remove list. */ + void cleanUpRemovedEvents(); + + /** Debug function to print all instructions on the list. */ + void dumpInsts(); + + /** Forwards an instruction read to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault read(DynInstPtr inst); + + /** Forwards an instruction write. to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault write(DynInstPtr inst); + + /** Executes a syscall.*/ + void syscall(int64_t callnum, int tid); + + public: + /** Per-Thread List of all the instructions in flight. */ + std::list<DynInstPtr> instList[ThePipeline::MaxThreads]; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + + /** List of all the resource requests that will be removed at the end of this + * cycle. + */ + std::queue<ResourceRequest*> reqRemoveList; + + /** List of all the cpu event requests that will be removed at the end of + * the current cycle. + */ + std::queue<Event*> cpuEventRemoveList; + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; + + /** True if there is non-speculative Inst Active In Pipeline. Lets any + * execution unit know, NOT to execute while the instruction is active. + */ + bool nonSpecInstActive[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of current non-speculative instruction. */ + InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of last instruction squashed in pipeline */ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Last Cycle that the CPU squashed instruction end. */ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + std::list<unsigned> fetchPriorityList; + + protected: + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Current Threads List */ + std::list<unsigned> currentThreads; + + /** Suspended Threads List */ + std::list<unsigned> suspendedThreads; + + /** Thread Status Functions (Unused Currently) */ + bool isThreadInCPU(unsigned tid); + bool isThreadActive(unsigned tid); + bool isThreadSuspended(unsigned tid); + void addToCurrentThreads(unsigned tid); + void removeFromCurrentThreads(unsigned tid); + + private: + /** The activity recorder; used to tell if the CPU has any + * activity remaining or if it can go to idle and deschedule + * itself. + */ + ActivityRecorder activityRec; + + public: + void readFunctional(Addr addr, uint32_t &buffer); + + /** Number of Active Threads in the CPU */ + int numActiveThreads() { return activeThreads.size(); } + + /** Records that there was time buffer activity this cycle. */ + void activityThisCycle() { activityRec.activity(); } + + /** Changes a stage's status to active within the activity recorder. */ + void activateStage(const int idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const int idx) + { activityRec.deactivateStage(idx); } + + /** Wakes the CPU, rescheduling the CPU if it's not already active. */ + void wakeCPU(); + + /** Gets a free thread id. Use if thread ids change across system. */ + int getFreeTid(); + + // LL/SC debug functionality + unsigned stCondFails; + unsigned readStCondFailures() { return stCondFails; } + unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; } + + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid = 0) + { + return thread[tid]->getTC(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum[ThePipeline::MaxThreads]; + + /** The global event number counter. */ + InstSeqNum cpuEventNum; + + /** Counter of how many stages have completed switching out. */ + int switchCount; + + /** Pointers to all of the threads in the CPU. */ + std::vector<Thread *> thread; + + /** Pointer to the icache interface. */ + MemInterface *icacheInterface; + + /** Pointer to the dcache interface. */ + MemInterface *dcacheInterface; + + /** Whether or not the CPU should defer its registration. */ + bool deferRegistration; + + /** Per-Stage Instruction Tracing */ + bool stageTracing; + + /** Is there a context switch pending? */ + bool contextSwitch; + + /** Threads Scheduled to Enter CPU */ + std::list<int> cpuWaitList; + + /** The cycle that the CPU was last running, used for statistics. */ + Tick lastRunningCycle; + + /** Number of Threads the CPU can process */ + unsigned numThreads; + + /** Number of Virtual Processors the CPU can process */ + unsigned numVirtProcs; + + /** Update Thread , used for statistic purposes*/ + inline void tickThreadStats(); + + /** Per-Thread Tick */ + Stats::Vector threadCycles; + + /** Tick for SMT */ + Stats::Scalar smtCycles; + + /** Stat for total number of times the CPU is descheduled. */ + Stats::Scalar timesIdled; + + /** Stat for total number of cycles the CPU spends descheduled. */ + Stats::Scalar idleCycles; + + /** Stat for the number of committed instructions per thread. */ + Stats::Vector committedInsts; + + /** Stat for the number of committed instructions per thread. */ + Stats::Vector smtCommittedInsts; + + /** Stat for the total number of committed instructions. */ + Stats::Scalar totalCommittedInsts; + + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + + /** Stat for the SMT-CPI per thread. */ + Stats::Formula smtCpi; + + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + + /** Stat for the total IPC. */ + Stats::Formula smtIpc; + + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc new file mode 100644 index 000000000..5e389b256 --- /dev/null +++ b/src/cpu/inorder/first_stage.cc @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace ThePipeline; + +FirstStage::FirstStage(Params *params, unsigned stage_num) + : PipelineStage(params, stage_num), numFetchingThreads(1), + fetchPolicy(FirstStage::RoundRobin) +{ + for(int tid=0; tid < this->numThreads; tid++) { + stageStatus[tid] = Running; + } +} + +void +FirstStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + fetchPriorityList = &cpu->fetchPriorityList; + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); +} + + +void +FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + //stageStatus[tid] = Squashing; + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n"); + while (!insts[tid].empty()) { + if (insts[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= " + "squashing seqNum %i.\n", + tid, + insts[tid].front()->seqNum, + squash_seq_num); + + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + insts[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, insts[tid].front()->seqNum, insts[tid].front()->PC); + insts[tid].pop(); + } + + // Now that squash has propagated to the first stage, + // Alert CPU to remove instructions from the CPU instruction list. + // @todo: Move this to the CPU object. + cpu->removeInstsUntil(squash_seq_num, tid); +} + +void +FirstStage::processStage(bool &status_change) +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + status_change = checkSignalsAndUpdate(tid) || status_change; + } + + for (int threadFetched = 0; threadFetched < numFetchingThreads; + threadFetched++) { + int tid = getFetchingThread(fetchPolicy); + + if (tid >= 0) { + DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid); + processThread(status_change, tid); + } else { + DPRINTF(InOrderStage, "No more threads to fetch from.\n"); + } + } +} + +//@TODO: Note in documentation, that when you make a pipeline stage change, then +//make sure you change the first stage too +void +FirstStage::processInsts(unsigned tid) +{ + bool all_reqs_completed = true; + + for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) { + DynInstPtr inst; + bool new_inst = false; + + if (!insts[tid].empty()) { + inst = insts[tid].front(); + } else { + // Get new instruction. + new_inst = true; + + inst = new InOrderDynInst(cpu, + cpu->thread[tid], + cpu->nextInstSeqNum(tid), + tid); + +#if TRACING_ON + inst->traceData = + tracer->getInstRecord(ThePipeline::NumStages, + cpu->stageTracing, + cpu->thread[tid]->getTC()); + +#endif // TRACING_ON + + DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Add instruction to the CPU's list of instructions. + inst->setInstListIt(cpu->addInst(inst)); + + DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Create Front-End Resource Schedule For Instruction + ThePipeline::createFrontEndSchedule(inst); + } + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + all_reqs_completed = processInstSchedule(inst); + + if (!all_reqs_completed) { + if (new_inst) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all " + "requests for this stage. Keep in stage inst. " + "list.\n", tid, inst->seqNum); + insts[tid].push(inst); + } + break; + } else if (!insts[tid].empty()){ + insts[tid].pop(); + } + + sendInstToNextStage(inst); + //++stageProcessedInsts; + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +int +FirstStage::getFetchingThread(FetchPriority &fetch_priority) +{ + if (numThreads > 1) { + switch (fetch_priority) { + + case SingleThread: + return 0; + + case RoundRobin: + return roundRobin(); + + default: + return -1; + } + } else { + int tid = *((*activeThreads).begin()); + + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + return tid; + } else { + return -1; + } + } + +} + +int +FirstStage::roundRobin() +{ + list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin(); + list<unsigned>::iterator end = (*fetchPriorityList).end(); + + int high_pri; + + while (pri_iter != end) { + high_pri = *pri_iter; + + assert(high_pri <= numThreads); + + if (stageStatus[high_pri] == Running || + stageStatus[high_pri] == Idle) { + + (*fetchPriorityList).erase(pri_iter); + (*fetchPriorityList).push_back(high_pri); + + return high_pri; + } + + pri_iter++; + } + + return -1; +} diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh new file mode 100644 index 000000000..55914c85c --- /dev/null +++ b/src/cpu/inorder/first_stage.hh @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FIRST_STAGE_HH__ +#define __CPU_INORDER_FIRST_STAGE_HH__ + +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "cpu/inorder/params.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" + +class InOrderCPU; + +class FirstStage : public PipelineStage { + public: + FirstStage(ThePipeline::Params *params, unsigned stage_num); + + /** Set Pointer to CPU */ + void setCPU(InOrderCPU *cpu_ptr); + + /** Evaluate Stage Info. & Execute Stage */ + void processStage(bool &status_change); + + /** Process All Instructions Available */ + void processInsts(unsigned tid); + + /** Squash Instructions Above a Seq. Num */ + void squash(InstSeqNum squash_seq_num, unsigned tid); + + /** There are no insts. coming from previous stages, so there is + * no need to sort insts here + */ + void sortInsts() {} + + /** There are no skidBuffers for the first stage. So + * just use an empty function. + */ + void skidInsert(unsigned tid) { } + + /** The number of fetching threads in the CPU */ + int numFetchingThreads; + + //@TODO: Add fetch priority information to a resource class... + /** Fetching Policy, Add new policies here.*/ + enum FetchPriority { + SingleThread, + RoundRobin + }; + + /** Fetch policy. */ + FetchPriority fetchPolicy; + + /** List that has the threads organized by priority. */ + std::list<unsigned> *fetchPriorityList; + + /** Return the next fetching thread */ + int getFetchingThread(FetchPriority &fetch_priority); + + /** Return next thred given Round Robin Policy for Thread Fetching */ + int roundRobin(); +}; + +#endif // __CPU_INORDER_FIRST_STAGE_HH__ diff --git a/src/cpu/inorder/inorder_cpu_builder.cc b/src/cpu/inorder/inorder_cpu_builder.cc new file mode 100644 index 000000000..0088a3bd9 --- /dev/null +++ b/src/cpu/inorder/inorder_cpu_builder.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <string> + +#include "cpu/base.hh" +#include "cpu/inst_seq.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "params/InOrderCPU.hh" + +InOrderCPU * +InOrderCPUParams::create() +{ + int actual_num_threads = + (numThreads >= workload.size()) ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + + numThreads = actual_num_threads; + + instShiftAmt = 2; + + return new InOrderCPU(this); +} + + + diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc new file mode 100644 index 000000000..ceb3cbe51 --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <iostream> +#include <set> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" +#include "base/trace.hh" + +#include "arch/faults.hh" +#include "cpu/exetrace.hh" +#include "mem/request.hh" + +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC, + Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu) + : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + + PC = inst_PC; + nextPC = PC + sizeof(MachInst); + nextNPC = nextPC + sizeof(MachInst); + predPC = pred_PC; + + initVars(); +} + +InOrderDynInst::InOrderDynInst(InOrderCPU *cpu, + InOrderThreadState *state, + InstSeqNum seq_num, + unsigned tid) + : traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + thread = state; + threadNumber = tid; + initVars(); +} + +InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst) + : seqNum(0), staticInst(_staticInst), traceData(NULL) +{ + initVars(); +} + +InOrderDynInst::InOrderDynInst() + : seqNum(0), traceData(NULL), cpu(cpu) +{ + initVars(); +} + +int InOrderDynInst::instcount = 0; + + +void +InOrderDynInst::setMachInst(ExtMachInst machInst) +{ + staticInst = StaticInst::decode(machInst, PC); + + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } +} + +void +InOrderDynInst::initVars() +{ + req = NULL; + effAddr = 0; + physEffAddr = 0; + + readyRegs = 0; + + nextStage = 0; + nextInstStageNum = 0; + + for(int i = 0; i < MaxInstDestRegs; i++) + instResult[i].val.integer = 0; + + status.reset(); + + memAddrReady = false; + eaCalcDone = false; + memOpDone = false; + + predictTaken = false; + procDelaySlotOnMispred = false; + + lqIdx = -1; + sqIdx = -1; + + // Also make this a parameter, or perhaps get it from xc or cpu. + asid = 0; + + virtProcNumber = 0; + + // Initialize the fault to be NoFault. + fault = NoFault; + + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + if (this->staticInst) { + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } + } + + // Update Instruction Count for this instruction + ++instcount; + if (instcount > 500) { + fatal("Number of Active Instructions in CPU is too high. " + "(Not Dereferencing Ptrs. Correctly?)\n"); + } + + + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n", + threadNumber, seqNum, instcount); +} + + +InOrderDynInst::~InOrderDynInst() +{ + if (req) { + delete req; + } + + if (traceData) { + delete traceData; + } + + fault = NoFault; + + --instcount; + + deleteStages(); + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n", + threadNumber, seqNum, instcount); +} + +void +InOrderDynInst::setStaticInst(StaticInstPtr &static_inst) +{ + this->staticInst = static_inst; + + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + if (this->staticInst) { + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } + } +} + +Fault +InOrderDynInst::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +Fault +InOrderDynInst::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + + +Fault +InOrderDynInst::completeAcc(Packet *pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +InstStage *InOrderDynInst::addStage() +{ + this->currentInstStage = new InstStage(this, nextInstStageNum++); + instStageList.push_back( this->currentInstStage ); + return this->currentInstStage; +} + +InstStage *InOrderDynInst::addStage(int stage_num) +{ + nextInstStageNum = stage_num; + return InOrderDynInst::addStage(); +} + +void InOrderDynInst::deleteStages() { + std::list<InstStage*>::iterator list_it = instStageList.begin(); + std::list<InstStage*>::iterator list_end = instStageList.end(); + + while(list_it != list_end) { + delete *list_it; + list_it++; + } +} + +Fault +InOrderDynInst::calcEA() +{ + return staticInst->eaCompInst()->execute(this, this->traceData); +} + +Fault +InOrderDynInst::memAccess() +{ + //return staticInst->memAccInst()->execute(this, this->traceData); + return initiateAcc( ); +} + +void +InOrderDynInst::syscall(int64_t callnum) +{ + cpu->syscall(callnum, this->threadNumber); +} + +void +InOrderDynInst::prefetch(Addr addr, unsigned flags) +{ + panic("Prefetch Unimplemented\n"); +} + +void +InOrderDynInst::writeHint(Addr addr, int size, unsigned flags) +{ + panic("Write-Hint Unimplemented\n"); +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copySrcTranslate(Addr src) +{ + // Not currently supported. + return NoFault; +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copy(Addr dest) +{ + // Not currently supported. + return NoFault; +} + +void +InOrderDynInst::releaseReq(ResourceRequest* req) +{ + std::list<ResourceRequest*>::iterator list_it = reqList.begin(); + std::list<ResourceRequest*>::iterator list_end = reqList.end(); + + while(list_it != list_end) { + if((*list_it)->getResIdx() == req->getResIdx() && + (*list_it)->getSlot() == req->getSlot()) { + DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n", + threadNumber, seqNum, req->res->name()); + reqList.erase(list_it); + return; + } + list_it++; + } + + panic("Releasing Res. Request That Isnt There!\n"); +} + +/** Records an integer source register being set to a value. */ +void +InOrderDynInst::setIntSrc(int idx, uint64_t val) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n", + threadNumber, seqNum, idx, val); + instSrc[idx].integer = val; +} + +/** Records an fp register being set to a value. */ +void +InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width) +{ + if (width == 32) + instSrc[idx].fp = val; + else if (width == 64) + instSrc[idx].dbl = val; + else + panic("Unsupported width!"); +} + +/** Records an fp register being set to an integer value. */ +void +InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val) +{ + instSrc[idx].integer = val; +} + +/** Reads a integer register. */ +IntReg +InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n", + threadNumber, seqNum, idx, instSrc[idx].integer); + return instSrc[idx].integer; +} + +/** Reads a FP register. */ +FloatReg +InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].fp; +} + + +/** Reads a FP register as a integer. */ +FloatRegBits +InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].integer; +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscReg(int misc_reg) +{ + return this->cpu->readMiscReg(misc_reg, threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegNoEffect(int misc_reg) +{ + return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber); +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx) +{ + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return cpu->readMiscRegNoEffect(reg, this->threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx) +{ + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg, this->threadNumber); +} + +/** Sets a misc. register. */ +void +InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +void +InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +MiscReg +InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return this->cpu->readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return this->cpu->readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File + } +} + +/** Sets a Integer register. */ +void +InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a FP register. */ +void +InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) +{ + if (width == 32) + instResult[idx].val.fp = val; + else if (width == 64) + instResult[idx].val.dbl = val; + else + panic("Unsupported Floating Point Width!"); + + instResult[idx].tick = curTick; +} + +/** Sets a FP register as a integer. */ +void +InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a misc. register. */ +/* Alter this when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +/* Alter this if/when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscReg(misc_reg, val, threadNumber); +} + +void +InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + this->cpu->setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + this->cpu->setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +void +InOrderDynInst::deallocateContext(int thread_num) +{ + this->cpu->deallocateContext(thread_num); +} + +void +InOrderDynInst::enableVirtProcElement(unsigned vpe) +{ + this->cpu->enableVirtProcElement(vpe); +} + +void +InOrderDynInst::disableVirtProcElement(unsigned vpe) +{ + this->cpu->disableVirtProcElement(threadNumber, vpe); +} + +void +InOrderDynInst::enableMultiThreading(unsigned vpe) +{ + this->cpu->enableMultiThreading(vpe); +} + +void +InOrderDynInst::disableMultiThreading(unsigned vpe) +{ + this->cpu->disableMultiThreading(threadNumber, vpe); +} + +void +InOrderDynInst::setThreadRescheduleCondition(uint32_t cond) +{ + this->cpu->setThreadRescheduleCondition(cond); +} + +template<class T> +inline Fault +InOrderDynInst::read(Addr addr, T &data, unsigned flags) +{ + return cpu->read(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + +template<class T> +inline Fault +InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + //memcpy(memData, gtoh(data), sizeof(T)); + storeData = data; + + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n", + threadNumber, seqNum, memData); + return cpu->write(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +InOrderDynInst::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +InOrderDynInst::dump() +{ + cprintf("T%d : %#08d `", threadNumber, PC); + cout << staticInst->disassemble(PC); + cprintf("'\n"); +} + +void +InOrderDynInst::dump(std::string &outstring) +{ + std::ostringstream s; + s << "T" << threadNumber << " : 0x" << PC << " " + << staticInst->disassemble(PC); + + outstring = s.str(); +} + + +#define NOHASH +#ifndef NOHASH + +#include "base/hashmap.hh" + +unsigned int MyHashFunc(const InOrderDynInst *addr) +{ + unsigned a = (unsigned)addr; + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; +} + +typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc> +my_hash_t; + +my_hash_t thishash; +#endif diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh new file mode 100644 index 000000000..55c61ffb9 --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_DYN_INST_HH__ +#define __CPU_INORDER_DYN_INST_HH__ + +#include <bitset> +#include <list> +#include <string> + +#include "arch/faults.hh" +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/inst_seq.hh" +#include "cpu/op_class.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "mem/packet.hh" +#include "sim/system.hh" + +/** + * @file + * Defines a dynamic instruction context for a inorder CPU model. + */ + +// Forward declaration. +class StaticInstPtr; +class ResourceRequest; + +class InOrderDynInst : public FastAlloc, public RefCounted +{ + public: + // Binary machine instruction type. + typedef TheISA::MachInst MachInst; + // Extended machine instruction type + typedef TheISA::ExtMachInst ExtMachInst; + // Logical register index type. + typedef TheISA::RegIndex RegIndex; + // Integer register type. + typedef TheISA::IntReg IntReg; + // Floating point register type. + typedef TheISA::FloatReg FloatReg; + // Floating point register type. + typedef TheISA::MiscReg MiscReg; + + typedef short int PhysRegIndex; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst*. + */ + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + // The list of instructions iterator type. + typedef std::list<DynInstPtr>::iterator ListIt; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. + * @param inst The binary instruction. + * @param PC The PC of the instruction. + * @param pred_PC The predicted next PC. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + */ + InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu); + + /** BaseDynInst constructor given a binary instruction. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + * NOTE: Must set Binary Instrution through Member Function + */ + InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num, + unsigned tid); + + /** BaseDynInst constructor given a StaticInst pointer. + * @param _staticInst The StaticInst for this BaseDynInst. + */ + InOrderDynInst(StaticInstPtr &_staticInst); + + /** Skeleton Constructor. */ + InOrderDynInst(); + + /** InOrderDynInst destructor. */ + ~InOrderDynInst(); + + public: + /** The sequence number of the instruction. */ + InstSeqNum seqNum; + + /** The sequence number of the instruction. */ + InstSeqNum bdelaySeqNum; + + enum Status { + RegDepMapEntry, /// Instruction has been entered onto the RegDepMap + IqEntry, /// Instruction is in the IQ + RobEntry, /// Instruction is in the ROB + LsqEntry, /// Instruction is in the LSQ + Completed, /// Instruction has completed + ResultReady, /// Instruction has its result + CanIssue, /// Instruction can issue and execute + Issued, /// Instruction has issued + Executed, /// Instruction has executed + CanCommit, /// Instruction can commit + AtCommit, /// Instruction has reached commit + Committed, /// Instruction has committed + Squashed, /// Instruction is squashed + SquashedInIQ, /// Instruction is squashed in the IQ + SquashedInLSQ, /// Instruction is squashed in the LSQ + SquashedInROB, /// Instruction is squashed in the ROB + RecoverInst, /// Is a recover instruction + BlockingInst, /// Is a blocking instruction + ThreadsyncWait, /// Is a thread synchronization instruction + SerializeBefore, /// Needs to serialize on + /// instructions ahead of it + SerializeAfter, /// Needs to serialize instructions behind it + SerializeHandled, /// Serialization has been handled + NumStatus + }; + + /** The status of this BaseDynInst. Several bits can be set. */ + std::bitset<NumStatus> status; + + /** The thread this instruction is from. */ + short threadNumber; + + /** data address space ID, for loads & stores. */ + short asid; + + /** The virtual processor number */ + short virtProcNumber; + + /** The StaticInst used by this BaseDynInst. */ + StaticInstPtr staticInst; + + /** InstRecord that tracks this instructions. */ + Trace::InOrderTraceRecord *traceData; + + /** Pointer to the Impl's CPU object. */ + InOrderCPU *cpu; + + /** Pointer to the thread state. */ + InOrderThreadState *thread; + + /** The kind of fault this instruction has generated. */ + Fault fault; + + /** The memory request. */ + Request *req; + + /** Pointer to the data for the memory access. */ + uint8_t *memData; + + /** Data used for a store for operation. */ + uint64_t loadData; + + /** Data used for a store for operation. */ + uint64_t storeData; + + /** The resource schedule for this inst */ + ThePipeline::ResSchedule resSched; + + /** List of active resource requests for this instruction */ + std::list<ResourceRequest*> reqList; + + /** The effective virtual address (lds & stores only). */ + Addr effAddr; + + /** The effective physical address. */ + Addr physEffAddr; + + /** Effective virtual address for a copy source. */ + Addr copySrcEffAddr; + + /** Effective physical address for a copy source. */ + Addr copySrcPhysEffAddr; + + /** The memory request flags (from translation). */ + unsigned memReqFlags; + + /** How many source registers are ready. */ + unsigned readyRegs; + + /** An instruction src/dest has to be one of these types */ + union InstValue { + uint64_t integer; + float fp; + double dbl; + }; + + /** Result of an instruction execution */ + struct InstResult { + InstValue val; + Tick tick; + }; + + /** The source of the instruction; assumes for now that there's only one + * destination register. + */ + InstValue instSrc[MaxInstSrcRegs]; + + /** The result of the instruction; assumes for now that there's only one + * destination register. + */ + InstResult instResult[MaxInstDestRegs]; + + /** PC of this instruction. */ + Addr PC; + + /** Next non-speculative PC. It is not filled in at fetch, but rather + * once the target of the branch is truly known (either decode or + * execute). + */ + Addr nextPC; + + /** Next next non-speculative PC. It is not filled in at fetch, but rather + * once the target of the branch is truly known (either decode or + * execute). + */ + Addr nextNPC; + + /** Predicted next PC. */ + Addr predPC; + + /** Address to fetch from */ + Addr fetchAddr; + + /** Address to get/write data from/to */ + Addr memAddr; + + /** Whether or not the source register is ready. + * @todo: Not sure this should be here vs the derived class. + */ + bool _readySrcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; + + int nextStage; + + /* vars to keep track of InstStage's - used for resource sched defn */ + int nextInstStageNum; + ThePipeline::InstStage *currentInstStage; + std::list<ThePipeline::InstStage*> instStageList; + + private: + /** Function to initialize variables in the constructors. */ + void initVars(); + + public: + Tick memTime; + + //////////////////////////////////////////////////////////// + // + // BASE INSTRUCTION INFORMATION. + // + //////////////////////////////////////////////////////////// + void setMachInst(ExtMachInst inst); + + /** Sets the StaticInst. */ + void setStaticInst(StaticInstPtr &static_inst); + + /** Sets the sequence number. */ + void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; } + + /** Sets the ASID. */ + void setASID(short addr_space_id) { asid = addr_space_id; } + + /** Reads the thread id. */ + short readTid() { return threadNumber; } + + /** Sets the thread id. */ + void setTid(unsigned tid) { threadNumber = tid; } + + void setVpn(int id) { virtProcNumber = id; } + + int readVpn() { return virtProcNumber; } + + /** Sets the pointer to the thread state. */ + void setThreadState(InOrderThreadState *state) { thread = state; } + + /** Returns the thread context. */ + ThreadContext *tcBase() { return thread->getTC(); } + + /** Returns the fault type. */ + Fault getFault() { return fault; } + + //////////////////////////////////////////////////////////// + // + // INSTRUCTION TYPES - Forward checks to StaticInst object. + // + //////////////////////////////////////////////////////////// + bool isNop() const { return staticInst->isNop(); } + bool isMemRef() const { return staticInst->isMemRef(); } + bool isLoad() const { return staticInst->isLoad(); } + bool isStore() const { return staticInst->isStore(); } + bool isStoreConditional() const + { return staticInst->isStoreConditional(); } + bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } + bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } + bool isCopy() const { return staticInst->isCopy(); } + bool isInteger() const { return staticInst->isInteger(); } + bool isFloating() const { return staticInst->isFloating(); } + bool isControl() const { return staticInst->isControl(); } + bool isCall() const { return staticInst->isCall(); } + bool isReturn() const { return staticInst->isReturn(); } + bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } + bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } + bool isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } + bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } + + bool isThreadSync() const { return staticInst->isThreadSync(); } + bool isSerializing() const { return staticInst->isSerializing(); } + bool isSerializeBefore() const + { return staticInst->isSerializeBefore() || status[SerializeBefore]; } + bool isSerializeAfter() const + { return staticInst->isSerializeAfter() || status[SerializeAfter]; } + bool isMemBarrier() const { return staticInst->isMemBarrier(); } + bool isWriteBarrier() const { return staticInst->isWriteBarrier(); } + bool isNonSpeculative() const { return staticInst->isNonSpeculative(); } + bool isQuiesce() const { return staticInst->isQuiesce(); } + bool isIprAccess() const { return staticInst->isIprAccess(); } + bool isUnverifiable() const { return staticInst->isUnverifiable(); } + + ///////////////////////////////////////////// + // + // RESOURCE SCHEDULING + // + ///////////////////////////////////////////// + + void setNextStage(int stage_num) { nextStage = stage_num; } + int getNextStage() { return nextStage; } + + ThePipeline::InstStage *addStage(); + ThePipeline::InstStage *addStage(int stage); + ThePipeline::InstStage *currentStage() { return currentInstStage; } + void deleteStages(); + + /** Add A Entry To Reource Schedule */ + void addToSched(ThePipeline::ScheduleEntry* sched_entry) + { resSched.push(sched_entry); } + + + /** Print Resource Schedule */ + void printSched() + { + using namespace ThePipeline; + + ResSchedule tempSched; + std::cerr << "\tInst. Res. Schedule: "; + while (!resSched.empty()) { + std::cerr << '\t' << resSched.top()->stageNum << "-" + << resSched.top()->resNum << ", "; + + tempSched.push(resSched.top()); + resSched.pop(); + } + + std::cerr << std::endl; + resSched = tempSched; + } + + /** Return Next Resource Stage To Be Used */ + int nextResStage() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->stageNum; + } + + + /** Return Next Resource To Be Used */ + int nextResource() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->resNum; + } + + /** Remove & Deallocate a schedule entry */ + void popSchedEntry() + { + if (!resSched.empty()) { + ThePipeline::ScheduleEntry* sked = resSched.top(); + resSched.pop(); + delete sked; + } + } + + /** Release a Resource Request (Currently Unused) */ + void releaseReq(ResourceRequest* req); + + //////////////////////////////////////////// + // + // INSTRUCTION EXECUTION + // + //////////////////////////////////////////// + /** Returns the opclass of this instruction. */ + OpClass opClass() const { return staticInst->opClass(); } + + /** Executes the instruction.*/ + Fault execute(); + + unsigned curResSlot; + + unsigned getCurResSlot() { return curResSlot; } + + void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; } + + /** Calls a syscall. */ + void syscall(int64_t callnum); + void prefetch(Addr addr, unsigned flags); + void writeHint(Addr addr, int size, unsigned flags); + Fault copySrcTranslate(Addr src); + Fault copy(Addr dest); + + //////////////////////////////////////////////////////////// + // + // MULTITHREADING INTERFACE TO CPU MODELS + // + //////////////////////////////////////////////////////////// + virtual void deallocateContext(int thread_num); + + virtual void enableVirtProcElement(unsigned vpe); + virtual void disableVirtProcElement(unsigned vpe); + + virtual void enableMultiThreading(unsigned vpe); + virtual void disableMultiThreading(unsigned vpe); + + virtual void setThreadRescheduleCondition(uint32_t cond); + + //////////////////////////////////////////////////////////// + // + // PROGRAM COUNTERS - PC/NPC/NPC + // + //////////////////////////////////////////////////////////// + /** Read the PC of this instruction. */ + const Addr readPC() const { return PC; } + + /** Sets the PC of this instruction. */ + void setPC(Addr pc) { PC = pc; } + + /** Returns the next PC. This could be the speculative next PC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextPC() { return nextPC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextPC(uint64_t val) { nextPC = val; } + + /** Returns the next NPC. This could be the speculative next NPC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextNPC() { return nextNPC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextNPC(uint64_t val) { nextNPC = val; } + + //////////////////////////////////////////////////////////// + // + // BRANCH PREDICTION + // + //////////////////////////////////////////////////////////// + /** Set the predicted target of this current instruction. */ + void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; } + + /** Returns the predicted target of the branch. */ + Addr readPredTarg() { return predPC; } + + /** Returns whether the instruction was predicted taken or not. */ + bool predTaken() { return predictTaken; } + + /** Returns whether the instruction mispredicted. */ + bool mispredicted() + { + // Special case since a not-taken, cond. delay slot, effectively + // nullifies the delay slot instruction + if (isCondDelaySlot() && !predictTaken) { + return predPC != nextPC; + } else { + return predPC != nextNPC; + } + } + + /** Returns whether the instruction mispredicted. */ + bool mistargeted() { return predPC != nextNPC; } + + /** Returns the branch target address. */ + Addr branchTarget() const { return staticInst->branchTarget(PC); } + + /** Checks whether or not this instruction has had its branch target + * calculated yet. For now it is not utilized and is hacked to be + * always false. + * @todo: Actually use this instruction. + */ + bool doneTargCalc() { return false; } + + void setBranchPred(bool prediction) { predictTaken = prediction; } + + int squashingStage; + + bool predictTaken; + + bool procDelaySlotOnMispred; + + //////////////////////////////////////////// + // + // MEMORY ACCESS + // + //////////////////////////////////////////// + /** + * Does a read to a given address. + * @param addr The address to read. + * @param data The read's data is written into this parameter. + * @param flags The request's flags. + * @return Returns any fault due to the read. + */ + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + /** + * Does a write to a given address. + * @param data The data to be written. + * @param addr The address to write to. + * @param flags The request's flags. + * @param res The result of the write (for load locked/store conditionals). + * @return Returns any fault due to the write. + */ + template <class T> + Fault write(T data, Addr addr, unsigned flags, + uint64_t *res); + + /** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access + * Only valid for memory operations. + */ + Fault initiateAcc(); + + /** Completes a memory access - Only valid for memory operations. */ + Fault completeAcc(Packet *pkt); + + /** Calculates Eff. Addr. part of a memory instruction. */ + Fault calcEA(); + + /** Read Effective Address from instruction & do memory access */ + Fault memAccess(); + + RequestPtr memReq; + + bool memAddrReady; + + bool validMemAddr() + { return memAddrReady; } + + void setMemAddr(Addr addr) + { memAddr = addr; memAddrReady = true;} + + void unsetMemAddr() + { memAddrReady = false;} + + Addr getMemAddr() + { return memAddr; } + + int getMemAccSize() { return staticInst->memAccSize(this); } + + int getMemFlags() { return staticInst->memAccFlags(); } + + /** Sets the effective address. */ + void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } + + /** Returns the effective address. */ + const Addr &getEA() const { return instEffAddr; } + + /** Returns whether or not the eff. addr. calculation has been completed. */ + bool doneEACalc() { return eaCalcDone; } + + /** Returns whether or not the eff. addr. source registers are ready. + * Assume that src registers 1..n-1 are the ones that the + * EA calc depends on. (i.e. src reg 0 is the source of the data to be + * stored) + */ + bool eaSrcsReady() + { + for (int i = 1; i < numSrcRegs(); ++i) { + if (!_readySrcRegIdx[i]) + return false; + } + + return true; + } + + ////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER INDEXING + // + ////////////////////////////////////////////////// + /** Returns the number of source registers. */ + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + + /** Returns the number of destination registers. */ + int8_t numDestRegs() const { return staticInst->numDestRegs(); } + + // the following are used to track physical register usage + // for machines with separate int & FP reg files + int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); } + int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); } + + /** Returns the logical register index of the i'th destination register. */ + RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); } + + /** Returns the logical register index of the i'th source register. */ + RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } + + ////////////////////////////////////////////////// + // + // RENAME/PHYSICAL REGISTER FILE SUPPORT + // + ////////////////////////////////////////////////// + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Returns if a source register is ready. */ + bool isReadySrcRegIdx(int idx) const + { + return this->_readySrcRegIdx[idx]; + } + + /** Records that one of the source registers is ready. */ + void markSrcRegReady() + { + if (++readyRegs == numSrcRegs()) { + status.set(CanIssue); + } + } + + /** Marks a specific register as ready. */ + void markSrcRegReady(RegIndex src_idx) + { + _readySrcRegIdx[src_idx] = true; + + markSrcRegReady(); + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + + PhysRegIndex readDestRegIdx(int idx) + { + return _destRegIdx[idx]; + } + + void setDestRegIdx(int idx, PhysRegIndex dest_idx) + { + _destRegIdx[idx] = dest_idx; + } + + int getDestIdxNum(PhysRegIndex dest_idx) + { + for (int i=0; i < staticInst->numDestRegs(); i++) { + if (_destRegIdx[i] == dest_idx) + return i; + } + + return -1; + } + + PhysRegIndex readSrcRegIdx(int idx) + { + return _srcRegIdx[idx]; + } + + void setSrcRegIdx(int idx, PhysRegIndex src_idx) + { + _srcRegIdx[idx] = src_idx; + } + + int getSrcIdxNum(PhysRegIndex src_idx) + { + for (int i=0; i < staticInst->numSrcRegs(); i++) { + if (_srcRegIdx[i] == src_idx) + return i; + } + + return -1; + } + + //////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER VALUES + // + //////////////////////////////////////////////////// + + /** Functions that sets an integer or floating point + * source register to a value. */ + void setIntSrc(int idx, uint64_t val); + void setFloatSrc(int idx, FloatReg val, int width = 32); + void setFloatRegBitsSrc(int idx, uint64_t val); + + uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; } + uint64_t readIntSrc(int idx) { return instSrc[idx].integer; } + + /** These Instructions read a integer/float/misc. source register + * value in the instruction. The instruction's execute function will + * call these and it is the interface that is used by the ISA descr. + * language (which is why the name isnt readIntSrc(...)) Note: That + * the source reg. value is set using the setSrcReg() function. + */ + IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0); + FloatReg readFloatRegOperand(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + MiscReg readMiscReg(int misc_reg); + MiscReg readMiscRegNoEffect(int misc_reg); + MiscReg readMiscRegOperand(const StaticInst *si, int idx); + MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx); + + /** Returns the result value instruction. */ + uint64_t readIntResult(int idx) { return instResult[idx].val.integer; } + float readFloatResult(int idx) { return instResult[idx].val.fp; } + double readDoubleResult(int idx) { return instResult[idx].val.dbl; } + Tick readResultTime(int idx) { return instResult[idx].tick; } + + uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; } + + /** This is the interface that an instruction will use to write + * it's destination register. + */ + void setIntRegOperand(const StaticInst *si, int idx, IntReg val); + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width = TheISA::SingleWidth); + void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val, + int width = TheISA::SingleWidth); + void setMiscReg(int misc_reg, const MiscReg &val); + void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val); + void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val); + + virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1); + virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1); + + ////////////////////////////////////////////////////////////// + // + // INSTRUCTION STATUS FLAGS (READ/SET) + // + ////////////////////////////////////////////////////////////// + /** Sets this instruction as entered on the CPU Reg Dep Map */ + void setRegDepEntry() { status.set(RegDepMapEntry); } + + /** Returns whether or not the entry is on the CPU Reg Dep Map */ + bool isRegDepEntry() const { return status[RegDepMapEntry]; } + + /** Sets this instruction as completed. */ + void setCompleted() { status.set(Completed); } + + /** Returns whether or not this instruction is completed. */ + bool isCompleted() const { return status[Completed]; } + + /** Marks the result as ready. */ + void setResultReady() { status.set(ResultReady); } + + /** Returns whether or not the result is ready. */ + bool isResultReady() const { return status[ResultReady]; } + + /** Sets this instruction as ready to issue. */ + void setCanIssue() { status.set(CanIssue); } + + /** Returns whether or not this instruction is ready to issue. */ + bool readyToIssue() const { return status[CanIssue]; } + + /** Sets this instruction as issued from the IQ. */ + void setIssued() { status.set(Issued); } + + /** Returns whether or not this instruction has issued. */ + bool isIssued() const { return status[Issued]; } + + /** Sets this instruction as executed. */ + void setExecuted() { status.set(Executed); } + + /** Returns whether or not this instruction has executed. */ + bool isExecuted() const { return status[Executed]; } + + /** Sets this instruction as ready to commit. */ + void setCanCommit() { status.set(CanCommit); } + + /** Clears this instruction as being ready to commit. */ + void clearCanCommit() { status.reset(CanCommit); } + + /** Returns whether or not this instruction is ready to commit. */ + bool readyToCommit() const { return status[CanCommit]; } + + void setAtCommit() { status.set(AtCommit); } + + bool isAtCommit() { return status[AtCommit]; } + + /** Sets this instruction as committed. */ + void setCommitted() { status.set(Committed); } + + /** Returns whether or not this instruction is committed. */ + bool isCommitted() const { return status[Committed]; } + + /** Sets this instruction as squashed. */ + void setSquashed() { status.set(Squashed); } + + /** Returns whether or not this instruction is squashed. */ + bool isSquashed() const { return status[Squashed]; } + + /** Temporarily sets this instruction as a serialize before instruction. */ + void setSerializeBefore() { status.set(SerializeBefore); } + + /** Clears the serializeBefore part of this instruction. */ + void clearSerializeBefore() { status.reset(SerializeBefore); } + + /** Checks if this serializeBefore is only temporarily set. */ + bool isTempSerializeBefore() { return status[SerializeBefore]; } + + /** Temporarily sets this instruction as a serialize after instruction. */ + void setSerializeAfter() { status.set(SerializeAfter); } + + /** Clears the serializeAfter part of this instruction.*/ + void clearSerializeAfter() { status.reset(SerializeAfter); } + + /** Checks if this serializeAfter is only temporarily set. */ + bool isTempSerializeAfter() { return status[SerializeAfter]; } + + /** Sets the serialization part of this instruction as handled. */ + void setSerializeHandled() { status.set(SerializeHandled); } + + /** Checks if the serialization part of this instruction has been + * handled. This does not apply to the temporary serializing + * state; it only applies to this instruction's own permanent + * serializing state. + */ + bool isSerializeHandled() { return status[SerializeHandled]; } + + private: + /** Instruction effective address. + * @todo: Consider if this is necessary or not. + */ + Addr instEffAddr; + + /** Whether or not the effective address calculation is completed. + * @todo: Consider if this is necessary or not. + */ + bool eaCalcDone; + + public: + /** Whether or not the memory operation is done. */ + bool memOpDone; + + public: + /** Load queue index. */ + int16_t lqIdx; + + /** Store queue index. */ + int16_t sqIdx; + + /** Iterator pointing to this BaseDynInst in the list of all insts. */ + ListIt instListIt; + + /** Returns iterator to this instruction in the list of all insts. */ + ListIt &getInstListIt() { return instListIt; } + + /** Sets iterator for this instruction in the list of all insts. */ + void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; } + + /** Count of total number of dynamic instructions. */ + static int instcount; + + /** Dumps out contents of this BaseDynInst. */ + void dump(); + + /** Dumps out contents of this BaseDynInst into given string. */ + void dump(std::string &outstring); + + + //inline int curCount() { return curCount(); } +}; + + +#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/dev/pitreg.h b/src/cpu/inorder/inorder_trace.cc index d42925a41..f12a1b7a9 100644 --- a/src/dev/pitreg.h +++ b/src/cpu/inorder/inorder_trace.cc @@ -1,4 +1,5 @@ /* + * Copyright (c) 2007 MIPS Technologies, Inc. * Copyright (c) 2001-2005 The Regents of The University of Michigan * All rights reserved. * @@ -25,51 +26,69 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Miguel Serrano + * Authors: Korey Sewell */ -/* @file - * Device register definitions for a device's PCI config space - */ +#include <iomanip> -#ifndef __PITREG_H__ -#define __PITREG_H__ +#include "cpu/exetrace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/thread_context.hh" +#include "params/InOrderTrace.hh" -#include <sys/types.h> +using namespace std; +using namespace TheISA; -// Control Word Format +namespace Trace { -#define PIT_SEL_SHFT 0x6 -#define PIT_RW_SHFT 0x4 -#define PIT_MODE_SHFT 0x1 -#define PIT_BCD_SHFT 0x0 +inline void +Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs) +{ + if (!stageTrace) { + ccprintf(outs, "%7d: ", when); + } else { + ccprintf(outs, ""); + for (int i=0; i < stageCycle.size(); i++) { + if (i < stageCycle.size() - 1) + outs << dec << stageCycle[i] << "-"; + else + outs << dec << stageCycle[i] << ":"; + } + } +} -#define PIT_SEL_MASK 0x3 -#define PIT_RW_MASK 0x3 -#define PIT_MODE_MASK 0x7 -#define PIT_BCD_MASK 0x1 +InOrderTraceRecord * +InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing, + ThreadContext *tc) +{ + if (!IsOn(ExecEnable)) + return NULL; -#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m) -#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK) -#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK) -#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK) -#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK) + if (!Trace::enabled) + return NULL; -#define PIT_READ_BACK 0x3 + return new InOrderTraceRecord(num_stages, stage_tracing, tc); +} -#define PIT_RW_LATCH_COMMAND 0x0 -#define PIT_RW_LSB_ONLY 0x1 -#define PIT_RW_MSB_ONLY 0x2 -#define PIT_RW_16BIT 0x3 +InOrderTraceRecord * +InOrderTrace::getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst, MicroPC upc) +{ + return new InOrderTraceRecord(ThePipeline::NumStages, true, tc); +} -#define PIT_MODE_INTTC 0x0 -#define PIT_MODE_ONESHOT 0x1 -#define PIT_MODE_RATEGEN 0x2 -#define PIT_MODE_SQWAVE 0x3 -#define PIT_MODE_SWSTROBE 0x4 -#define PIT_MODE_HWSTROBE 0x5 +/* namespace Trace */ } -#define PIT_BCD_FALSE 0x0 -#define PIT_BCD_TRUE 0x1 +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::InOrderTrace * +InOrderTraceParams::create() +{ + return new Trace::InOrderTrace(this); +}; -#endif // __PITREG_H__ diff --git a/src/cpu/inorder/inorder_trace.hh b/src/cpu/inorder/inorder_trace.hh new file mode 100644 index 000000000..4338b438c --- /dev/null +++ b/src/cpu/inorder/inorder_trace.hh @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + */ + +#ifndef __INORDERTRACE_HH__ +#define __INORDERTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" +#include "params/InOrderTrace.hh" +#include "cpu/exetrace.hh" + +class ThreadContext; + + +namespace Trace { + +class InOrderTraceRecord : public ExeTracerRecord +{ + public: + InOrderTraceRecord(unsigned num_stages, bool _stage_tracing, + ThreadContext *_thread, bool spec = false) + : ExeTracerRecord(0, _thread, NULL, 0, spec) + { + stageTrace = _stage_tracing; + stageCycle.resize(num_stages); + } + + // Trace stage-by-stage execution of instructions. + bool stageTrace; + std::vector<Tick> stageCycle; + + void dumpTicks(std::ostream &outs); + + void + setStageCycle(int num_stage, Tick cur_cycle) + { + if (stageTrace) { + stageCycle[num_stage] = cur_cycle; + } else { + when = cur_cycle; + } + } + + void + setStaticInst(const StaticInstPtr &_staticInst) + { + staticInst = _staticInst; + } + void setPC(Addr _pc) { PC = _pc; } +}; + +class InOrderTrace : public InstTracer +{ + public: + InOrderTrace(const InOrderTraceParams *p) : InstTracer(p) + {} + + InOrderTraceRecord * + getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc); + + virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0); +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/o3/params.hh b/src/cpu/inorder/params.hh index b487778c6..51b7409ad 100755..100644 --- a/src/cpu/o3/params.hh +++ b/src/cpu/inorder/params.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,101 +25,45 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim + * Authors: Korey Sewell */ -#ifndef __CPU_O3_PARAMS_HH__ -#define __CPU_O3_PARAMS_HH__ +#ifndef __CPU_INORDER_PARAMS_HH__ +#define __CPU_INORDER_PARAMS_HH__ -#include "cpu/o3/cpu.hh" +#include "cpu/base.hh" //Forward declarations -class FUPool; +class FunctionalMemory; +class Process; +class MemObject; +class MemInterface; /** - * This file defines the parameters that will be used for the O3CPU. + * This file defines the parameters that will be used for the InOrderCPU. * This must be defined externally so that the Impl can have a params class * defined that it can pass to all of the individual stages. */ -class O3Params : public BaseO3CPU::Params + +class InOrderParams : public BaseCPU::Params { public: - unsigned activity; - // - // Pointers to key objects - // + // Workloads #if !FULL_SYSTEM std::vector<Process *> workload; Process *process; #endif // FULL_SYSTEM - BaseCPU *checker; - // - // Caches + // Memory System/Caches // - // MemInterface *icacheInterface; - // MemInterface *dcacheInterface; - unsigned cachePorts; + std::string fetchMemPort; + std::string dataMemPort; // - // Fetch - // - unsigned decodeToFetchDelay; - unsigned renameToFetchDelay; - unsigned iewToFetchDelay; - unsigned commitToFetchDelay; - unsigned fetchWidth; - - // - // Decode - // - unsigned renameToDecodeDelay; - unsigned iewToDecodeDelay; - unsigned commitToDecodeDelay; - unsigned fetchToDecodeDelay; - unsigned decodeWidth; - - // - // Rename - // - unsigned iewToRenameDelay; - unsigned commitToRenameDelay; - unsigned decodeToRenameDelay; - unsigned renameWidth; - - // - // IEW - // - unsigned commitToIEWDelay; - unsigned renameToIEWDelay; - unsigned issueToExecuteDelay; - unsigned dispatchWidth; - unsigned issueWidth; - unsigned wbWidth; - unsigned wbDepth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - Tick trapLatency; - Tick fetchTrapLatency; - - // - // Timebuffer sizes - // - unsigned backComSize; - unsigned forwardComSize; - - // - // Branch predictor (BP, BTB, RAS) + // Branch predictor (BP & BTB) // std::string predType; unsigned localPredictorSize; @@ -131,50 +75,50 @@ class O3Params : public BaseO3CPU::Params unsigned globalHistoryBits; unsigned choicePredictorSize; unsigned choiceCtrBits; - unsigned BTBEntries; unsigned BTBTagSize; - unsigned RASSize; - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; + // Pipeline Parameters + unsigned stageWidth; + + // InOrderCPU Simulation Parameters + unsigned instShiftAmt; + unsigned activity; + unsigned deferRegistration; // - // Memory dependence + // Memory Parameters // - unsigned SSITSize; - unsigned LFSTSize; + unsigned memBlockSize; // - // Miscellaneous + // Multiply Divide Unit // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; + // @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr, + // then MDU must be defined as its own SimObject so that an arbitrary # can + // be defined with different parameters + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multLatency; + unsigned multRepeatRate; - //SMT Parameters - unsigned smtNumFetchingThreads; + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8Latency; + unsigned div8RepeatRate; - std::string smtFetchPolicy; + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16Latency; + unsigned div16RepeatRate; - std::string smtIQPolicy; - unsigned smtIQThreshold; + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24Latency; + unsigned div24RepeatRate; - std::string smtLSQPolicy; - unsigned smtLSQThreshold; + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32Latency; + unsigned div32RepeatRate; - std::string smtCommitPolicy; - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; }; -#endif // __CPU_O3_ALPHA_PARAMS_HH__ +#endif // _CPU_INORDER_PARAMS_HH__ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc new file mode 100644 index 000000000..cb69464b0 --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.cc @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +PipelineStage::PipelineStage(Params *params, unsigned stage_num) + : stageNum(stage_num), stageWidth(ThePipeline::StageWidth), + numThreads(ThePipeline::MaxThreads), _status(Inactive), + stageBufferMax(ThePipeline::interStageBuffSize[stage_num]), + prevStageValid(false), nextStageValid(false) +{ + init(params); +} + +void +PipelineStage::init(Params *params) +{ + for(int tid=0; tid < numThreads; tid++) { + stageStatus[tid] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); + + if (stageNum < BackEndStartStage) + lastStallingStage[tid] = BackEndStartStage - 1; + else + lastStallingStage[tid] = NumStages - 1; + } +} + + +std::string +PipelineStage::name() const +{ + return cpu->name() + ".stage-" + to_string(stageNum); +} + + +void +PipelineStage::regStats() +{ +/* stageIdleCycles + .name(name() + ".IdleCycles") + .desc("Number of cycles stage is idle") + .prereq(stageIdleCycles); + stageBlockedCycles + .name(name() + ".BlockedCycles") + .desc("Number of cycles stage is blocked") + .prereq(stageBlockedCycles); + stageRunCycles + .name(name() + ".RunCycles") + .desc("Number of cycles stage is running") + .prereq(stageRunCycles); + stageUnblockCycles + .name(name() + ".UnblockCycles") + .desc("Number of cycles stage is unblocking") + .prereq(stageUnblockCycles); + stageSquashCycles + .name(name() + ".SquashCycles") + .desc("Number of cycles stage is squashing") + .prereq(stageSquashCycles); + stageProcessedInsts + .name(name() + ".ProcessedInsts") + .desc("Number of instructions handled by stage") + .prereq(stageProcessedInsts); + stageSquashedInsts + .name(name() + ".SquashedInsts") + .desc("Number of squashed instructions handled by stage") + .prereq(stageSquashedInsts);*/ +} + + +void +PipelineStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + dummyBufferInst = new InOrderDynInst(cpu_ptr, NULL, 0, 0); + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); + + tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer()); +} + + +void +PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(InOrderStage, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to write information back to fetch. + toPrevStages = timeBuffer->getWire(0); + + // Create wires to get information from proper places in time buffer. + fromNextStages = timeBuffer->getWire(-1); +} + + +void +PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n"); + prevStageQueue = prev_stage_ptr; + + // Setup wire to read information from fetch queue. + prevStage = prevStageQueue->getWire(-1); + + prevStageValid = true; +} + + + +void +PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting next stage pointer.\n"); + nextStageQueue = next_stage_ptr; + + // Setup wire to write information to proper place in stage queue. + nextStage = nextStageQueue->getWire(0); + nextStage->size = 0; + nextStageValid = true; +} + + + +void +PipelineStage::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(InOrderStage, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +/*inline void +PipelineStage::switchToActive() +{ + if (_status == Inactive) { + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + + _status = Active; + } +}*/ + +void +PipelineStage::switchOut() +{ + // Stage can immediately switch out. + panic("Switching Out of Stages Unimplemented"); +} + + +void +PipelineStage::takeOverFrom() +{ + _status = Inactive; + + // Be sure to reset state and clear out any old instructions. + for (int i = 0; i < numThreads; ++i) { + stageStatus[i] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[i].stage[stNum] = false; + } + + stalls[i].resources.clear(); + + while (!insts[i].empty()) + insts[i].pop(); + + while (!skidBuffer[i].empty()) + skidBuffer[i].pop(); + } + wroteToTimeBuffer = false; +} + + + +bool +PipelineStage::checkStall(unsigned tid) const +{ + bool ret_val = false; + + // Only check pipeline stall from stage directly following this stage + if (nextStageValid && stalls[tid].stage[stageNum + 1]) { + DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n", + tid, stageNum + 1); + ret_val = true; + } + + if (!stalls[tid].resources.empty()) { + string stall_src; + + for (int i=0; i < stalls[tid].resources.size(); i++) { + stall_src += stalls[tid].resources[i]->res->name() + ":"; + } + + DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n", + tid, stall_src); + ret_val = true; + } + + return ret_val; +} + + +void +PipelineStage::removeStalls(unsigned tid) +{ + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); +} + +inline bool +PipelineStage::prevStageInstsValid() +{ + return prevStage->size > 0; +} + +bool +PipelineStage::isBlocked(unsigned tid) +{ + return stageStatus[tid] == Blocked; +} + +bool +PipelineStage::block(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid); + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + // skidInsert(tid); + + // If the stage status is blocked or unblocking then stage has not yet + // signalled fetch to unblock. In that case, there is no need to tell + // fetch to block. + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + if (prevStageValid) + toPrevStages->stageBlock[stageNum][tid] = true; + wroteToTimeBuffer = true; + } + + return true; + } + + + return false; +} + +void +PipelineStage::blockDueToBuffer(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid); + + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + wroteToTimeBuffer = true; + } + } +} + +bool +PipelineStage::unblock(unsigned tid) +{ + // Stage is done unblocking only if the skid buffer is empty. + if (skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid); + + if (prevStageValid) + toPrevStages->stageUnblock[stageNum][tid] = true; + + wroteToTimeBuffer = true; + + stageStatus[tid] = Running; + + return true; + } + + DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid); + return false; +} + +void +PipelineStage::squashDueToBranch(DynInstPtr &inst, unsigned tid) +{ + if (cpu->squashSeqNum[tid] < inst->seqNum && + cpu->lastSquashCycle[tid] == curTick){ + DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash " + "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]); + } else { + // Send back mispredict information. + toPrevStages->stageInfo[stageNum][tid].branchMispredict = true; + toPrevStages->stageInfo[stageNum][tid].predIncorrect = true; + toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum; + toPrevStages->stageInfo[stageNum][tid].squash = true; + toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg(); + toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() != + (inst->readNextPC() + sizeof(TheISA::MachInst)); + toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg()); + InstSeqNum squash_seq_num = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] " + "branch.\n", tid, squash_seq_num, inst->seqNum); + + // Save squash num for later stage use + cpu->squashSeqNum[tid] = squash_seq_num; + cpu->lastSquashCycle[tid] = curTick; + } +} + +void +PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, + unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from " + "incoming stage queue.\n", tid); + + for (int i=0; i < prevStage->size; i++) { + if (prevStage->insts[i]->threadNumber == tid && + prevStage->insts[i]->seqNum > squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " + "[sn:%i] PC %08p.\n", + tid, + prevStage->insts[i]->seqNum, + prevStage->insts[i]->readPC()); + prevStage->insts[i]->setSquashed(); + } + } +} + +void +PipelineStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + stageStatus[tid] = Squashing; + + squashPrevStageInsts(squash_seq_num, tid); + + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n", + tid); + while (!skidBuffer[tid].empty()) { + if (skidBuffer[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + skidBuffer[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC); + skidBuffer[tid].pop(); + } + +} + +int +PipelineStage::stageBufferAvail() +{ + unsigned total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + int incoming_insts = (prevStageValid) ? + cpu->pipelineStage[stageNum]->prevStage->size : + 0; + + int avail = stageBufferMax - total -0;// incoming_insts; + + if (avail < 0) + fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i", + stageNum, stageBufferMax, total, incoming_insts, avail); + + return avail; +} + +bool +PipelineStage::canSendInstToStage(unsigned stage_num) +{ + bool buffer_avail = false; + + if (cpu->pipelineStage[stage_num]->prevStageValid) { + buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() >= 1; + } + + if (!buffer_avail && nextStageQueueValid(stage_num)) { + DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1); + } + + return buffer_avail; +} + +void +PipelineStage::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop(); + + assert(tid == inst->threadNumber); + + DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", + tid, inst->seqNum, inst->readPC(), inst->threadNumber); + + skidBuffer[tid].push(inst); + } +} + + +int +PipelineStage::skidSize() +{ + int total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + return total; +} + +bool +PipelineStage::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + + + +void +PipelineStage::updateStatus() +{ + bool any_unblocking = false; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (stageStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // Stage will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + } + } else { + // If it's not unblocking, then stage will not have any internal + // activity. Switch it to inactive. + if (_status == Active) { + _status = Inactive; + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(stageNum); + } + } +} + + + +void +PipelineStage::sortInsts() +{ + if (prevStageValid) { + int insts_from_prev_stage = prevStage->size; + + DPRINTF(InOrderStage, "%i insts available from stage buffer %i.\n", + insts_from_prev_stage, prevStageQueue->id()); + + for (int i = 0; i < insts_from_prev_stage; ++i) { + + if (prevStage->insts[i]->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting " + "into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + continue; + } + + DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + int tid = prevStage->insts[i]->threadNumber; + + DynInstPtr inst = prevStage->insts[i]; + + skidBuffer[tid].push(prevStage->insts[i]); + + prevStage->insts[i] = dummyBufferInst; + + } + } +} + + + +void +PipelineStage::readStallSignals(unsigned tid) +{ + for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid]; + stage_idx++) { + + // Check for Stage Blocking Signal + if (fromNextStages->stageBlock[stage_idx][tid]) { + stalls[tid].stage[stage_idx] = true; + } + + // Check for Stage Unblocking Signal + if (fromNextStages->stageUnblock[stage_idx][tid]) { + //assert(fromNextStages->stageBlock[stage_idx][tid]); + stalls[tid].stage[stage_idx] = false; + } + } +} + + + +bool +PipelineStage::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is. + // Check stall signals, block if necessary. + // If status was blocked + // Check if stall conditions have passed + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + + // Update the per thread stall statuses. + readStallSignals(tid); + + // Check for squash from later pipeline stages + for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) { + if (fromNextStages->stageInfo[stage_idx][tid].squash) { + DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash " + "from stage %u.\n", tid, stage_idx); + InstSeqNum squash_seq_num = fromNextStages-> + stageInfo[stage_idx][tid].bdelayDoneSeqNum; + squash(squash_seq_num, tid); + break; //return true; + } + } + + if (checkStall(tid)) { + return block(tid); + } + + if (stageStatus[tid] == Blocked) { + DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + + unblock(tid); + + return true; + } + + if (stageStatus[tid] == Squashing) { + if (!skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + } else { + // Switch status to running if stage isn't being told to block or + // squash this cycle. + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n", + tid); + + stageStatus[tid] = Running; + } + + return true; + } + + // If we've reached this point, we have not gotten any signals that + // cause stage to change its status. Stage remains the same as before.*/ + return false; +} + + + +void +PipelineStage::tick() +{ + wroteToTimeBuffer = false; + + bool status_change = false; + + if (nextStageValid) + nextStage->size = 0; + + toNextStageIndex = 0; + + sortInsts(); + + processStage(status_change); + + if (status_change) { + updateStatus(); + } + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + } + + DPRINTF(InOrderStage, "\n\n"); +} + +void +PipelineStage::setResStall(ResReqPtr res_req, unsigned tid) +{ + DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name()); + stalls[tid].resources.push_back(res_req); +} + +void +PipelineStage::unsetResStall(ResReqPtr res_req, unsigned tid) +{ + // Search through stalls to find stalling request and then + // remove it + vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin(); + vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end(); + + while (req_it != req_end) { + if( (*req_it)->res == res_req->res && // Same Resource + (*req_it)->inst == res_req->inst && // Same Instruction + (*req_it)->getSlot() == res_req->getSlot()) { + DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n", + tid, res_req->res->name()); + stalls[tid].resources.erase(req_it); + break; + } + + req_it++; + } + + if (stalls[tid].resources.size() == 0) { + DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n", + tid); + } +} + +// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled +// one at a time, but instead first come first serve by instruction? +// Questions are how should a pipeline stage handle thread-specific stalls & +// pipeline squashes +void +PipelineStage::processStage(bool &status_change) +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid); + status_change = checkSignalsAndUpdate(tid) || status_change; + + processThread(status_change, tid); + } + + if (nextStageValid) { + DPRINTF(InOrderStage, "%i insts now available for stage %i.\n", + nextStage->size, stageNum + 1); + } + + DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(), + stageNum); + + DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(), + stageNum); +} + +void +PipelineStage::processThread(bool &status_change, unsigned tid) +{ + // If status is Running or idle, + // call stageInsts() + // If status is Unblocking, + // buffer any instructions coming from fetch + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (stageStatus[tid] == Blocked) { + ;//++stageBlockedCycles; + } else if (stageStatus[tid] == Squashing) { + ;//++stageSquashCycles; + } + + // Stage should try to stage as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run " + "stage.\n",tid); + + processInsts(tid); + } else if (stageStatus[tid] == Unblocking) { + // Make sure that the skid buffer has something in it if the + // status is unblocking. + assert(!skidsEmpty()); + + // If the status was unblocking, then instructions from the skid + // buffer were used. Remove those instructions and handle + // the rest of unblocking. + processInsts(tid); + + if (prevStageValid && prevStageInstsValid()) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + } + + status_change = unblock(tid) || status_change; + } +} + + +void +PipelineStage::processInsts(unsigned tid) +{ + // Instructions can come either from the skid buffer or the list of + // instructions coming from fetch, depending on stage's status. + int insts_available = skidBuffer[tid].size(); + + std::queue<DynInstPtr> &insts_to_stage = skidBuffer[tid]; + + if (insts_available == 0) { + DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out" + " early.\n",tid); + // Should I change the status to idle? + //++stageIdleCycles; + return; + } + + DynInstPtr inst; + bool last_req_completed = true; + + int insts_processed = 0; + + while (insts_available > 0 && + insts_processed < stageWidth && + (!nextStageValid || canSendInstToStage(stageNum+1)) && + last_req_completed) { + assert(!insts_to_stage.empty()); + + inst = insts_to_stage.front(); + + DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x\n", + tid, inst->seqNum, inst->readPC()); + + if (inst->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->readPC()); + + //++stageSquashedInsts; + + insts_to_stage.pop(); + + --insts_available; + + continue; + } + + + last_req_completed = processInstSchedule(inst); + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + if (!last_req_completed) + continue; + + // Send to Next Stage or Break Loop + if (nextStageValid && !sendInstToNextStage(inst)) { + DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n", + tid, inst->seqNum,inst->nextStage); + break; + } + + insts_processed++; + + insts_to_stage.pop(); + + //++stageProcessedInsts; + --insts_available; + } + + // If we didn't process all instructions, then we will need to block + // and put all those instructions into the skid buffer. + if (!insts_to_stage.empty()) { + blockDueToBuffer(tid); + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +bool +PipelineStage::processInstSchedule(DynInstPtr inst) +{ + bool last_req_completed = true; + int tid; + + tid = inst->readTid(); + + if (inst->nextResStage() == stageNum) { + int res_stage_num = inst->nextResStage(); + + while (res_stage_num == stageNum) { + int res_num = inst->nextResource(); + + + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + ResReqPtr req = cpu->resPool->request(res_num, inst); + + if (req->isCompleted()) { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + if (req->fault == NoFault) { + inst->popSchedEntry(); + } else { + panic("%i: encountered %s fault!\n", + curTick, req->fault->name()); + } + } else { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + last_req_completed = false; + + break; + } + + res_stage_num = inst->nextResStage(); + } + } else { + DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x " + " needed no resources in stage %i.\n", + tid, inst->seqNum, inst->readPC(), stageNum); + } + + return last_req_completed; +} + +bool +PipelineStage::nextStageQueueValid(int stage_num) +{ + return cpu->pipelineStage[stage_num]->nextStageValid; +} + + +bool +PipelineStage::sendInstToNextStage(DynInstPtr inst) +{ + // Update Next Stage Variable in Instruction + // NOTE: Some Resources will update this nextStage var. to + // for bypassing, so can't always assume nextStage=stageNum+1 + if (inst->nextStage == stageNum) + inst->nextStage++; + + bool success = false; + int tid = inst->readTid(); + int next_stage = inst->nextStage; + int prev_stage = next_stage - 1; + + assert(next_stage >= 1); + assert(prev_stage >= 0); + + DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid, + stageNum+1); + + if (!canSendInstToStage(inst->nextStage)) { + DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid, + stageNum+1); + return false; + } + + + if (nextStageQueueValid(inst->nextStage - 1)) { + if (inst->seqNum > cpu->squashSeqNum[tid] && + curTick == cpu->lastSquashCycle[tid]) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion " + "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage); + } else { + if (nextStageValid) { + DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", + tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); + } + + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " + "index %i of stage buffer %i queue.\n", + tid, inst->seqNum, toNextStageIndex, + cpu->pipelineStage[prev_stage]->nextStageQueue->id()); + + int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size; + + // Place instructions in inter-stage communication struct for the next + // pipeline stage to read next cycle + cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst; + + ++(cpu->pipelineStage[prev_stage]->nextStage->size); + + ++toNextStageIndex; + + success = true; + + // Take note of trace data for this inst & stage + if (inst->traceData) { + inst->traceData->setStageCycle(stageNum, curTick); + } + + } + } + + return success; +} + +void +PipelineStage::dumpInsts() +{ + cprintf("Insts in Stage %i skidbuffers\n",stageNum); + + for (int tid=0; tid < ThePipeline::MaxThreads; tid++) { + + std::queue<DynInstPtr> copy_buff(skidBuffer[tid]); + + while (!copy_buff.empty()) { + DynInstPtr inst = copy_buff.front(); + + cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n", + inst->readPC(), inst->threadNumber, inst->seqNum); + + copy_buff.pop(); + } + } + +} diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh new file mode 100644 index 000000000..b074639fb --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.hh @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_STAGE_HH__ +#define __CPU_INORDER_PIPELINE_STAGE_HH__ + +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class PipelineStage +{ + protected: + typedef ThePipeline::Params Params; + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + /** Overall stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum StageStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking, + MemWaitResponse, + MemWaitRetry, + MemAccessComplete + }; + + protected: + /** The Number of This Pipeline Stage */ + unsigned stageNum; + + /** The width of stage, in instructions. */ + unsigned stageWidth; + + /** Number of Threads*/ + unsigned numThreads; + + /** Stage status. */ + StageStatus _status; + + /** Per-thread status. */ + ThreadStatus stageStatus[ThePipeline::MaxThreads]; + + public: + PipelineStage(Params *params, unsigned stage_num); + + /** MUST use init() function if this constructor is used. */ + PipelineStage() { } + + virtual ~PipelineStage() { } + + /** PipelineStage initialization. */ + void init(Params *params); + + /** Returns the name of stage. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + virtual void setCPU(InOrderCPU *cpu_ptr); + + virtual void scheduleStageStart(int delay, int tid) { } + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Sets pointer to time buffer coming from fetch. */ + void setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + bool nextStageQueueValid(int stage_num); + + bool isBlocked(unsigned tid); + + /** Changes the status of this stage to active, and indicates this + * to the CPU. + */ + //inline void switchToActive(); + + /** Changes the status of this stage to inactive, and indicates + * this to the CPU. + */ + //inline void switchToInactive(); + + /** Switches out the stage stage. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks stage, processing all input signals and executing as many + * instructions as possible. + */ + virtual void tick(); + + /** Set a resource stall in the pipeline-stage */ + void setResStall(ResReqPtr res_req, unsigned tid); + + /** Unset a resource stall in the pipeline-stage */ + void unsetResStall(ResReqPtr res_req, unsigned tid); + + /** Remove all stall signals for a particular thread; */ + virtual void removeStalls(unsigned tid); + + /** Is there room in the stage buffer? */ + int stageBufferAvail(); + + protected: + /** Evaluate Stage Conditions and then process stage */ + virtual void processStage(bool &status_change); + + /** Determines what to do based on stage's current status. + * @param status_change stage() sets this variable if there was a status + * change (ie switching from from blocking to unblocking). + * @param tid Thread id to stage instructions from. + */ + virtual void processThread(bool &status_change, unsigned tid); + + /** Processes instructions from fetch and passes them on to rename. + * Decoding of instructions actually happens when they are created in + * fetch, so this function mostly checks if PC-relative branches are + * correct. + */ + virtual void processInsts(unsigned tid); + + /** Process all resources on an instruction's resource schedule */ + virtual bool processInstSchedule(DynInstPtr inst); + + /** Is there room in the next stage buffer for this instruction? */ + virtual bool canSendInstToStage(unsigned stage_num); + + /** Send an instruction to the next stage buffer */ + virtual bool sendInstToNextStage(DynInstPtr inst); + + /** Inserts a thread's instructions into the skid buffer, to be staged + * once stage unblocks. + */ + virtual void skidInsert(unsigned tid); + + /** Total size of all skid buffers */ + int skidSize(); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall stage status based on all of the threads' statuses. */ + virtual void updateStatus(); + + /** Separates instructions from fetch into individual lists of instructions + * sorted by thread. + */ + void sortInsts(); + + /** Reads all stall signals from the backwards communication timebuffer. */ + virtual void readStallSignals(unsigned tid); + + /** Checks all input signals and updates stage's status appropriately. */ + virtual bool checkSignalsAndUpdate(unsigned tid); + + /** Checks all stall signals, and returns if any are true. */ + virtual bool checkStall(unsigned tid) const; + + /** Returns if there any instructions from the previous stage + * on this cycle. + */ + inline bool prevStageInstsValid(); + + /** Switches stage to blocking, and signals back that stage has + * become blocked. + * @return Returns true if there is a status change. + */ + virtual bool block(unsigned tid); + + void blockDueToBuffer(unsigned tid); + + /** Switches stage to unblocking if the skid buffer is empty, and + * signals back that stage has unblocked. + * @return Returns true if there is a status change. + */ + virtual bool unblock(unsigned tid); + + + public: + /** Squashes if there is a PC-relative branch that was predicted + * incorrectly. Sends squash information back to fetch. + */ + virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid); + + /** Squash instructions from stage buffer */ + virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid); + + /** Squashes due to commit signalling a squash. Changes status to + * squashing and clears block/unblock signals as needed. + */ + virtual void squash(InstSeqNum squash_num, unsigned tid); + + void dumpInsts(); + + protected: + /** CPU interface. */ + InOrderCPU *cpu; + + Trace::InOrderTrace *tracer; + + /** List of active thread ids */ + std::list<unsigned> *activeThreads; + + /** Queue of all instructions coming from previous stage on this cycle. */ + std::queue<DynInstPtr> insts[ThePipeline::MaxThreads]; + + /** Queue of instructions that are finished processing and ready to go next stage. + * This is used to prevent from processing an instrution more than once on any + * stage. NOTE: It is up to the PROGRAMMER must manage this as a queue + */ + std::list<DynInstPtr> instsToNextStage; + + /** Skid buffer between previous stage and this one. */ + std::queue<DynInstPtr> skidBuffer[ThePipeline::MaxThreads]; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */ + Addr bdelayDoneSeqNum[ThePipeline::MaxThreads]; + + /** Instruction used for squashing branch (used for MIPS) */ + DynInstPtr squashInst[ThePipeline::MaxThreads]; + + /** Tells when their is a pending delay slot inst. to send + * to rename. If there is, then wait squash after the next + * instruction (used for MIPS). + */ + bool squashAfterDelaySlot[ThePipeline::MaxThreads]; + + /** Maximum size of the inter-stage buffer connecting the previous stage to + * this stage (which we call a skid buffer) */ + unsigned stageBufferMax; + + /** Variable that tracks if stage has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Index of instructions being sent to the next stage. */ + unsigned toNextStageIndex; + + /** The last stage that this particular stage should look for stalls */ + int lastStallingStage[ThePipeline::MaxThreads]; + + /** Time buffer interface. */ + TimeBuffer<TimeStruct> *timeBuffer; + + public: + /** Wire to get rename's output from backwards time buffer. */ + TimeBuffer<TimeStruct>::wire fromNextStages; + + /** Wire to get iew's information from backwards time buffer. */ + TimeBuffer<TimeStruct>::wire toPrevStages; + + /** Instruction queue linking previous stage */ + TimeBuffer<InterStageStruct> *prevStageQueue; + + /** Wire to get the previous stage's. */ + TimeBuffer<InterStageStruct>::wire prevStage; + + /** Instruction queue linking next stage */ + TimeBuffer<InterStageStruct> *nextStageQueue; + + /** Wire to write to the next stage */ + TimeBuffer<InterStageStruct>::wire nextStage; + + /** Is Previous Stage Valid? */ + bool prevStageValid; + + /** Is Next Stage Valid? */ + bool nextStageValid; + + /** Source of possible stalls. */ + struct Stalls { + bool stage[ThePipeline::NumStages]; + std::vector<ResReqPtr> resources; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[ThePipeline::MaxThreads]; + + //@TODO: Use Stats for the pipeline stages + /** Stat for total number of idle cycles. */ + //Stats::Scalar stageIdleCycles; + /** Stat for total number of blocked cycles. */ + //Stats::Scalar stageBlockedCycles; + /** Stat for total number of normal running cycles. */ + //Stats::Scalar stageRunCycles; + /** Stat for total number of unblocking cycles. */ + //Stats::Scalar stageUnblockCycles; + /** Stat for total number of squashing cycles. */ + //Stats::Scalar stageSquashCycles; + /** Stat for total number of staged instructions. */ + //Stats::Scalar stageProcessedInsts; + /** Stat for total number of squashed instructions. */ + //Stats::Scalar stageSquashedInsts; +}; + +#endif diff --git a/src/cpu/inorder/pipeline_traits.5stage.cc b/src/cpu/inorder/pipeline_traits.5stage.cc new file mode 100644 index 000000000..50c30af1e --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.cc @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // IF - Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB, TLBUnit::FetchLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::InitiateFetch)); + + // + // DE - Stage 1 + // --------------------------------------- + stNum++; stPri = 0; + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::CompleteFetch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode, DecodeUnit::DecodeInst)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred, BranchPredictor::PredictBranch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // EX - Stage 2 + // --------------------------------------- + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr)); + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData)); + } + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + + // + // MEM - Stage 3 + // --------------------------------------- + stPri = 0; stNum++; + if ( inst->isStore() ) { // for store, need src reg at this point + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1)); + } + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData)); + } else if ( inst->isStore() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData)); + } + + // + // WB - Stage 4 + // --------------------------------------- + stPri = 0; stNum++; + if (inst->isNonSpeculative()) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + + if ( inst->isStore() ) + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData)); + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx)); + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst)); + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.5stage.hh b/src/cpu/inorder/pipeline_traits.5stage.hh new file mode 100644 index 000000000..aea6eff37 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.cc b/src/cpu/inorder/pipeline_traits.9stage.cc new file mode 100644 index 000000000..d686bb3bc --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.cc @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + if (inst->readTid() == 0) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass)); + else //if (inst->readTid() == 1) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.hh b/src/cpu/inorder/pipeline_traits.9stage.hh new file mode 100644 index 000000000..91e537366 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> +#include <map> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 2; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map<unsigned, unsigned> stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.cc b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc new file mode 100644 index 000000000..9d2ed8e61 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + int fetch_buff_num = FetchBuff + inst->readTid(); + + inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass)); + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + //if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + //inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + //} else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + //} + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.hh b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh new file mode 100644 index 000000000..22da4ea0f --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> +#include <map> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 2; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map<unsigned, unsigned> stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + MaxThreads * 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + MaxThreads * 4, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + MaxThreads /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc new file mode 100644 index 000000000..eb899452a --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + InstStage *I = inst->addStage(); + InstStage *E = inst->addStage(); + + I->needs(FetchSeq, FetchSeqUnit::AssignNextPC); + I->needs(ITLB, TLBUnit::FetchLookup); + I->needs(ICache, CacheUnit::InitiateFetch); + + E->needs(ICache, CacheUnit::CompleteFetch); + E->needs(Decode, DecodeUnit::DecodeInst); + E->needs(BPred, BranchPredictor::PredictBranch); + E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + InstStage *E = inst->currentStage(); + InstStage *M = inst->addStage(); + InstStage *A = inst->addStage(); + InstStage *W = inst->addStage(); + + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) { + E->needs(RegManager, UseDefUnit::ReadSrcReg, idx); + } + } + + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if ( inst->isMemRef() ) { + E->needs(AGEN, AGENUnit::GenerateAddr); + if ( inst->isLoad() ) { + E->needs(DTLB, TLBUnit::DataLookup); + E->needs(DCache, CacheUnit::InitiateReadData); + } + } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + E->needs(MDU, MultDivUnit::StartMultDiv); + + // ZERO-LATENCY Multiply: + // E->needs(MDU, MultDivUnit::MultDiv); + } else { + E->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + M->needs(MDU, MultDivUnit::EndMultDiv); + } + + if ( inst->isLoad() ) { + M->needs(DCache, CacheUnit::CompleteReadData); + } else if ( inst->isStore() ) { + M->needs(RegManager, UseDefUnit::ReadSrcReg, 1); + M->needs(DTLB, TLBUnit::DataLookup); + M->needs(DCache, CacheUnit::InitiateWriteData); + } + + if ( inst->isStore() ) { + A->needs(DCache, CacheUnit::CompleteWriteData); + } + + if ( inst->isNonSpeculative() ) { + if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); + W->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + for (int idx=0; idx < inst->numDestRegs(); idx++) { + W->needs(RegManager, UseDefUnit::WriteDestReg, idx); + } + + W->needs(Grad, GraduationUnit::GraduateInst); + + return true; +} + +InstStage::InstStage(DynInstPtr inst, int stage_num) +{ + stageNum = stage_num; + nextTaskPriority = 0; + instSched = &inst->resSched; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh new file mode 100644 index 000000000..3c49143bc --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.hh @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include <list> +#include <queue> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/base.hh" + +#include "params/InOrderCPU.hh" + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 8; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + MDU, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr<InOrderDynInst> DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); + + class InstStage { + private: + int nextTaskPriority; + int stageNum; + ResSchedule *instSched; + + public: + InstStage(DynInstPtr inst, int stage_num); + + void needs(int unit, int request) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request + )); + } + + void needs(int unit, int request, int param) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request, param + )); + } + + }; +}; + + + + +#endif diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc new file mode 100644 index 000000000..a405b1fb9 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +RegDepMap::RegDepMap(int size) +{ + regMap.resize(size); +} + +string +RegDepMap::name() +{ + return cpu->name() + ".RegDepMap"; +} + +void +RegDepMap::setCPU(InOrderCPU *_cpu) +{ + cpu = _cpu; +} + +void +RegDepMap::clear() +{ + regMap.clear(); +} + +void +RegDepMap::insert(DynInstPtr inst) +{ + int dest_regs = inst->numDestRegs(); + + DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] " + ", %s (dest. regs = %i).\n", + inst->seqNum, + inst->staticInst->getName(), + dest_regs); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + + //if (inst->numFPDestRegs()) + // idx += TheISA::FP_Base_DepTag; + + insert(idx, inst); + } +} + + +void +RegDepMap::insert(unsigned idx, DynInstPtr inst) +{ + DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n", + inst->seqNum, idx); + + regMap[idx].push_back(inst); + + inst->setRegDepEntry(); +} + +void +RegDepMap::remove(DynInstPtr inst) +{ + if (inst->isRegDepEntry()) { + DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n", + inst->seqNum); + + int dest_regs = inst->numDestRegs(); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + remove(idx, inst); + } + } +} + +void +RegDepMap::remove(unsigned idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + std::list<DynInstPtr>::iterator list_end = regMap[idx].end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + regMap[idx].erase(list_it); + break; + } + + list_it++; + } +} + +void +RegDepMap::removeFront(unsigned idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg." + "%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum); + + assert(list_it != regMap[idx].end()); + + assert(inst == (*list_it)); + + regMap[idx].erase(list_it); +} + +bool +RegDepMap::canRead(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + return false; + } +} + +ThePipeline::DynInstPtr +RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = regMap[reg_idx].begin(); + std::list<DynInstPtr>::iterator list_end = regMap[reg_idx].end(); + + DynInstPtr forward_inst = NULL; + + // Look for first, oldest instruction + while (list_it != list_end && + (*list_it)->seqNum < inst->seqNum) { + forward_inst = (*list_it); + list_it++; + } + + if (forward_inst) { + if (forward_inst->isExecuted() && + forward_inst->readResultTime(src_idx) < curTick) { + return forward_inst; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, " + " [sn:%i] has not been executed yet.\n", + inst->seqNum, forward_inst->seqNum); + return NULL; + } + } else { + DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n", + inst->seqNum); + return NULL; + } +} + +bool +RegDepMap::canWrite(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + } + + return false; +} + +int +RegDepMap::depSize(unsigned idx) +{ + return regMap[idx].size(); +} + +ThePipeline::DynInstPtr +RegDepMap::findBypassInst(unsigned idx) +{ + std::list<DynInstPtr>::iterator list_it = regMap[idx].begin(); + + if (depSize(idx) == 1) + return NULL; + + list_it++; + + while (list_it != regMap[idx].end()) { + if((*list_it)->isExecuted()) { + return *list_it; + break; + } + } + + return NULL; +} diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh new file mode 100644 index 000000000..ba2a8c8a3 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef CPU_INORDER_REG_DEP_MAP_HH +#define CPU_INORDER_REG_DEP_MAP_HH + +#include <list> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class RegDepMap +{ + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + RegDepMap(int size = TheISA::TotalNumRegs); + + ~RegDepMap() { } + + std::string name(); + + void setCPU(InOrderCPU *_cpu); + + /** Clear the Entire Map */ + void clear(); + + /** Insert all of a instruction's destination registers into map*/ + void insert(DynInstPtr inst); + + /** Insert an instruction into a specific destination register index onto map */ + void insert(unsigned idx, DynInstPtr inst); + + /** Remove all of a instruction's destination registers into map*/ + void remove(DynInstPtr inst); + + /** Remove a specific instruction and destination register index from map */ + void remove(unsigned idx, DynInstPtr inst); + + /** Remove Front instruction from a destination register */ + void removeFront(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to read from this destination register? */ + bool canRead(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to get a forwarded value from another instruction + * for this destination register? */ + DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst); + + /** find an instruction to forward/bypass a value from */ + DynInstPtr findBypassInst(unsigned idx); + + /** Is the current instruction able to write to this destination register? */ + bool canWrite(unsigned idx, DynInstPtr inst); + + /** Size of Dependency of Map */ + int depSize(unsigned idx); + + protected: + // Eventually make this a map of lists for + // efficiency sake! + std::vector<std::list<DynInstPtr> > regMap; + + InOrderCPU *cpu; +}; + +#endif + + + + + + + diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc new file mode 100644 index 000000000..3106628f0 --- /dev/null +++ b/src/cpu/inorder/resource.cc @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/cpu.hh" +using namespace std; + +Resource::Resource(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : resName(res_name), id(res_id), + width(res_width), latency(res_latency), cpu(_cpu) +{ + // Use to deny a instruction a resource. + deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0); +} + +void +Resource::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new ResourceEvent[width]; + + initSlots(); +} + +void +Resource::initSlots() +{ + // Add available slot numbers for resource + for (int slot_idx = 0; slot_idx < width; slot_idx++) { + availSlots.push_back(slot_idx); + resourceEvent[slot_idx].init(this, slot_idx); + } +} + +std::string +Resource::name() +{ + return cpu->name() + "." + resName; +} + +void +Resource::regStats() +{ + instReqsProcessed + .name(name() + ".instReqsProcessed") + .desc("Number of Instructions Requests that completed in this resource."); +} + +int +Resource::slotsAvail() +{ + return availSlots.size(); +} + +int +Resource::slotsInUse() +{ + return width - availSlots.size(); +} + +void +Resource::freeSlot(int slot_idx) +{ + DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + slot_idx); + + // Put slot number on this resource's free list + availSlots.push_back(slot_idx); + + // Erase Request Pointer From Request Map + std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx); + + assert(req_it != reqMap.end()); + reqMap.erase(req_it); + +} + +// TODO: More efficiently search for instruction's slot within +// resource. +int +Resource::findSlot(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + int slot_num = -1; + + while (map_it != map_end) { + if ((*map_it).second->getInst()->seqNum == + inst->seqNum) { + slot_num = (*map_it).second->getSlot(); + } + map_it++; + } + + return slot_num; +} + +int +Resource::getSlot(DynInstPtr inst) +{ + int slot_num; + + if (slotsAvail() != 0) { + slot_num = availSlots[0]; + + vector<int>::iterator vect_it = availSlots.begin(); + + assert(slot_num == *vect_it); + + availSlots.erase(vect_it); + } else { + DPRINTF(Resource, "[tid:%i]: No slots in resource " + "available to service [sn:%i].\n", inst->readTid(), + inst->seqNum); + slot_num = -1; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second) { + DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n", + (*map_it).second->getInst()->readTid(), + (*map_it).second->getInst()->seqNum); + } + map_it++; + } + } + + return slot_num; +} + +ResReqPtr +Resource::request(DynInstPtr inst) +{ + // See if the resource is already serving this instruction. + // If so, use that request; + bool try_request = false; + int slot_num; + int stage_num; + ResReqPtr inst_req = findRequest(inst); + + if (inst_req) { + // If some preprocessing has to be done on instruction + // that has already requested once, then handle it here. + // update the 'try_request' variable if we should + // re-execute the request. + requestAgain(inst, try_request); + + slot_num = inst_req->getSlot(); + stage_num = inst_req->getStageNum(); + } else { + // Get new slot # for instruction + slot_num = getSlot(inst); + + if (slot_num != -1) { + // Get Stage # from Schedule Entry + stage_num = inst->resSched.top()->stageNum; + unsigned cmd = inst->resSched.top()->cmd; + + // Generate Resource Request + inst_req = getRequest(inst, stage_num, id, slot_num, cmd); + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n", + inst->readTid()); + } + + reqMap[slot_num] = inst_req; + + try_request = true; + } + } + + if (try_request) { + // Schedule execution of resource + scheduleExecution(slot_num); + } else { + inst_req = deniedReq; + rejectRequest(inst); + } + + return inst_req; +} + +void +Resource::requestAgain(DynInstPtr inst, bool &do_request) +{ + do_request = true; + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n", + inst->readTid()); + } +} + +ResReqPtr +Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new ResourceRequest(this, inst, stage_num, id, slot_num, + cmd); +} + +ResReqPtr +Resource::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second && + (*map_it).second->getInst() == inst) { + return (*map_it).second; + } + map_it++; + } + + return NULL; +} + +void +Resource::rejectRequest(DynInstPtr inst) +{ + DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n", + inst->readTid(), inst->seqNum); +} + +void +Resource::execute(int slot_idx) +{ + DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n", + reqMap[slot_idx]->getTid(), name()); + reqMap[slot_idx]->setCompleted(true); + reqMap[slot_idx]->fault = NoFault; + reqMap[slot_idx]->done(); +} + +void +Resource::deactivateThread(unsigned tid) +{ + // In the most basic case, deactivation means squashing everything + // from a particular thread + DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid); + squash(dummy_inst, 0, 0, tid); +} + +void +Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + std::vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + int req_slot_num = req_ptr->getSlot(); + + unscheduleEvent(req_slot_num); + + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } +} + + +Tick +Resource::ticks(int num_cycles) +{ + return cpu->ticks(num_cycles); +} + + +void +Resource::scheduleExecution(int slot_num) +{ + int res_latency = getLatency(slot_num); + + if (res_latency >= 1) { + scheduleEvent(slot_num, res_latency); + } else { + execute(slot_num); + } +} + +void +Resource::scheduleEvent(int slot_idx, int delay) +{ + DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + cpu->ticks(delay) + curTick); + resourceEvent[slot_idx].scheduleEvent(delay); +} + +bool +Resource::scheduleEvent(DynInstPtr inst, int delay) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].scheduleEvent(delay); + + return slot_idx; +} + +void +Resource::unscheduleEvent(int slot_idx) +{ + resourceEvent[slot_idx].unscheduleEvent(); +} + +bool +Resource::unscheduleEvent(DynInstPtr inst) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].unscheduleEvent(); + + return slot_idx; +} + +int ResourceRequest::resReqID = 0; + +int ResourceRequest::resReqCount = 0; + +void +ResourceRequest::done(bool completed) +{ + DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n", + res->name(), inst->seqNum, inst->readTid()); + + setCompleted(completed); + + // Add to remove list + res->cpu->reqRemoveList.push(res->reqMap[slotNum]); + + // Free Slot So Another Instruction Can Use This Resource + res->freeSlot(slotNum); + + res->instReqsProcessed++; +} + +ResourceEvent::ResourceEvent() + : Event((Event::Priority)Resource_Event_Pri) +{ } + +ResourceEvent::ResourceEvent(Resource *res, int slot_idx) + : Event((Event::Priority)Resource_Event_Pri), resource(res), + slotIdx(slot_idx) +{ } + +void +ResourceEvent::init(Resource *res, int slot_idx) +{ + resource = res; + slotIdx = slot_idx; +} + +void +ResourceEvent::process() +{ + resource->execute(slotIdx); +} + +const char * +ResourceEvent::description() +{ + string desc = resource->name() + " event"; + + return desc.c_str(); +} diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh new file mode 100644 index 000000000..b857e59ed --- /dev/null +++ b/src/cpu/inorder/resource.hh @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_HH__ +#define __CPU_INORDER_RESOURCE_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class ResourceEvent; +class ResourceRequest; + +typedef ResourceRequest ResReq; +typedef ResourceRequest* ResReqPtr; + +class Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + friend class ResourceEvent; + friend class ResourceRequest; + + public: + Resource(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~Resource() {} + + /** Return name of this resource */ + virtual std::string name(); + + /** Define this function if resource, has a port to connect to an outside + * simulation object. + */ + virtual Port* getPort(const std::string &if_name, int idx) { return NULL; } + + /** Return ID for this resource */ + int getId() { return id; } + + /** Any extra initiliazation stuff can be set up using this function that + * should get called before the simulation starts (tick 0) + */ + virtual void init(); + virtual void initSlots(); + + /** Register Stats for this resource */ + virtual void regStats(); + + /** Resources that care about thread activation override this. */ + virtual void activateThread(unsigned tid) { } + + /** Deactivate Thread. Default action is to squash all instructions + * from deactivated thread. + */ + virtual void deactivateThread(unsigned tid); + + /** Resources that care when an instruction has been graduated + * can override this + */ + virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { } + + /** Request usage of this resource. Returns a ResourceRequest object + * with all the necessary resource information + */ + virtual ResourceRequest* request(DynInstPtr inst); + + /** Get the next available slot in this resource. Instruction is passed + * so that resources can check the instruction before allocating a slot + * if necessary. + */ + virtual int getSlot(DynInstPtr inst); + + /** Find the slot that this instruction is using in a resource */ + virtual int findSlot(DynInstPtr inst); + + /** Free a resource slot */ + virtual void freeSlot(int slot_idx); + + /** Request usage of a resource for this instruction. If this instruction already + * has made this request to this resource, and that request is uncompleted + * this function will just return that request + */ + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + /** Schedule Execution of This Resource For A Given Slot*/ + virtual void scheduleExecution(int slot_idx); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + virtual void execute(int slot_idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. Needs to be defined for derived units. + */ + virtual Fault doFetchAccess(DynInstPtr inst) + { panic("doFetchAccess undefined for %s", name()); return NoFault; } + + /** Read/Write on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to do access.Needs to be defined for derived units. + */ + virtual Fault doDataAccess(DynInstPtr inst) + { panic("doDataAccess undefined for %s", name()); return NoFault; } + + /** Squash All Requests After This Seq Num */ + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + /** The number of instructions available that this resource can + * can still process + */ + int slotsAvail(); + + /** The number of instructions using this resource */ + int slotsInUse(); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int slot_idx, int delay); + + /** Find instruction in list, Schedule resource event, regardless of its current state. */ + bool scheduleEvent(DynInstPtr inst, int delay); + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent(int slot_idx); + + /** Unschedule resource event, regardless of its current state. */ + bool unscheduleEvent(DynInstPtr inst); + + /** Return the number of cycles in 'Tick' format */ + Tick ticks(int numCycles); + + /** Find the request that corresponds to this instruction */ + virtual ResReqPtr findRequest(DynInstPtr inst); + + /** */ + virtual void rejectRequest(DynInstPtr inst); + + /** Request a Resource again. Some resources have to special process this + * in subsequent accesses. + */ + virtual void requestAgain(DynInstPtr inst, bool &try_request); + + /** Return Latency of Resource */ + /* Can be overridden for complex cases */ + virtual int getLatency(int slot_num) { return latency; } + + protected: + /** The name of this resource */ + std::string resName; + + /** ID of the resource. The Resource Pool uses this # to identify this + * resource. + */ + int id; + + /** The number of instructions the resource can simultaneously + * process. + */ + int width; + + /** Constant latency for this resource. + * Note: Dynamic latency resources set this to 0 and + * manage the latency themselves + */ + const int latency; + + public: + /** Mapping of slot-numbers to the resource-request pointers */ + std::map<int, ResReqPtr> reqMap; + + /** A list of all the available execution slots for this resource. + * This correlates with the actual resource event idx. + */ + std::vector<int> availSlots; + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + protected: + /** The resource event used for scheduling resource slots on the + * event queue + */ + ResourceEvent *resourceEvent; + + /** Default denied resource request pointer*/ + ResReqPtr deniedReq; + + public: + ///////////////////////////////////////////////////////////////// + // + // DEFAULT RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar instReqsProcessed; +}; + +class ResourceEvent : public Event +{ + public: + /** Pointer to the CPU. */ + Resource *resource; + + + /// Resource events that come before other associated CPU events + /// (for InOrderCPU model). + /// check src/sim/eventq.hh for more event priorities. + enum InOrderPriority { + Resource_Event_Pri = 45, + }; + + /** The Resource Slot that this event is servicing */ + int slotIdx; + + /** Constructs a resource event. */ + ResourceEvent(); + ResourceEvent(Resource *res, int slot_idx); + virtual ~ResourceEvent() { } + + /** Initialize data for this resource event. */ + virtual void init(Resource *res, int slot_idx); + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Set slot idx for event */ + void setSlot(int slot) { slotIdx = slot; } + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int delay) + { + if (squashed()) + mainEventQueue.reschedule(this, curTick + resource->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this, curTick + resource->ticks(delay)); + } + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent() + { + if (scheduled()) + squash(); + } + +}; + +class ResourceRequest +{ + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + static int resReqID; + + static int resReqCount; + + public: + ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, unsigned _cmd) + : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num), + resIdx(res_idx), slotNum(slot_num), completed(false), + squashed(false), processing(false), waiting(false) + { + reqID = resReqID++; + resReqCount++; + DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount); + + if (resReqCount > 100) { + fatal("Too many undeleted resource requests. Memory leak?\n"); + } + } + + virtual ~ResourceRequest() + { + resReqCount--; + DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount); + } + + int reqID; + + /** Acknowledge that this is a request is done and remove + * from resource. + */ + void done(bool completed = true); + + ///////////////////////////////////////////// + // + // GET RESOURCE REQUEST IDENTIFICATION / INFO + // + ///////////////////////////////////////////// + /** Get Resource Index */ + int getResIdx() { return resIdx; } + + /** Get Slot Number */ + int getSlot() { return slotNum; } + + /** Get Stage Number */ + int getStageNum() { return stageNum; } + + /** Set/Get Thread Ids */ + void setTid(unsigned _tid) { tid = _tid; } + int getTid() { return tid; } + + /** Instruction this request is for */ + DynInstPtr getInst() { return inst; } + + /** Data from this request. Overridden by Resource-Specific Request + * Objects + */ + virtual PacketDataPtr getData() { return NULL; } + + /** Pointer to Resource that is being used */ + Resource *res; + + /** Instruction being used */ + DynInstPtr inst; + + /** Fault Associated With This Resource Request */ + Fault fault; + + /** Command For This Resource */ + unsigned cmd; + + //////////////////////////////////////// + // + // GET RESOURCE REQUEST STATUS FROM VARIABLES + // + //////////////////////////////////////// + /** Get/Set Completed variables */ + bool isCompleted() { return completed; } + void setCompleted(bool cond = true) { completed = cond; } + + /** Get/Set Squashed variables */ + bool isSquashed() { return squashed; } + void setSquashed() { squashed = true; } + + /** Get/Set IsProcessing variables */ + bool isProcessing() { return processing; } + void setProcessing() { processing = true; } + + /** Get/Set IsWaiting variables */ + bool isWaiting() { return waiting; } + void setWaiting() { waiting = true; } + + protected: + /** Resource Identification */ + int tid; + int stageNum; + int resIdx; + int slotNum; + + /** Resource Status */ + bool completed; + bool squashed; + bool processing; + bool waiting; +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc new file mode 100644 index 000000000..4a0258e71 --- /dev/null +++ b/src/cpu/inorder/resource_pool.9stage.cc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include <vector> +#include <list> + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + for (int i = 0; i < params->numberOfThreads; i++) { + char fbuff_name[20]; + sprintf(fbuff_name, "Fetch-Buffer-T%i", i); + resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params)); + } + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(&mainEventQueue, CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + reschedule(curTick + resPool->cpu->cycles(delay)); + else if (!scheduled()) + schedule(curTick + resPool->cpu->cycles(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc new file mode 100644 index 000000000..94af68c7a --- /dev/null +++ b/src/cpu/inorder/resource_pool.cc @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include <vector> +#include <list> + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params)); + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name()); + + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name); + + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name, + resources[obj_idx]->name(), obj_idx); + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name); + + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name); + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh new file mode 100644 index 000000000..35fce7db7 --- /dev/null +++ b/src/cpu/inorder/resource_pool.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_POOL_HH__ +#define __CPU_INORDER_RESOURCE_POOL_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/params.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/cpu.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class Resource; +class ResourceEvent; + +class ResourcePool { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + // List of Resource Pool Events that extends + // the list started by the CPU + // NOTE(1): Resource Pool also uses event list + // CPUEventType defined in inorder/cpu.hh + enum ResPoolEventType { + InstGraduated = InOrderCPU::NumCPUEvents, + SquashAll, + Default + }; + + class ResPoolEvent : public Event + { + protected: + /** Resource Pool */ + ResourcePool *resPool; + + public: + InOrderCPU::CPUEventType eventType; + + DynInstPtr inst; + + InstSeqNum seqNum; + + int stageNum; + + unsigned tid; + + public: + /** Constructs a resource event. */ + ResPoolEvent(ResourcePool *_resPool); + + /** Set Type of Event To Be Scheduled */ + void setEvent(InOrderCPU::CPUEventType e_type, + DynInstPtr _inst, + int stage_num, + InstSeqNum seq_num, + unsigned _tid) + { + eventType = e_type; + inst = _inst; + seqNum = seq_num; + stageNum = stage_num; + tid = _tid; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + public: + ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ResourcePool() {} + + std::string name(); + + std::string name(int res_idx) { return resources[res_idx]->name(); } + + void init(); + + /** Register Statistics in All Resources */ + void regStats(); + + /** Returns a specific port. */ + Port* getPort(const std::string &if_name, int idx); + + /** Returns a specific port. */ + unsigned getPortIdx(const std::string &if_name); + + Resource* getResource(int res_idx) { return resources[res_idx]; } + + /** Request usage of this resource. Returns -1 if not granted and + * a positive request tag if granted. + */ + ResReqPtr request(int res_idx, DynInstPtr inst); + + /** Squash The Resource */ + void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid); + + /** Squash All Resources in Pool after Done Seq. Num */ + void squashAll(DynInstPtr inst, int stage_num, + InstSeqNum done_seq_num, unsigned tid); + + /** Activate Thread in all resources */ + void activateAll(unsigned tid); + + /** De-Activate Thread in all resources */ + void deactivateAll(unsigned tid); + + /** Broadcast graduation to all resources */ + void instGraduated(InstSeqNum seq_num,unsigned tid); + + /** The number of instructions available that a resource can + * can still process. + */ + int slotsAvail(int res_idx); + + /** The number of instructions using a resource */ + int slotsInUse(int res_idx); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL, + int delay = 0, int res_idx = 0, int tid = 0); + + /** UnSchedule resource event, regardless of its current state. */ + void unscheduleEvent(int res_idx, DynInstPtr inst); + + /** Tasks to perform when simulation starts */ + virtual void startup() { } + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + DynInstPtr dummyInst[ThePipeline::MaxThreads]; + + private: + std::vector<Resource *> resources; + + std::vector<int> memObjects; + +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc new file mode 100644 index 000000000..f462b12ea --- /dev/null +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/agen_unit.hh" + +AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +AGENUnit::execute(int slot_num) +{ + ResourceRequest* agen_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid; + int seq_num = inst->seqNum; + + tid = inst->readTid(); + agen_req->fault = NoFault; + + switch (agen_req->cmd) + { + case GenerateAddr: + { + // Load/Store Instruction + if (inst->isMemRef()) { + DPRINTF(InOrderAGEN, "[tid:%i] Generating Address for [sn:%i] (%s).\n", + tid, inst->seqNum, inst->staticInst->getName()); + + + // We are not handdling Prefetches quite yet + if (inst->isDataPrefetch() || inst->isInstPrefetch()) { + panic("Prefetches arent handled yet.\n"); + } else { + if (inst->isLoad()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + //inst->setExecuted(); + + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else if (inst->isStore()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else { + panic("Unexpected memory type!\n"); + } + + if (fault == NoFault) { + agen_req->done(); + } else { + fatal("%s encountered @ [sn:%i]",fault->name(), seq_num); + } + } + } else { + DPRINTF(InOrderAGEN, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num); + agen_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} diff --git a/src/base/annotate.hh b/src/cpu/inorder/resources/agen_unit.hh index 36607bf90..2010c9fa6 100644 --- a/src/base/annotate.hh +++ b/src/cpu/inorder/resources/agen_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,49 +25,40 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Ali Saidi + * Authors: Korey Sewell + * */ -#ifndef __BASE__ANNOTATE_HH__ -#define __BASE__ANNOTATE_HH__ - -#include "sim/host.hh" +#ifndef __CPU_INORDER_AGEN_UNIT_HH__ +#define __CPU_INORDER_AGEN_UNIT_HH__ -#include <string> +#include <vector> #include <list> -#include <map> - - -class System; +#include <string> -namespace Annotate { +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/params.hh" +class AGENUnit : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; -class Annotate { + public: + AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~AGENUnit() {} - protected: - struct AnnotateData { - Tick time; - std::string system; - Addr stack; - uint32_t stateMachine; - uint32_t curState; - uint32_t waitMachine; - uint32_t waitState; + enum Command { + GenerateAddr }; - std::list<AnnotateData*> data; - std::map<System*, std::string> nameCache; + virtual void execute(int slot_num); - public: - Annotate(); - void add(System *sys, Addr stack, uint32_t sm, uint32_t st, uint32_t - wm, uint32_t ws); - void dump(); + protected: + /** @todo: Add Resource Stats Here */ }; -extern Annotate annotations; -} //namespace Annotate - -#endif //__BASE__ANNOTATE_HH__ - +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc new file mode 100644 index 000000000..66d0779a2 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.cc @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include <list> +#include <vector> + +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/inorder/resources/bpred_unit.hh" + +using namespace std; +using namespace ThePipeline; + +BPredUnit::BPredUnit(ThePipeline::Params *params) + : BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) +{ + // Setup the selected predictor. + if (params->predType == "local") { + localBP = new LocalBP(params->localPredictorSize, + params->localCtrBits, + params->instShiftAmt); + predictor = Local; + } else if (params->predType == "tournament") { + tournamentBP = new TournamentBP(params->localPredictorSize, + params->localCtrBits, + params->localHistoryTableSize, + params->localHistoryBits, + params->globalPredictorSize, + params->globalHistoryBits, + params->globalCtrBits, + params->choicePredictorSize, + params->choiceCtrBits, + params->instShiftAmt); + predictor = Tournament; + } else { + fatal("Invalid BP selected!"); + } + + for (int i=0; i < ThePipeline::MaxThreads; i++) + RAS[i].init(params->RASSize); +} + + +void +BPredUnit::regStats() +{ + lookups + .name(name() + ".BPredUnit.lookups") + .desc("Number of BP lookups") + ; + + condPredicted + .name(name() + ".BPredUnit.condPredicted") + .desc("Number of conditional branches predicted") + ; + + condIncorrect + .name(name() + ".BPredUnit.condIncorrect") + .desc("Number of conditional branches incorrect") + ; + + BTBLookups + .name(name() + ".BPredUnit.BTBLookups") + .desc("Number of BTB lookups") + ; + + BTBHits + .name(name() + ".BPredUnit.BTBHits") + .desc("Number of BTB hits") + ; + + BTBCorrect + .name(name() + ".BPredUnit.BTBCorrect") + .desc("Number of correct BTB predictions (this stat may not " + "work properly.") + ; + + usedRAS + .name(name() + ".BPredUnit.usedRAS") + .desc("Number of times the RAS was used to get a target.") + ; + + RASIncorrect + .name(name() + ".BPredUnit.RASInCorrect") + .desc("Number of incorrect RAS predictions.") + ; +} + + +void +BPredUnit::switchOut() +{ + // Clear any state upon switch out. + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + squash(0, i); + } +} + + +void +BPredUnit::takeOverFrom() +{ + // Can reset all predictor state, but it's not necessarily better + // than leaving it be. +/* + for (int i = 0; i < ThePipeline::MaxThreads; ++i) + RAS[i].reset(); + + BP.reset(); + BTB.reset(); +*/ +} + + +bool +BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid) +{ + // See if branch predictor predicts taken. + // If so, get its target addr either from the BTB or the RAS. + // Save off record of branch stuff so the RAS can be fixed + // up once it's done. + + using TheISA::MachInst; + + bool pred_taken = false; + Addr target; + + ++lookups; + + void *bp_history = NULL; + + if (inst->isUncondCtrl()) { + DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid); + pred_taken = true; + // Tell the BP there was an unconditional branch. + BPUncond(bp_history); + + if (inst->isReturn() && RAS[tid].empty()) { + DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting " + "false.\n", tid); + pred_taken = false; + } + } else { + ++condPredicted; + + pred_taken = BPLookup(PC, bp_history); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i " + "for PC %#x\n", + tid, pred_taken, inst->readPC()); + } + + PredictorHistory predict_record(inst->seqNum, PC, pred_taken, + bp_history, tid); + + // Now lookup in the BTB or RAS. + if (pred_taken) { + if (inst->isReturn()) { + ++usedRAS; + + // If it's a function return call, then look up the address + // in the RAS. + target = RAS[tid].top(); + + // Record the top entry of the RAS, and its index. + predict_record.usedRAS = true; + predict_record.RASIndex = RAS[tid].topIdx(); + predict_record.RASTarget = target; + + assert(predict_record.RASIndex < 16); + + RAS[tid].pop(); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, " + "RAS predicted target: %#x, RAS index: %i.\n", + tid, inst->readPC(), target, predict_record.RASIndex); + } else { + ++BTBLookups; + + if (inst->isCall()) { + RAS[tid].push(PC + sizeof(MachInst)); + + // Record that it was a call so that the top RAS entry can + // be popped off if the speculation is incorrect. + predict_record.wasCall = true; + + DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call" + ", adding %#x to the RAS.\n", + tid, inst->readPC(), PC + sizeof(MachInst)); + } + + if (inst->isCall() && + inst->isUncondCtrl() && + inst->isDirectCtrl()) { + target = inst->branchTarget(); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted" + " target to %#x.\n", + tid, inst->readPC(), target); + } else if (BTB.valid(PC, tid)) { + ++BTBHits; + + // If it's not a return, use the BTB to get the target addr. + target = BTB.lookup(PC, tid); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted" + " target is %#x.\n", + tid, inst->readPC(), target); + } else { + DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a " + "valid entry.\n",tid); + pred_taken = false; + } + } + } + + if (pred_taken) { + // Set the PC and the instruction's predicted target. + PC = target; + inst->setPredTarg(target); + } else { + PC = PC + sizeof(MachInst); + inst->setPredTarg(PC); + } + + predHist[tid].push_front(predict_record); + + DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); + + inst->setBranchPred(pred_taken); + + return pred_taken; +} + + +void +BPredUnit::update(const InstSeqNum &done_sn, unsigned tid) +{ + DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence" + "number %lli.\n", tid, done_sn); + + while (!predHist[tid].empty() && + predHist[tid].back().seqNum <= done_sn) { + // Update the branch predictor with the correct results. + BPUpdate(predHist[tid].back().PC, + predHist[tid].back().predTaken, + predHist[tid].back().bpHistory); + + predHist[tid].pop_back(); + } +} + + +void +BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid) +{ + History &pred_hist = predHist[tid]; + + while (!pred_hist.empty() && + pred_hist.front().seqNum > squashed_sn) { + if (pred_hist.front().usedRAS) { + DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i," + " target: %#x.\n", + tid, + pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + RAS[tid].restore(pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + } else if (pred_hist.front().wasCall) { + DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry " + "added to the RAS.\n",tid); + + RAS[tid].pop(); + } + + // This call should delete the bpHistory. + BPSquash(pred_hist.front().bpHistory); + + pred_hist.pop_front(); + } + +} + + +void +BPredUnit::squash(const InstSeqNum &squashed_sn, + const Addr &corr_target, + const bool actually_taken, + unsigned tid) +{ + // Now that we know that a branch was mispredicted, we need to undo + // all the branches that have been seen up until this branch and + // fix up everything. + + History &pred_hist = predHist[tid]; + + ++condIncorrect; + + DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, " + "setting target to %#x.\n", + tid, squashed_sn, corr_target); + + squash(squashed_sn, tid); + + // If there's a squash due to a syscall, there may not be an entry + // corresponding to the squash. In that case, don't bother trying to + // fix up the entry. + if (!pred_hist.empty()) { + assert(pred_hist.front().seqNum == squashed_sn); + if (pred_hist.front().usedRAS) { + ++RASIncorrect; + } + + BPUpdate(pred_hist.front().PC, actually_taken, + pred_hist.front().bpHistory); + + BTB.update(pred_hist.front().PC, corr_target, tid); + pred_hist.pop_front(); + } +} + + +void +BPredUnit::BPUncond(void * &bp_history) +{ + // Only the tournament predictor cares about unconditional branches. + if (predictor == Tournament) { + tournamentBP->uncondBr(bp_history); + } +} + + +void +BPredUnit::BPSquash(void *bp_history) +{ + if (predictor == Local) { + localBP->squash(bp_history); + } else if (predictor == Tournament) { + tournamentBP->squash(bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +bool +BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history) +{ + if (predictor == Local) { + return localBP->lookup(inst_PC, bp_history); + } else if (predictor == Tournament) { + return tournamentBP->lookup(inst_PC, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history) +{ + if (predictor == Local) { + localBP->update(inst_PC, taken, bp_history); + } else if (predictor == Tournament) { + tournamentBP->update(inst_PC, taken, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::dump() +{ + /*typename History::iterator pred_hist_it; + + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + if (!predHist[i].empty()) { + pred_hist_it = predHist[i].begin(); + + cprintf("predHist[%i].size(): %i\n", i, predHist[i].size()); + + while (pred_hist_it != predHist[i].end()) { + cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, " + "bpHistory:%#x\n", + (*pred_hist_it).seqNum, (*pred_hist_it).PC, + (*pred_hist_it).tid, (*pred_hist_it).predTaken, + (*pred_hist_it).bpHistory); + pred_hist_it++; + } + + cprintf("\n"); + } + }*/ +} diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh new file mode 100644 index 000000000..bd68459d1 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.hh @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_BPRED_UNIT_HH__ +#define __CPU_INORDER_BPRED_UNIT_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "cpu/inst_seq.hh" + +//#include "cpu/inorder/params.hh" +#include "cpu/o3/2bit_local_pred.hh" +#include "cpu/o3/btb.hh" +#include "cpu/o3/ras.hh" +#include "cpu/o3/tournament_pred.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" + +#include <list> + +/** + * Basically a wrapper class to hold both the branch predictor + * and the BTB. + */ +class BPredUnit +{ + private: + + enum PredType { + Local, + Tournament + }; + + PredType predictor; + + public: + + /** + * @param params The params object, that has the size of the BP and BTB. + */ + BPredUnit(ThePipeline::Params *params); + + /** + * Registers statistics. + */ + void regStats(); + + void switchOut(); + + void takeOverFrom(); + + /** + * Predicts whether or not the instruction is a taken branch, and the + * target of the branch if it is taken. + * @param inst The branch instruction. + * @param PC The predicted PC is passed back through this parameter. + * @param tid The thread id. + * @return Returns if the branch is taken or not. + */ + bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid); + + // @todo: Rename this function. + void BPUncond(void * &bp_history); + + /** + * Tells the branch predictor to commit any updates until the given + * sequence number. + * @param done_sn The sequence number to commit any older updates up until. + * @param tid The thread id. + */ + void update(const InstSeqNum &done_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number, and + * corrects that sn's update with the proper address and taken/not taken. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param corr_target The correct branch target. + * @param actually_taken The correct branch direction. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, + bool actually_taken, unsigned tid); + + /** + * @param bp_history Pointer to the history object. The predictor + * will need to update any state and delete the object. + */ + void BPSquash(void *bp_history); + + /** + * Looks up a given PC in the BP to see if it is taken or not taken. + * @param inst_PC The PC to look up. + * @param bp_history Pointer that will be set to an object that + * has the branch predictor state associated with the lookup. + * @return Whether the branch is taken or not taken. + */ + bool BPLookup(Addr &inst_PC, void * &bp_history); + + /** + * Looks up a given PC in the BTB to see if a matching entry exists. + * @param inst_PC The PC to look up. + * @return Whether the BTB contains the given PC. + */ + bool BTBValid(Addr &inst_PC) + { return BTB.valid(inst_PC, 0); } + + /** + * Looks up a given PC in the BTB to get the predicted target. + * @param inst_PC The PC to look up. + * @return The address of the target of the branch. + */ + Addr BTBLookup(Addr &inst_PC) + { return BTB.lookup(inst_PC, 0); } + + /** + * Updates the BP with taken/not taken information. + * @param inst_PC The branch's PC that will be updated. + * @param taken Whether the branch was taken or not taken. + * @param bp_history Pointer to the branch predictor state that is + * associated with the branch lookup that is being updated. + * @todo Make this update flexible enough to handle a global predictor. + */ + void BPUpdate(Addr &inst_PC, bool taken, void *bp_history); + + /** + * Updates the BTB with the target of a branch. + * @param inst_PC The branch's PC that will be updated. + * @param target_PC The branch's target that will be added to the BTB. + */ + void BTBUpdate(Addr &inst_PC, Addr &target_PC) + { BTB.update(inst_PC, target_PC,0); } + + void dump(); + + private: + struct PredictorHistory { + /** + * Makes a predictor history struct that contains any + * information needed to update the predictor, BTB, and RAS. + */ + PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, + const bool pred_taken, void *bp_history, + const unsigned _tid) + : seqNum(seq_num), PC(inst_PC), RASTarget(0), + RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), + wasCall(0), bpHistory(bp_history) + { } + + /** The sequence number for the predictor history entry. */ + InstSeqNum seqNum; + + /** The PC associated with the sequence number. */ + Addr PC; + + /** The RAS target (only valid if a return). */ + Addr RASTarget; + + /** The RAS index of the instruction (only valid if a call). */ + unsigned RASIndex; + + /** The thread id. */ + unsigned tid; + + /** Whether or not it was predicted taken. */ + bool predTaken; + + /** Whether or not the RAS was used. */ + bool usedRAS; + + /** Whether or not the instruction was a call. */ + bool wasCall; + + /** Pointer to the history object passed back from the branch + * predictor. It is used to update or restore state of the + * branch predictor. + */ + void *bpHistory; + }; + + typedef std::list<PredictorHistory> History; + + /** + * The per-thread predictor history. This is used to update the predictor + * as instructions are committed, or restore it to the proper state after + * a squash. + */ + History predHist[ThePipeline::MaxThreads]; + + /** The local branch predictor. */ + LocalBP *localBP; + + /** The tournament branch predictor. */ + TournamentBP *tournamentBP; + + /** The BTB. */ + DefaultBTB BTB; + + /** The per-thread return address stack. */ + ReturnAddrStack RAS[ThePipeline::MaxThreads]; + + /** Stat for number of BP lookups. */ + Stats::Scalar lookups; + /** Stat for number of conditional branches predicted. */ + Stats::Scalar condPredicted; + /** Stat for number of conditional branches predicted incorrectly. */ + Stats::Scalar condIncorrect; + /** Stat for number of BTB lookups. */ + Stats::Scalar BTBLookups; + /** Stat for number of BTB hits. */ + Stats::Scalar BTBHits; + /** Stat for number of times the BTB is correct. */ + Stats::Scalar BTBCorrect; + /** Stat for number of times the RAS is used to get a target. */ + Stats::Scalar usedRAS; + /** Stat for number of times the RAS is incorrect. */ + Stats::Scalar RASIncorrect; +}; + +#endif // __CPU_INORDER_BPRED_UNIT_HH__ diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc new file mode 100644 index 000000000..511a0ac82 --- /dev/null +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/branch_predictor.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + branchPred(params) +{ + instSize = sizeof(MachInst); +} + +void +BranchPredictor::regStats() +{ + predictedTaken + .name(name() + ".predictedTaken") + .desc("Number of Branches Predicted As Taken (True)."); + + predictedNotTaken + .name(name() + ".predictedNotTaken") + .desc("Number of Branches Predicted As Not Taken (False)."); + + Resource::regStats(); +} + +void +BranchPredictor::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* bpred_req = reqMap[slot_num]; + + DynInstPtr inst = bpred_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + //int stage_num = bpred_req->getStageNum(); + + bpred_req->fault = NoFault; + + switch (bpred_req->cmd) + { + case PredictBranch: + { + Addr pred_PC = inst->readNextPC(); + + if (inst->isControl()) { + // If predicted, the pred_PC will be updated to new target value + // If not, the pred_PC be updated to pc+8 + bool predict_taken = branchPred.predict(inst, pred_PC, tid); + + if (predict_taken) { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n", + tid, seq_num); + + inst->setPredTarg(pred_PC); + + predictedTaken++; + } else { + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n", + tid, seq_num); + + if (inst->isCondDelaySlot()) + { + inst->setPredTarg(inst->readPC() + (2 * instSize)); + } else { + inst->setPredTarg(pred_PC); + } + + predictedNotTaken++; + } + + inst->setBranchPred(predict_taken); + + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n", + tid, seq_num, pred_PC); + + } else { + DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't " + "a control instruction.\n", tid, seq_num); + } + + bpred_req->done(); + } + break; + + case UpdatePredictor: + { + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n", + tid, seq_num); + + + branchPred.update(seq_num, tid); + + bpred_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +BranchPredictor::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderBPred, "Squashing...\n"); + branchPred.squash(squash_seq_num, tid); +} + +void +BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + branchPred.update(seq_num, tid); +} diff --git a/src/dev/x86/opteron.cc b/src/cpu/inorder/resources/branch_predictor.hh index ba46f2dfa..47053910d 100644 --- a/src/dev/x86/opteron.cc +++ b/src/cpu/inorder/resources/branch_predictor.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,85 +25,62 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Korey Sewell + * */ -/** @file - * Implementation of Opteron platform. - */ +#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__ +#define __CPU_INORDER_BRANCH_PREDICTOR_HH__ -#include <deque> -#include <string> #include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/bpred_unit.hh" +#include "cpu/inorder/cpu.hh" -#include "arch/x86/x86_traits.hh" -#include "cpu/intr_control.hh" -#include "dev/simconsole.hh" -#include "dev/x86/opteron.hh" -#include "sim/system.hh" +class BranchPredictor : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; -using namespace std; -using namespace TheISA; + public: + enum Command { + PredictBranch, + UpdatePredictor + }; -Opteron::Opteron(const Params *p) - : Platform(p), system(p->system) -{ - // set the back pointer from the system to myself - system->platform = this; -} + public: + BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); -Tick -Opteron::intrFrequency() -{ - panic("Need implementation\n"); - M5_DUMMY_RETURN -} + virtual void regStats(); -void -Opteron::postConsoleInt() -{ - warn_once("Don't know what interrupt to post for console.\n"); - //panic("Need implementation\n"); -} + virtual void execute(int slot_num); -void -Opteron::clearConsoleInt() -{ - warn_once("Don't know what interrupt to clear for console.\n"); - //panic("Need implementation\n"); -} + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); -void -Opteron::postPciInt(int line) -{ - panic("Need implementation\n"); -} + virtual void instGraduated(InstSeqNum seq_num,unsigned tid); -void -Opteron::clearPciInt(int line) -{ - panic("Need implementation\n"); -} + protected: + /** List of instructions this resource is currently + * processing. + */ + BPredUnit branchPred; -Addr -Opteron::pciToDma(Addr pciAddr) const -{ - panic("Need implementation\n"); - M5_DUMMY_RETURN -} + int instSize; + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar predictedTaken; + Stats::Scalar predictedNotTaken; -Addr -Opteron::calcConfigAddr(int bus, int dev, int func) -{ - assert(func < 8); - assert(dev < 32); - assert(bus == 0); - return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11)); -} +}; -Opteron * -OpteronParams::create() -{ - return new Opteron(this); -} +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc new file mode 100644 index 000000000..57bcb10ef --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "arch/mips/locked_mem.hh" +#include "arch/utility.hh" +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "mem/request.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +Tick +CacheUnit::CachePort::recvAtomic(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvAtomic callback!"); + return curTick; +} + +void +CacheUnit::CachePort::recvFunctional(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvFunctional callback!"); +} + +void +CacheUnit::CachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("DefaultFetch doesn't expect recvStatusChange callback!"); +} + +bool +CacheUnit::CachePort::recvTiming(Packet *pkt) +{ + cachePortUnit->processCacheCompletion(pkt); + return true; +} + +void +CacheUnit::CachePort::recvRetry() +{ + cachePortUnit->recvRetry(); +} + +CacheUnit::CacheUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + retryPkt(NULL), retrySlot(-1), cacheBlocked(false) +{ + cachePort = new CachePort(this); +} + +Port * +CacheUnit::getPort(const string &if_name, int idx) +{ + if (if_name == resName) + return cachePort; + else + return NULL; +} + +int +CacheUnit::getSlot(DynInstPtr inst) +{ + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access\n"); + } + + Addr req_addr = inst->getMemAddr(); + + if (resName == "icache_port" || + find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) { + + int new_slot = Resource::getSlot(inst); + + if (new_slot == -1) + return -1; + + inst->memTime = curTick; + addrList.push_back(req_addr); + addrMap[req_addr] = inst->seqNum; + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", + inst->readTid(), inst->seqNum, req_addr); + return new_slot; + } else { + DPRINTF(InOrderCachePort, + "Denying request because there is an outstanding" + " request to/for addr. %08p. by [sn:%i] @ tick %i\n", + req_addr, addrMap[req_addr], inst->memTime); + return -1; + } +} + +void +CacheUnit::freeSlot(int slot_num) +{ + vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(), + reqMap[slot_num]->inst->getMemAddr()); + assert(vect_it != addrList.end()); + + DPRINTF(InOrderCachePort, + "[tid:%i]: Address %08p removed from dependency list\n", + reqMap[slot_num]->inst->readTid(), (*vect_it)); + + addrList.erase(vect_it); + + Resource::freeSlot(slot_num); +} + +ResReqPtr +CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + ScheduleEntry* sched_entry = inst->resSched.top(); + + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access\n"); + } + + int req_size = 0; + MemCmd::Command pkt_cmd; + + if (sched_entry->cmd == InitiateReadData) { + pkt_cmd = MemCmd::ReadReq; + req_size = inst->getMemAccSize(); + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateWriteData) { + pkt_cmd = MemCmd::WriteReq; + req_size = inst->getMemAccSize(); + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateFetch){ + pkt_cmd = MemCmd::ReadReq; + req_size = sizeof(MachInst); //@TODO: mips16e + + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else { + panic("%i: Unexpected request type (%i) to %s", curTick, + sched_entry->cmd, name()); + } + + return new CacheRequest(this, inst, stage_num, id, slot_num, + sched_entry->cmd, req_size, pkt_cmd, + 0/*flags*/, this->cpu->readCpuId()); +} + +void +CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) +{ + //service_request = false; + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst)); + assert(cache_req); + + // Check to see if this instruction is requesting the same command + // or a different one + if (cache_req->cmd != inst->resSched.top()->cmd) { + // If different, then update command in the request + cache_req->cmd = inst->resSched.top()->cmd; + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: the command for this instruction\n", + inst->readTid(), inst->seqNum); + + service_request = true; + } else { + // If same command, just check to see if memory access was completed + // but dont try to re-execute + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: requesting this resource again\n", + inst->readTid(), inst->seqNum); + + service_request = true; + } +} + +void +CacheUnit::execute(int slot_num) +{ + if (cacheBlocked) { + DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access\n"); + return; + } + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]); + assert(cache_req); + + DynInstPtr inst = cache_req->inst; + int tid; + tid = inst->readTid(); + int seq_num; + seq_num = inst->seqNum; + //int stage_num = cache_req->getStageNum(); + + cache_req->fault = NoFault; + + switch (cache_req->cmd) + { + case InitiateFetch: + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating fetch access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: Fetching new cache block from addr: %08p\n", + tid, cache_req->memReq->getVaddr()); + + inst->setCurResSlot(slot_num); + doDataAccess(inst); + break; + + case CompleteFetch: + if (cache_req->isMemAccComplete()) { + DPRINTF(InOrderCachePort, + "[tid:%i]: Completing Fetch Access for [sn:%i]\n", + tid, inst->seqNum); + + MachInst mach_inst = cache_req->dataPkt->get<MachInst>(); + + /** + * @TODO: May Need This Function for Endianness-Compatibility + * mach_inst = + * gtoh(*reinterpret_cast<MachInst *>(&cacheData[tid][offset])); + */ + + DPRINTF(InOrderCachePort, + "[tid:%i]: Fetched instruction is %08p\n", + tid, mach_inst); + + // ExtMachInst ext_inst = makeExtMI(mach_inst, cpu->tcBase(tid)); + + inst->setMachInst(mach_inst); + inst->setASID(tid); + inst->setThreadState(cpu->thread[tid]); + + DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n", + tid, seq_num, inst->staticInst->disassemble(inst->PC)); + + // Set Up More TraceData info + if (inst->traceData) { + inst->traceData->setStaticInst(inst->staticInst); + inst->traceData->setPC(inst->readPC()); + } + + cache_req->done(); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n", + tid, inst->seqNum); + DPRINTF(InOrderStall, + "STALL: [tid:%i]: Fetch miss from %08p\n", + tid, cache_req->inst->readPC()); + cache_req->setCompleted(false); + } + break; + + case InitiateReadData: + case InitiateWriteData: + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating data access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + inst->setCurResSlot(slot_num); + //inst->memAccess(); + inst->initiateAcc(); + break; + + case CompleteReadData: + case CompleteWriteData: + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n", + tid, inst->seqNum); + if (cache_req->isMemAccComplete()) { + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->getMemAddr()); + cache_req->setCompleted(false); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +Fault +CacheUnit::doDataAccess(DynInstPtr inst) +{ + Fault fault = NoFault; + int tid = 0; + + tid = inst->readTid(); + + CacheReqPtr cache_req + = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]); + assert(cache_req); + + cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd, + Packet::Broadcast); + + if (cache_req->dataPkt->isRead()) { + cache_req->dataPkt->dataStatic(cache_req->reqData); + } else if (cache_req->dataPkt->isWrite()) { + cache_req->dataPkt->dataStatic(&cache_req->inst->storeData); + + } + + cache_req->dataPkt->time = curTick; + + bool do_access = true; // flag to suppress cache access + + Request *memReq = cache_req->dataPkt->req; + + if (cache_req->dataPkt->isWrite() && memReq->isLocked()) { + assert(cache_req->inst->isStoreConditional()); + DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n"); + do_access = TheISA::handleLockedWrite(cpu, memReq); + } + + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] attempting to access cache\n", + tid, inst->seqNum); + + //@TODO: If you want to ignore failed store conditional accesses, then + // enable this. However, this might skew memory stats because + // the failed store conditional access will get ignored. + // - Remove optionality here ... + if (1/*do_access*/) { + if (!cachePort->sendTiming(cache_req->dataPkt)) { + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is waiting to retry request\n", + tid, inst->seqNum); + + retrySlot = cache_req->getSlot(); + retryReq = cache_req; + retryPkt = cache_req->dataPkt; + + cacheStatus = cacheWaitRetry; + + //cacheBlocked = true; + + DPRINTF(InOrderStall, "STALL: \n"); + + cache_req->setCompleted(false); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is now waiting for cache response\n", + tid, inst->seqNum); + cache_req->setCompleted(); + cache_req->setMemAccPending(); + cacheStatus = cacheWaitResponse; + cacheBlocked = false; + } + } else if (!do_access && memReq->isLocked()){ + // Store-Conditional instructions complete even if they "failed" + assert(cache_req->inst->isStoreConditional()); + cache_req->setCompleted(true); + + DPRINTF(LLSC, + "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n", + tid, tid); + + cache_req->dataPkt->req->setExtraData(0); + + processCacheCompletion(cache_req->dataPkt); + + // Automatically set these since we ignored the memory access + //cache_req->setMemAccPending(false); + //cache_req->setMemAccCompleted(); + } else { + // Make cache request again since access due to + // inability to access + DPRINTF(InOrderStall, "STALL: \n"); + cache_req->setCompleted(false); + } + + return fault; +} + +void +CacheUnit::processCacheCompletion(PacketPtr pkt) +{ + // Cast to correct packet type + CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt); + assert(cache_pkt); + + if (cache_pkt->cacheReq->isSquashed()) { + DPRINTF(InOrderCachePort, + "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum); + + cache_pkt->cacheReq->done(); + return; + } + + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum, + cache_pkt->cacheReq->getInst()->getMemAddr()); + + // Cast to correct request type + CacheRequest *cache_req = dynamic_cast<CacheReqPtr>( + findRequest(cache_pkt->cacheReq->getInst())); + assert(cache_req); + + + // Get resource request info + // @todo: SMT needs to figure out where to get thread # from. + unsigned tid = 0; + unsigned stage_num = cache_req->getStageNum(); + DynInstPtr inst = cache_req->inst; + + if (!cache_req->isSquashed()) { + if (inst->resSched.top()->cmd == CompleteFetch) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing fetch access\n", + tid, inst->seqNum); + } else if (inst->staticInst && inst->isMemRef()) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing cache access\n", + tid, inst->seqNum); + + inst->completeAcc(pkt); + + if (inst->isLoad()) { + assert(cache_pkt->isRead()); + + if (cache_pkt->req->isLocked()) { + DPRINTF(InOrderCachePort, + "[tid:%u]: Handling Load-Linked for [sn:%u]\n", + tid, inst->seqNum); + TheISA::handleLockedRead(cpu, cache_pkt->req); + } + + // @TODO: Hardcoded to for load instructions. Assumes that + // the dest. idx 0 is always where the data is loaded to. + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data loaded was: %08p\n", + tid, inst->seqNum, inst->readIntResult(0)); + } else if(inst->isStore()) { + assert(cache_pkt->isWrite()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data stored was: %08p\n", + tid, inst->seqNum, + getMemData(cache_pkt)); + + } + } + + cache_req->setMemAccPending(false); + cache_req->setMemAccCompleted(); + + // Wake up the CPU (if it went to sleep and was waiting on this + // completion event). + cpu->wakeCPU(); + + DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n", + tid, cpu->pipelineStage[stage_num]->name()); + + cpu->switchToActive(stage_num); + } else { + DPRINTF(InOrderCachePort, + "[tid:%u] Miss on block @ %08p completed, but squashed\n", + tid, cache_req->inst->readPC()); + cache_req->setMemAccCompleted(); + } + + inst->unsetMemAddr(); +} + +void +CacheUnit::recvRetry() +{ + DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i]\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + + assert(retryPkt != NULL); + assert(cacheBlocked); + assert(cacheStatus == cacheWaitRetry); + + if (cachePort->sendTiming(retryPkt)) { + cacheStatus = cacheWaitResponse; + retryPkt = NULL; + cacheBlocked = false; + } else { + DPRINTF(InOrderCachePort, + "Retry Request for [tid:%i] [sn:%i] failed\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + } +} + +void +CacheUnit::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(InOrderCachePort, + "[tid:%i] Squashing request from [sn:%i]\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); + + req_ptr->setSquashed(); + + req_ptr->getInst()->setSquashed(); + + CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr); + assert(cache_req); + + if (!cache_req->isMemAccPending()) { + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) + freeSlot(slot_remove_list[i]); +} + +uint64_t +CacheUnit::getMemData(Packet *packet) +{ + switch (packet->getSize()) + { + case 8: + return packet->get<uint8_t>(); + + case 16: + return packet->get<uint16_t>(); + + case 32: + return packet->get<uint32_t>(); + + case 864: + return packet->get<uint64_t>(); + + default: + panic("bad store data size = %d\n", packet->getSize()); + } +} + diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh new file mode 100644 index 000000000..8cd2b89cb --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CACHE_UNIT_HH__ +#define __CPU_INORDER_CACHE_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +//#include "cpu/inorder/params.hh" + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" +#include "mem/port.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/sim_object.hh" + +#include "params/InOrderCPU.hh" + +class CacheRequest; +typedef CacheRequest* CacheReqPtr; + +class CacheReqPacket; +typedef CacheReqPacket* CacheReqPktPtr; + +class CacheUnit : public Resource +{ + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + CacheUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~CacheUnit() {} + + enum Command { + InitiateFetch, + CompleteFetch, + InitiateReadData, + CompleteReadData, + InitiateWriteData, + CompleteWriteData, + Fetch, + ReadData, + WriteData + }; + + public: + /** CachePort class for the Cache Unit. Handles doing the + * communication with the cache/memory. + */ + class CachePort : public Port + { + protected: + /** Pointer to cache port unit */ + CacheUnit *cachePortUnit; + + public: + /** Default constructor. */ + CachePort(CacheUnit *_cachePortUnit) + : Port(_cachePortUnit->name() + "-cache-port", + (MemObject*)_cachePortUnit->cpu), + cachePortUnit(_cachePortUnit) + { } + + bool snoopRangeSent; + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles setting fetch to the + * proper status to start fetching. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of a failed fetch. */ + virtual void recvRetry(); + }; + + enum CachePortStatus { + cacheWaitResponse, + cacheWaitRetry, + cacheAccessComplete + }; + + ///virtual void init(); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + void requestAgain(DynInstPtr inst, bool &try_request); + + int getSlot(DynInstPtr inst); + + void freeSlot(int slot_num); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + + /** Processes cache completion event. */ + void processCacheCompletion(PacketPtr pkt); + + void recvRetry(); + + /** Align a PC to the start of an I-cache block. */ + Addr cacheBlockAlignPC(Addr addr) + { + //addr = TheISA::realPCToFetchPC(addr); + return (addr & ~(cacheBlkMask)); + } + + /** Returns a specific port. */ + Port *getPort(const std::string &if_name, int idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. + */ + //Fault doFetchAccess(DynInstPtr inst); + + /** Read/Write on behalf of an instruction. + * curResSlot needs to be a valid value in instruction. + */ + Fault doDataAccess(DynInstPtr inst); + + uint64_t getMemData(Packet *packet); + + protected: + /** Cache interface. */ + CachePort *cachePort; + + CachePortStatus cacheStatus; + + CacheReqPtr retryReq; + + PacketPtr retryPkt; + + int retrySlot; + + bool cacheBlocked; + + std::vector<Addr> addrList; + + std::map<Addr, InstSeqNum> addrMap; + + public: + int cacheBlkSize; + + int cacheBlkMask; + + /** Align a PC to the start of the Cache block. */ + Addr cacheBlockAlign(Addr addr) + { + return (addr & ~(cacheBlkMask)); + } + + /** THINGS USED FOR FETCH */ + // NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION + /** The mem line being fetched. */ + //uint8_t *cacheData[ThePipeline::MaxThreads]; + + /** The Addr of the cacheline that has been loaded. */ + //Addr cacheBlockAddr[ThePipeline::MaxThreads]; + + //unsigned fetchOffset[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ +}; + +struct CacheSchedEntry : public ThePipeline::ScheduleEntry +{ + enum EntryType { + FetchAccess, + DataAccess + }; + + CacheSchedEntry(int stage_num, int _priority, int res_num, + MemCmd::Command pkt_cmd, EntryType _type = FetchAccess) + : ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd), + type(_type) + { } + + MemCmd::Command pktCmd; + EntryType type; +}; + +class CacheRequest : public ResourceRequest +{ + public: + CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int req_size, + MemCmd::Command pkt_cmd, unsigned flags, int cpu_id) + : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd), + pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false) + { + memReq = inst->memReq; + + reqData = new uint8_t[req_size]; + retryPkt = NULL; + } + + virtual ~CacheRequest() + { +#if 0 + delete reqData; + + // Can get rid of packet and packet request now + if (*dataPkt) { + if (*dataPkt->req) { + delete dataPkt->req; + } + delete dataPkt; + } + + // Can get rid of packet and packet request now + if (retryPkt) { + if (retryPkt->req) { + delete retryPkt->req; + } + delete retryPkt; + } +#endif + + if (memReq) + delete memReq; + } + + virtual PacketDataPtr getData() + { return reqData; } + + void + setMemAccCompleted(bool completed = true) + { + memAccComplete = completed; + } + + bool isMemAccComplete() { return memAccComplete; } + + void setMemAccPending(bool pending = true) { memAccPending = pending; } + bool isMemAccPending() { return memAccPending; } + + //Make this data private/protected! + MemCmd::Command pktCmd; + RequestPtr memReq; + PacketDataPtr reqData; + PacketPtr dataPkt; + PacketPtr retryPkt; + + bool memAccComplete; + bool memAccPending; +}; + +class CacheReqPacket : public Packet +{ + public: + CacheReqPacket(CacheRequest *_req, + Command _cmd, short _dest) + : Packet(_req->memReq, _cmd, _dest), cacheReq(_req) + { + + } + + CacheRequest *cacheReq; +}; + +#endif //__CPU_CACHE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc new file mode 100644 index 000000000..d95b1d4bb --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/decode_unit.hh" + +using namespace TheISA; +using namespace ThePipeline; +using namespace std; + +DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + for (int tid = 0; tid < MaxThreads; tid++) { + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +void +DecodeUnit::execute(int slot_num) +{ + ResourceRequest* decode_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + decode_req->fault = NoFault; + + switch (decode_req->cmd) + { + case DecodeInst: + { + bool done_sked = ThePipeline::createBackEndSchedule(inst); + + if (done_sked) { + DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", + tid, seq_num); + regDepMap[tid]->insert(inst); + decode_req->done(); + } else { + DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create " + "schedule for instruction [sn:%i] \n", tid, inst->seqNum); + DPRINTF(InOrderStall, "STALL: \n"); + decode_req->done(false); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + +void +DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderDecode, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n", + tid, stage_num, squash_seq_num); + + //cpu->removeInstsUntil(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh new file mode 100644 index 000000000..3813de6c4 --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_DECODE_UNIT_HH__ +#define __CPU_INORDER_DECODE_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class DecodeUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~DecodeUnit() {} + + enum Command { + DecodeInst + }; + + virtual void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + protected: + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc new file mode 100644 index 000000000..843adb5b0 --- /dev/null +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +ExecutionUnit::regStats() +{ + predictedTakenIncorrect + .name(name() + ".predictedTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Taken."); + + predictedNotTakenIncorrect + .name(name() + ".predictedNotTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Not Taken)."); + + Resource::regStats(); +} + +void +ExecutionUnit::execute(int slot_num) +{ + ResourceRequest* exec_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + exec_req->fault = NoFault; + + DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n", + tid, seq_num, inst->readPC()); + + switch (exec_req->cmd) + { + case ExecuteInst: + { + if (inst->isMemRef()) { + fatal("%s not configured to handle memory ops.\n", resName); + } else if (inst->isControl()) { + // Evaluate Branch + fault = inst->execute(); + + inst->setExecuted(); + + if (fault == NoFault) { + // If branch is mispredicted, then signal squash + // throughout all stages behind the pipeline stage + // that got squashed. + if (inst->mispredicted()) { + int stage_num = exec_req->getStageNum(); + int tid = inst->readTid(); + + // If it's a branch ... + if (inst->isDirectCtrl()) { + assert(!inst->isIndirectCtrl()); + + if (inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst" + "[sn:%i] PC %#x mispredicted as taken.\n", tid, + seq_num, inst->PC); + } else if (!inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + inst->procDelaySlotOnMispred = true; + + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst." + "[sn:%i] PC %#x mispredicted as not taken.\n", tid, + seq_num, inst->PC); + } else { + inst->bdelaySeqNum = seq_num + 1; + + DPRINTF(InOrderExecute, "[tid:%i]: Misprediction detected at " + "[sn:%i] PC %#x,\n\t squashing after delay slot " + "instruction [sn:%i].\n", + tid, seq_num, inst->PC, inst->bdelaySeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch " + "misprediction at %#x\n", tid, inst->PC); + inst->setPredTarg(inst->nextNPC); + } + + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + + } else if(inst->isIndirectCtrl()){ + inst->setPredTarg(inst->nextNPC); + inst->bdelaySeqNum = seq_num + 1; + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + } else { + panic("Non-control instruction (%s) mispredicting?!!", + inst->staticInst->getName()); + } + + DPRINTF(InOrderExecute, "[tid:%i] Squashing will start from stage %i.\n", + tid, stage_num); + + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + inst->squashingStage = stage_num; + + // Squash throughout other resources + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, + inst, 0, 0, tid); + + if (inst->predTaken()) { + predictedTakenIncorrect++; + } else { + predictedNotTakenIncorrect++; + } + } + exec_req->done(); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + } + } else { + // Regular ALU instruction + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + exec_req->done(); + + DPRINTF(InOrderExecute, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh new file mode 100644 index 000000000..46691bbf2 --- /dev/null +++ b/src/cpu/inorder/resources/execution_unit.hh @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__ +#define __CPU_INORDER_EXECUTION_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class ExecutionUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ExecuteInst + }; + + public: + ExecutionUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ExecutionUnit() {} + + public: + virtual void regStats(); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + virtual void execute(int slot_num); + + protected: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar predictedTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; +}; + + +#endif //__CPU_INORDER_EXCUTION_UNIT_HH__ diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc new file mode 100644 index 000000000..444252e1b --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resource_pool.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + instSize(sizeof(MachInst)) +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + } +} + +void +FetchSeqUnit::init() +{ + resourceEvent = new FetchSeqEvent[width]; + + initSlots(); +} + +void +FetchSeqUnit::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* fs_req = reqMap[slot_num]; + DynInstPtr inst = fs_req->inst; + int tid = inst->readTid(); + int stage_num = fs_req->getStageNum(); + int seq_num = inst->seqNum; + + fs_req->fault = NoFault; + + switch (fs_req->cmd) + { + case AssignNextPC: + { + if (pcValid[tid]) { + + if (delaySlotInfo[tid].targetReady && + delaySlotInfo[tid].numInsts == 0) { + // Set PC to target + PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC + nextPC[tid] = PC[tid] + instSize; //next_NPC + nextNPC[tid] = PC[tid] + (2 * instSize); + + delaySlotInfo[tid].targetReady = false; + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to delay slot target\n",tid); + } + + inst->setPC(PC[tid]); + inst->setNextPC(PC[tid] + instSize); + inst->setNextNPC(PC[tid] + (instSize * 2)); + + inst->setPredTarg(inst->readNextNPC()); + + inst->setMemAddr(PC[tid]); + inst->setSeqNum(cpu->getAndIncrementInstSeq(tid)); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid, + inst->seqNum, inst->readPC()); + + if (delaySlotInfo[tid].numInsts > 0) { + --delaySlotInfo[tid].numInsts; + + // It's OK to set PC to target of branch + if (delaySlotInfo[tid].numInsts == 0) { + delaySlotInfo[tid].targetReady = true; + } + + DPRINTF(InOrderFetchSeq, "[tid:%i]: %i delay slot inst(s) left to" + " process.\n", tid, delaySlotInfo[tid].numInsts); + } + + PC[tid] = nextPC[tid]; + nextPC[tid] = nextNPC[tid]; + nextNPC[tid] += instSize; + + fs_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid); + fs_req->setCompleted(false); + } + } + break; + + case UpdateTargetPC: + { + if (inst->isControl()) { + // If it's a return, then we must wait for resolved address. + if (inst->isReturn() && !inst->predTaken()) { + cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true; + pcValid[tid] = false; + pcBlockStage[tid] = stage_num; + } else if (inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken AND Conditional Control + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. " + "Delay inst. Skipping delay slot and Updating PC to %08p\n", + tid, inst->seqNum, inst->readPC(), inst->readPredTarg()); + + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num); + + inst->bdelaySeqNum = seq_num; + inst->squashingStage = stage_num; + + squashAfterInst(inst, stage_num, tid); + } else if (!inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken Control + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control " + "inst. updating PC to %08p\n", tid, inst->seqNum, + inst->readNextPC()); + + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readNextNPC(); + + } else if (inst->predTaken()) { + // Taken Control + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readPredTarg(); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay slot target " + "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg()); + + // Set-Up Squash Through-Out Pipeline + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num + 1); + inst->bdelaySeqNum = seq_num + 1; + inst->squashingStage = stage_num; + + // Do Squashing + squashAfterInst(inst, stage_num, tid); + } + } else { + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch target update " + "since then is not a control instruction.\n", tid, inst->seqNum); + } + + fs_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +inline void +FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid) +{ + // Squash In Pipeline Stage + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + // Squash inside current resource, so if there needs to be fetching on same cycle + // the fetch information will be correct. + // squash(inst, stage_num, inst->bdelaySeqNum, tid); + + // Schedule Squash Through-out Resource Pool + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0); +} +void +FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from stage %i.\n", + tid, squash_stage); + + InstSeqNum done_seq_num = inst->bdelaySeqNum; + Addr new_PC = inst->readPredTarg(); + + if (squashSeqNum[tid] <= done_seq_num && + lastSquashCycle[tid] == curTick) { + DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, since" + "there is an outstanding squash that is older.\n", + tid, squash_stage); + } else { + squashSeqNum[tid] = done_seq_num; + lastSquashCycle[tid] = curTick; + + // If The very next instruction number is the done seq. num, + // then we haven't seen the delay slot yet ... if it isn't + // the last done_seq_num then this is the delay slot inst. + if (cpu->nextInstSeqNum(tid) != done_seq_num && + !inst->procDelaySlotOnMispred) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + // Reset PC + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %08p.\n", + tid, PC[tid]); + } else { + delaySlotInfo[tid].numInsts = 1; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC; + + // Reset PC to Delay Slot Instruction + if (inst->procDelaySlotOnMispred) { + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + } + + } + + // Unblock Any Stages Waiting for this information to be updated ... + if (!pcValid[tid]) { + cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true; + } + + pcValid[tid] = true; + } + + Resource::squash(inst, squash_stage, squash_seq_num, tid); +} + +FetchSeqUnit::FetchSeqEvent::FetchSeqEvent() + : ResourceEvent() +{ } + +void +FetchSeqUnit::FetchSeqEvent::process() +{ + FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource); + assert(fs_res); + + for (int i=0; i < MaxThreads; i++) { + fs_res->PC[i] = fs_res->cpu->readPC(i); + fs_res->nextPC[i] = fs_res->cpu->readNextPC(i); + fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i); + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n", + fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]); + + fs_res->pcValid[i] = true; + } + + //cpu->fetchPriorityList.push_back(tid); +} + + +void +FetchSeqUnit::activateThread(unsigned tid) +{ + pcValid[tid] = true; + + PC[tid] = cpu->readPC(tid); + nextPC[tid] = cpu->readNextPC(tid); + nextNPC[tid] = cpu->readNextNPC(tid); + + cpu->fetchPriorityList.push_back(tid); + + DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n", + tid, PC[tid], nextPC[tid], nextNPC[tid]); +} + +void +FetchSeqUnit::deactivateThread(unsigned tid) +{ + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + + std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(), + cpu->fetchPriorityList.end(), + tid); + + if (thread_it != cpu->fetchPriorityList.end()) + cpu->fetchPriorityList.erase(thread_it); +} diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh new file mode 100644 index 000000000..1885d1f11 --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__ +#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class FetchSeqUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + AssignNextPC, + UpdateTargetPC + }; + + public: + FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~FetchSeqUnit() {} + + virtual void init(); + virtual void activateThread(unsigned tid); + virtual void deactivateThread(unsigned tid); + virtual void execute(int slot_num); + + /** Override default Resource squash sequence. This actually, + * looks in the global communication buffer to get squash + * info + */ + virtual void squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid); + + + inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid); + + protected: + unsigned instSize; + + bool pcValid[ThePipeline::MaxThreads]; + int pcBlockStage[ThePipeline::MaxThreads]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** Tracks delay slot information for threads in ISAs which use + * delay slots; + */ + struct DelaySlotInfo { + InstSeqNum delaySlotSeqNum; + InstSeqNum branchSeqNum; + int numInsts; + Addr targetAddr; + bool targetReady; + }; + + DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class FetchSeqEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + FetchSeqEvent(); + virtual ~FetchSeqEvent() {} + + /** Processes a resource event. */ + virtual void process(); + }; + +}; + +#endif diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc new file mode 100644 index 000000000..569401e4f --- /dev/null +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "cpu/inorder/resources/graduation_unit.hh" + +using namespace ThePipeline; + +GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + lastCycleGrad(0), numCycleGrad(0) + +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + } +} + +void +GraduationUnit::execute(int slot_num) +{ + ResourceRequest* grad_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + int stage_num = inst->resSched.top()->stageNum; + + grad_req->fault = NoFault; + + switch (grad_req->cmd) + { + case GraduateInst: + { + // @TODO: Instructions should never really get to this point since this should be handled + // through the request interface. Check to make sure this happens and delete this + // code. + if (lastCycleGrad != curTick) { + lastCycleGrad = curTick; + numCycleGrad = 0; + } else if (numCycleGrad > width) { + DPRINTF(InOrderGraduation, "Graduation bandwidth reached for this cycle.\n"); + return; + } + + // Make sure this is the last thing on the resource schedule + assert(inst->resSched.size() == 1); + + DPRINTF(InOrderGraduation, "[tid:%i] Graduating instruction [sn:%i].\n", + tid, seq_num); + + DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/); + + // Release Non-Speculative "Block" on instructions that could not execute + // because there was a non-speculative inst. active. + // @TODO: Fix this functionality. Probably too conservative. + if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = false; + DPRINTF(InOrderGraduation, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n", + tid, seq_num); + } + + if (inst->traceData) { + inst->traceData->setStageCycle(stage_num, curTick); + } + + // Tell CPU that instruction is finished processing + cpu->instDone(inst, tid); + + //cpu->pipelineStage[stage_num]->toPrevStages-> + //stageInfo[stage_num][tid].doneSeqNum = inst->seqNum; + + grad_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} diff --git a/src/cpu/o3/alpha/params.hh b/src/cpu/inorder/resources/graduation_unit.hh index 164c25312..ad222b119 100644 --- a/src/cpu/o3/alpha/params.hh +++ b/src/cpu/inorder/resources/graduation_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,37 +25,46 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim + * Authors: Korey Sewell + * */ -#ifndef __CPU_O3_ALPHA_PARAMS_HH__ -#define __CPU_O3_ALPHA_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace AlphaISA -{ - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> -class AlphaSimpleParams : public O3Params -{ +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class GraduationUnit : public Resource { public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + GraduateInst + }; + + public: + GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~GraduationUnit() {} + + virtual void execute(int slot_num); + + protected: + Tick lastCycleGrad; + int numCycleGrad; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; - AlphaISA::ITB *itb; - AlphaISA::DTB *dtb; + /** @todo: Add Resource Stats Here */ }; -#endif // __CPU_O3_ALPHA_PARAMS_HH__ +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc new file mode 100644 index 000000000..fafff1fa7 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +InstBuffer::regStats() +{ + instsBypassed + .name(name() + ".instsBypassed") + .desc("Number of Instructions Bypassed."); + + Resource::regStats(); +} + +void +InstBuffer::execute(int slot_idx) +{ + ResReqPtr ib_req = reqMap[slot_idx]; + DynInstPtr inst = ib_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = ib_req->getStageNum(); + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case ScheduleOrBypass: + { + int next_stage = stage_num + 1; + int bypass_stage = stage_num + 2; + bool do_bypass = true; + + if (!instList.empty()) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) { + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because there is no room in " + "stage %i incoming stage buffer.\n", inst->seqNum, next_stage); + do_bypass = false; + } + + if (!do_bypass) { // SCHEDULE USAGE OF BUFFER + DPRINTF(InOrderInstBuffer, "Scheduling [sn:%i] for buffer insertion in stage %i\n", + inst->seqNum, next_stage); + + // Add to schedule: Insert into buffer in next stage + int stage_pri = ThePipeline::getNextPriority(inst, next_stage); + + inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id, + InstBuffer::InsertInst)); + + // Add to schedule: Remove from buffer in next next (bypass) stage + stage_pri = ThePipeline::getNextPriority(inst, bypass_stage); + + inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id, + InstBuffer::RemoveInst)); + } else { // BYPASS BUFFER & NEXT STAGE + DPRINTF(InOrderInstBuffer, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n", + inst->seqNum, next_stage, bypass_stage); + inst->setNextStage(bypass_stage); + instsBypassed++; + } + + ib_req->done(); + } + break; + + case InsertInst: + { + bool inserted = false; + + if (instList.size() < width) { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + inserted = true; + } else { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request because " + "buffer is full.\n", tid, seq_num); + + + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum); + list_it++; + } + } + + ib_req->done(inserted); + } + break; + + case RemoveInst: + { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(InOrderInstBuffer, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop(unsigned tid) +{ + instList.pop_front(); +} + +ThePipeline::DynInstPtr +InstBuffer::top(unsigned tid) +{ + return instList.front(); +} + +void +InstBuffer::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + queue<list<DynInstPtr>::iterator> remove_list; + list<DynInstPtr>::iterator list_it = instList.begin(); + list<DynInstPtr>::iterator list_end = instList.end(); + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->readTid() == tid && + (*list_it)->seqNum > squash_seq_num) { + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n", + tid, (*remove_list.front())->seqNum); + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(inst, stage_num, squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh new file mode 100644 index 000000000..baadd42ff --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.hh @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr, + ScheduleOrBypass + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~InstBuffer() {} + + virtual void regStats(); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(unsigned tid); + + virtual DynInstPtr top(unsigned tid); + + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + public: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar instsBypassed; + +}; + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc new file mode 100644 index 000000000..7e2c98837 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +ResReqPtr +InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top()); + assert(ib_entry); + + return new InstBufferRequest(this, inst, stage_num, id, slot_num, + ib_entry->cmd); +} + +void +InstBuffer::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]); + assert(ib_req); + + DynInstPtr inst = ib_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case InsertInst: + { + DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + ib_req->done(); + } + break; + + case RemoveInst: + { + DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list<DynInstPtr>::iterator list_it = instList.begin(); + std::list<DynInstPtr>::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop() +{ instList.pop_front(); } + +ThePipeline::DynInstPtr +InstBuffer::top() +{ return instList.front(); } + +void +InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + list<DynInstPtr>::iterator list_it = instList.begin(); + list<DynInstPtr>::iterator list_end = instList.end(); + queue<list<DynInstPtr>::iterator> remove_list; + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->seqNum > squash_seq_num) { + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n", + tid, (*list_it)->seqNum); + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh new file mode 100644 index 000000000..e374fa109 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.hh @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~InstBuffer() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(); + + virtual DynInstPtr top(); + + virtual void squash(InstSeqNum squash_seq_num, unsigned tid); + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + /** @todo: Add Resource Stats Here */ + +}; + +struct InstBufferEntry : public ThePipeline::ScheduleEntry { + InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) : + ScheduleEntry(stage_num, res_num), cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + +class InstBufferRequest : public ResourceRequest { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + InstBuffer::Command _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num), + cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/base/stats/statdb.hh b/src/cpu/inorder/resources/mem_dep_unit.hh index a5b9be7eb..0bd850c5c 100644 --- a/src/base/stats/statdb.hh +++ b/src/cpu/inorder/resources/mem_dep_unit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,46 +25,42 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Nathan Binkert + * Authors: Korey Sewell + * */ -#ifndef __BASE_STATS_STATDB_HH__ -#define __BASE_STATS_STATDB_HH__ +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ -#include <iosfwd> +#include <vector> #include <list> -#include <map> #include <string> -class Python; - -namespace Stats { +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" -class StatData; +class MemDepUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; -namespace Database { + public: + MemDepUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~MemDepUnit() {} -typedef std::map<void *, StatData *> stat_map_t; -typedef std::list<StatData *> stat_list_t; + virtual void execute(int slot_num); -// We wrap the database in a struct to make sure it is built in time. -struct TheDatabase -{ - stat_map_t map; - stat_list_t stats; -}; + protected: + Tick lastCycleGrad; + int numCycleGrad; -TheDatabase &db(); -inline stat_map_t &map() { return db().map; } -inline stat_list_t &stats() { return db().stats; } + bool *nonSpecInstActive[ThePipeline::MaxThreads]; -StatData *find(void *stat); -void regStat(void *stat, StatData *data); -void regPrint(void *stat); + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; -inline std::string name() { return "Statistics Database"; } - -/* namespace Database */ } -/* namespace Stats */ } + /** @todo: Add Resource Stats Here */ +}; -#endif // __BASE_STATS_STATDB_HH__ +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc new file mode 100644 index 000000000..b31d60ad5 --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "cpu/inorder/resources/mult_div_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/op_class.hh" + +using namespace std; +using namespace ThePipeline; + +MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + multRepeatRate(params->multRepeatRate), multLatency(params->multLatency), + div8RepeatRate(params->div8RepeatRate), div8Latency(params->div8Latency), + div16RepeatRate(params->div16RepeatRate), div16Latency(params->div16Latency), + div24RepeatRate(params->div24RepeatRate), div24Latency(params->div24Latency), + div32RepeatRate(params->div32RepeatRate), div32Latency(params->div32Latency), + lastMDUCycle(0) +{ } + +void +MultDivUnit::regStats() +{ + multInstReqsProcessed + .name(name() + ".multInstReqsProcessed") + .desc("Number of Multiply Requests Processed."); + + divInstReqsProcessed + .name(name() + ".divInstReqsProcessed") + .desc("Number of Divide Requests Processed."); + + Resource::regStats(); +} + +void +MultDivUnit::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new MDUEvent[width]; + + initSlots(); +} + +int +MultDivUnit::findSlot(DynInstPtr inst) +{ + DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + inst->seqNum, slotsAvail(), slotsInUse()); + + return Resource::findSlot(inst); +} + +void +MultDivUnit::freeSlot(int slot_idx) +{ + DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse()); + + Resource::freeSlot(slot_idx); +} + + +int +MultDivUnit::getSlot(DynInstPtr inst) +{ + // If MDU already has instruction, return current slot. + int slot_num = findSlot(inst); + + // If we have this instruction's request already then return + if (slot_num != -1 && + inst->resSched.top()->cmd == reqMap[slot_num]->cmd) + return slot_num; + + unsigned repeat_rate = 0; + + /** Enforce MDU dependencies after a multiply is seen last */ + if (lastOpType == IntMultOp) { + repeat_rate = multRepeatRate; + } + + /** Enforce dependencies after a divide is seen last */ + if (lastOpType == IntDivOp) { + switch (lastDivSize) { + case 8: + repeat_rate = div8RepeatRate; + break; + + case 16: + repeat_rate = div16RepeatRate; + break; + + case 24: + repeat_rate = div24RepeatRate; + break; + + case 32: + repeat_rate = div32RepeatRate; + break; + } + } + + if (lastMDUCycle + repeat_rate > curTick) { + DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n", + lastMDUCycle + repeat_rate); + return -1; + } else { + int rval = Resource::getSlot(inst); + DPRINTF(InOrderMDU, "MDU request should pass: %i.\n", + rval); + + if (rval != -1) { + lastMDUCycle = curTick; + lastOpType = inst->opClass(); + lastInstName = inst->staticInst->getName(); + } + + return rval; + } +} + +int +MultDivUnit::getDivOpSize(DynInstPtr inst) +{ + // Get RT Register from instruction (index #1) + uint32_t div_op = inst->readIntSrc(1); + + if (div_op <= 0xFF) { + return 8; + } else if (div_op <= 0xFFFF) { + return 16; + } else if (div_op <= 0xFFFFFF) { + return 24; + } else { + return 32; + } +} + +void +MultDivUnit::execute(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + + //int tid = inst->readTid(); + //int seq_num = inst->seqNum; + + switch (mult_div_req->cmd) + { + case StartMultDiv: + DPRINTF(InOrderMDU, "Start MDU called ...\n"); + + if (inst->opClass() == IntMultOp) { + scheduleEvent(slot_num, multLatency); + multInstReqsProcessed++; + } else if (inst->opClass() == IntDivOp) { + int op_size = getDivOpSize(inst); + + switch (op_size) + { + case 8: + scheduleEvent(slot_num, div8Latency); + break; + + case 16: + scheduleEvent(slot_num, div16Latency); + break; + + case 24: + scheduleEvent(slot_num, div24Latency); + break; + + case 32: + scheduleEvent(slot_num, div32Latency); + break; + } + + lastDivSize = op_size; + + divInstReqsProcessed++; + } + + // Allow to pass through to next stage while + // event processes + mult_div_req->setCompleted(); + break; + + case MultDiv: + DPRINTF(InOrderMDU, "Execute MDU called ...\n"); + exeMulDiv(slot_num); + mult_div_req->done(); + break; + + + case EndMultDiv: + //@TODO: Why not allow high-latency requests to sleep + // within stage until event wakes up???? + // Seems wasteful to continually check to see if + // this is done when we have a event in parallel + // counting down the time + { + DPRINTF(InOrderMDU, "End MDU called ...\n"); + if (mult_div_req->getInst()->isExecuted()) + mult_div_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +MultDivUnit::exeMulDiv(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + mult_div_req->setCompleted(); + + DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } +} + + +MDUEvent::MDUEvent() + : ResourceEvent() +{ } + +void +MDUEvent::process() +{ + MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource); + + mdu_res->exeMulDiv(slotIdx); + + ResourceRequest* mult_div_req = resource->reqMap[slotIdx]; + + mult_div_req->done(); +} + + diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh new file mode 100644 index 000000000..76180714c --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.hh @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__ +#define __CPU_INORDER_MULT_DIV_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/func_unit.hh" +#include "cpu/op_class.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class MDUEvent; + +class MultDivUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + StartMultDiv, + EndMultDiv, + MultDiv + }; + + public: + MultDivUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~MultDivUnit() {} + + public: + /** Override default Resource getSlot(). Will only getSlot if + * valid mult/div sequence is being maintained + */ + virtual int getSlot(DynInstPtr inst); + + virtual int findSlot(DynInstPtr inst); + + virtual void freeSlot(int slot_idx); + + virtual void init(); + + /** Get Operand Size For A Division Operation */ + int getDivOpSize(DynInstPtr inst); + + /** Override default Resource execute */ + virtual void execute(int slot_num); + + void exeMulDiv(int slot_num); + + /** Register extra resource stats */ + virtual void regStats(); + + protected: + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multRepeatRate; + unsigned multLatency; + + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8RepeatRate; + unsigned div8Latency; + + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16RepeatRate; + unsigned div16Latency; + + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24RepeatRate; + unsigned div24Latency; + + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32RepeatRate; + unsigned div32Latency; + + /** Last cycle that MDU was used */ + Tick lastMDUCycle; + + /** Last type of instruction MDU started processing */ + OpClass lastOpType; + + /** Last Division Operand of instruction MDU was processing */ + uint32_t lastDivSize; + + /** Last instruction name the MDU used */ + std::string lastInstName; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar multInstReqsProcessed; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar divInstReqsProcessed; + + MDUEvent *mduEvent; +}; + +class MDUEvent : public ResourceEvent +{ + public: + MDUEvent(); + virtual ~MDUEvent() { } + + + virtual void process(); +}; + + +#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__ diff --git a/src/arch/mips/syscallreturn.hh b/src/cpu/inorder/resources/resource_list.hh index 24a40ddcc..cbe2ad8c3 100644 --- a/src/arch/mips/syscallreturn.hh +++ b/src/cpu/inorder/resources/resource_list.hh @@ -25,31 +25,23 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black - * Korey Sewell + * Authors: Korey Sewell + * */ -#ifndef __ARCH_MIPS_SYSCALLRETURN_HH__ -#define __ARCH_MIPS_SYSCALLRETURN_HH__ - -#include "sim/syscallreturn.hh" -#include "cpu/thread_context.hh" +#ifndef CPU_INORDER_RESOURCE_LIST_HH +#define CPU_INORDER_RESOURCE_LIST_HH -namespace MipsISA -{ - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext *tc) - { - if (return_value.successful()) { - // no error - tc->setIntReg(SyscallSuccessReg, 0); - tc->setIntReg(ReturnValueReg1, return_value.value()); - } else { - // got an error, return details - tc->setIntReg(SyscallSuccessReg, (IntReg) -1); - tc->setIntReg(ReturnValueReg1, -return_value.value()); - } - } -} +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/resources/decode_unit.hh" +#include "cpu/inorder/resources/graduation_unit.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resources/branch_predictor.hh" +#include "cpu/inorder/resources/agen_unit.hh" +#include "cpu/inorder/resources/mult_div_unit.hh" #endif diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc new file mode 100644 index 000000000..8f8ba144e --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +TLBUnit::TLBUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params) +{ + for (int i=0; i < MaxThreads; i++) { + tlbBlocked[i] = false; + } +} + +void +TLBUnit::init() +{ + resourceEvent = new TLBUnitEvent[width]; + + initSlots(); +} + +int +TLBUnit::getSlot(DynInstPtr inst) +{ + if (tlbBlocked[inst->threadNumber]) { + return -1; + } else { + return Resource::getSlot(inst); + } +} + +ResourceRequest* +TLBUnit::getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd) +{ + return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num, + cmd); +} + +void +TLBUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqMap[slot_idx]); + assert(tlb_req); + + DynInstPtr inst = tlb_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = tlb_req->getStageNum(); + + tlb_req->fault = NoFault; + + switch (tlb_req->cmd) + { + case FetchLookup: + { + tlb_req->fault = + this->cpu->itb->translateAtomic(tlb_req->memReq, + cpu->thread[tid]->getTC()); + + if (tlb_req->fault != NoFault) { + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + case DataLookup: + { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n", + tid, seq_num, tlb_req->memReq->getVaddr()); + + tlb_req->fault = + this->cpu->itb->translateAtomic(tlb_req->memReq, + cpu->thread[tid]->getTC()); + + if (tlb_req->fault != NoFault) { + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +TLBUnitEvent::TLBUnitEvent() + : ResourceEvent() +{ } + +void +TLBUnitEvent::process() +{ + DynInstPtr inst = resource->reqMap[slotIdx]->inst; + int stage_num = resource->reqMap[slotIdx]->getStageNum(); + int tid = inst->threadNumber; + + DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n", + inst->seqNum); + + TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource); + assert(tlb_res); + + tlb_res->tlbBlocked[tid] = false; + + tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid); + + // Effectively NOP the instruction but still allow it + // to commit + //while (!inst->resSched.empty() && + // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) { + //inst->resSched.pop(); + //} +} diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh new file mode 100644 index 000000000..c7fee6030 --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_TLB_UNIT_HH__ +#define __CPU_INORDER_TLB_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class TLBUnit : public InstBuffer { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum TLBCommand { + FetchLookup, + DataLookup + }; + + public: + TLBUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~TLBUnit() {} + + void init(); + + int getSlot(DynInstPtr inst); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual void execute(int slot_num); + + bool tlbBlocked[ThePipeline::MaxThreads]; + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list<DynInstPtr> instList; + + /** @todo: Add Resource Stats Here */ + +}; + +class TLBUnitEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + TLBUnitEvent(); + virtual ~TLBUnitEvent() {} + + /** Processes a resource event. */ + virtual void process(); +}; + +class TLBUnitRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + unsigned _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd) + { + Addr aligned_addr; + int req_size; + unsigned flags; + + if (_cmd == TLBUnit::FetchLookup) { + aligned_addr = inst->getMemAddr(); + req_size = sizeof(MachInst); + flags = 0; + } else { + aligned_addr = inst->getMemAddr();; + req_size = inst->getMemAccSize(); + flags = inst->getMemFlags(); + } + + // @TODO: Add Vaddr & Paddr functions + inst->memReq = new Request(inst->readTid(), aligned_addr, req_size, + flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid()); + + memReq = inst->memReq; + } + + RequestPtr memReq; +}; + + +#endif //__CPU_INORDER_TLB_UNIT_HH__ diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc new file mode 100644 index 000000000..a9281a18c --- /dev/null +++ b/src/cpu/inorder/resources/use_def.cc @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include <vector> +#include <list> +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + maxSeqNum((InstSeqNum)-1) +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + + outReadSeqNum[tid] = maxSeqNum; + outWriteSeqNum[tid] = maxSeqNum; + + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +ResReqPtr +UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd, + inst->resSched.top()->idx); +} + + +ResReqPtr +UseDefUnit::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second); + assert(ud_req); + + if (ud_req && + ud_req->getInst() == inst && + ud_req->cmd == inst->resSched.top()->cmd && + ud_req->useDefIdx == inst->resSched.top()->idx) { + return ud_req; + } + map_it++; + } + + return NULL; +} + +void +UseDefUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]); + assert(ud_req); + + DynInstPtr inst = ud_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + int ud_idx = ud_req->useDefIdx; + + // If there is a non-speculative instruction + // in the pipeline then stall instructions here + if (*nonSpecInstActive[tid] == true && + seq_num > *nonSpecSeqNum[tid]) { + DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because there is " + "non-speculative instruction [sn:%i] has not graduated.\n", + tid, seq_num, *nonSpecSeqNum[tid]); + return; + } else if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = true; + *nonSpecSeqNum[tid] = seq_num; + } + + switch (ud_req->cmd) + { + case ReadSrcReg: + { + int reg_idx = inst->_srcRegIdx[ud_idx]; + + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to read source register idx %i.\n", + tid, ud_idx); + + // Ask register dependency map if it is OK to read from Arch. Reg. File + if (regDepMap[tid]->canRead(reg_idx, inst)) { + // Read From Register File + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Int Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readIntReg(reg_idx,inst->readTid())); + } else if (reg_idx <= Ctrl_Base_DepTag) { + reg_idx -= FP_Base_DepTag; + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Float Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now + cpu->readFloatRegBits(reg_idx, inst->readTid())); + } else { + reg_idx -= Ctrl_Base_DepTag; + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Misc Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readMiscReg(reg_idx, inst->readTid())); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n", + tid, outReadSeqNum[tid]); + } + + } else { + DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst); + + if (forward_inst) { + + if (inst->seqNum <= outReadSeqNum[tid]) { + int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx); + + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } else if (reg_idx <= Ctrl_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readFloatResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx)); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n", + tid, outReadSeqNum[tid]); + } + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i is not ready to read.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n", + tid, reg_idx); + outReadSeqNum[tid] = inst->seqNum; + } + } + } + break; + + case WriteDestReg: + { + int reg_idx = inst->_destRegIdx[ud_idx]; + + if (regDepMap[tid]->canWrite(reg_idx, inst)) { + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to write to Register File.\n", + tid); + + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(InOrderUseDef, "[tid:%i]: Writing 0x%x to register idx %i.\n", + tid, inst->readIntResult(ud_idx), reg_idx); + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + cpu->setIntReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } else if(reg_idx <= Ctrl_Base_DepTag) { + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= FP_Base_DepTag; + + cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here + inst->readFloatResult(ud_idx), + inst->readTid()); + } else { + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= Ctrl_Base_DepTag; + cpu->setMiscReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } + + outWriteSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n", + tid, outReadSeqNum); + } + } else { + DPRINTF(InOrderUseDef, "[tid:%i]: Dest. register idx: %i is not ready to write.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n", + tid, reg_idx); + outWriteSeqNum[tid] = inst->seqNum; + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} + +void +UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", + tid, squash_seq_num); + + std::vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(InOrderUseDef, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + regDepMap[tid]->remove(req_ptr->getInst()); + + int req_slot_num = req_ptr->getSlot(); + + if (latency > 0) + unscheduleEvent(req_slot_num); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } + + if (outReadSeqNum[tid] >= squash_seq_num) { + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid); + outReadSeqNum[tid] = maxSeqNum; + } else if (outReadSeqNum[tid] != maxSeqNum) { + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n", + tid, outReadSeqNum[tid]); + } + + if (outWriteSeqNum[tid] >= squash_seq_num) { + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid); + outWriteSeqNum[tid] = maxSeqNum; + } else if (outWriteSeqNum[tid] != maxSeqNum) { + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n", + tid, outWriteSeqNum[tid]); + } +} diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh new file mode 100644 index 000000000..238591117 --- /dev/null +++ b/src/cpu/inorder/resources/use_def.hh @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__ +#define __CPU_INORDER_USE_DEF_UNIT_HH__ + +#include <vector> +#include <list> +#include <string> + +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class UseDefUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ReadSrcReg, + WriteDestReg + }; + + public: + UseDefUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~UseDefUnit() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual ResReqPtr findRequest(DynInstPtr inst); + + virtual void execute(int slot_num); + + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + const InstSeqNum maxSeqNum; + + protected: + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + /** Outstanding Seq. Num. Trying to Read from Register File */ + InstSeqNum outReadSeqNum[ThePipeline::MaxThreads]; + + InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads]; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class UseDefRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int use_def_idx) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd), + useDefIdx(use_def_idx) + { } + + int useDefIdx; + }; +}; + +#endif //__CPU_INORDER_USE_DEF_UNIT_HH__ diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc new file mode 100644 index 000000000..13f8ecdad --- /dev/null +++ b/src/cpu/inorder/thread_context.cc @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/exetrace.hh" +#include "cpu/inorder/thread_context.hh" + +using namespace TheISA; + +void +InOrderThreadContext::takeOverFrom(ThreadContext *old_context) +{ + // some things should already be set up + assert(getProcessPtr() == old_context->getProcessPtr()); + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + + thread->funcExeInst = old_context->readFuncExeInst(); + old_context->setStatus(ThreadContext::Unallocated); + thread->inSyscall = false; + thread->trapPending = false; +} + +void +InOrderThreadContext::activate(int delay) +{ + DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Active) + return; + + thread->setStatus(ThreadContext::Active); + + cpu->activateContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::suspend(int delay) +{ + DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Suspended) + return; + + thread->setStatus(ThreadContext::Suspended); + cpu->suspendContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::deallocate(int delay) +{ + DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Unallocated) + return; + + thread->setStatus(ThreadContext::Unallocated); + cpu->deallocateContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::halt(int delay) +{ + DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Halted) + return; + + thread->setStatus(ThreadContext::Halted); + cpu->haltContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif + ; +} + + +void +InOrderThreadContext::serialize(std::ostream &os) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->serialize(os); +#endif + ; +} + + +void +InOrderThreadContext::unserialize(Checkpoint *cp, const std::string §ion) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->unserialize(cp, section); +#endif + ; +} + +TheISA::MachInst +InOrderThreadContext:: getInst() +{ + return thread->getInst(); +} + + +void +InOrderThreadContext::copyArchRegs(ThreadContext *src_tc) +{ + TheISA::copyRegs(src_tc, this); +} + + +void +InOrderThreadContext::clearArchRegs() +{} + + +uint64_t +InOrderThreadContext::readIntReg(int reg_idx) +{ + return cpu->readIntReg(reg_idx, thread->readTid()); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx, int width) +{ + return cpu->readFloatReg(reg_idx, thread->readTid(), width); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx) +{ + return cpu->readFloatReg(reg_idx, thread->readTid()); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx, int width) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid(), width); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid()); +} + +uint64_t +InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid) +{ + return cpu->readRegOtherThread(reg_idx, tid); +} + +void +InOrderThreadContext::setIntReg(int reg_idx, uint64_t val) +{ + cpu->setIntReg(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid(), width); +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, + int width) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width); +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid()); +} + +void +InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid) +{ + cpu->setRegOtherThread(misc_reg, val, tid); +} + +void +InOrderThreadContext::setPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting PC to %08p\n", val); + cpu->setPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setNextPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val); + cpu->setNextPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setNextNPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val); + cpu->setNextNPC(val, thread->readTid()); +} + +void +InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); +} + +void +InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val) +{ + cpu->setMiscReg(misc_reg, val, thread->readTid()); +} diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh new file mode 100644 index 000000000..2fb2ed85f --- /dev/null +++ b/src/cpu/inorder/thread_context.hh @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_THREAD_CONTEXT_HH__ +#define __CPU_INORDER_THREAD_CONTEXT_HH__ + +#include "cpu/exetrace.hh" +#include "cpu/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" + +class TranslatingPort; + +/** + * Derived ThreadContext class for use with the InOrderCPU. It + * provides the interface for any external objects to access a + * single thread's state and some general CPU state. Any time + * external objects try to update state through this interface, + * the CPU will create an event to squash all in-flight + * instructions in order to ensure state is maintained correctly. + * It must be defined specifically for the InOrderCPU because + * not all architectural state is located within the O3ThreadState + * (such as the commit PC, and registers), and specific actions + * must be taken when using this interface (such as squashing all + * in-flight instructions when doing a write to this interface). + */ +class InOrderThreadContext : public ThreadContext +{ + public: + InOrderThreadContext() { } + + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + /** Pointer to the thread state that this TC corrseponds to. */ + InOrderThreadState *thread; + + + /** Returns a pointer to the ITB. */ + TheISA::ITB *getITBPtr() { return cpu->itb; } + + /** Returns a pointer to the DTB. */ + TheISA::DTB *getDTBPtr() { return cpu->dtb; } + + System *getSystemPtr() { return cpu->system; } + + /** Returns a pointer to this CPU. */ + virtual BaseCPU *getCpuPtr() { return cpu; } + + /** Returns a pointer to this CPU. */ + virtual std::string getCpuName() { return cpu->name(); } + + /** Reads this CPU's ID. */ + virtual int cpuId() { return cpu->cpuId(); } + + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } + + virtual uint64_t readMicroPC() + { return 0; } + + virtual void setMicroPC(uint64_t val) { }; + + virtual uint64_t readNextMicroPC() + { return 0; } + + virtual void setNextMicroPC(uint64_t val) { }; + + virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } + + /** Returns a pointer to this thread's process. */ + virtual Process *getProcessPtr() { return thread->getProcessPtr(); } + + /** Returns this thread's status. */ + virtual Status status() const { return thread->status(); } + + /** Sets this thread's status. */ + virtual void setStatus(Status new_status) + { thread->setStatus(new_status); } + + /** Set the status to Active. Optional delay indicates number of + * cycles to wait before beginning execution. */ + virtual void activate(int delay = 1); + + /** Set the status to Suspended. */ + virtual void suspend(int delay = 0); + + /** Set the status to Unallocated. */ + virtual void deallocate(int delay = 1); + + /** Set the status to Halted. */ + virtual void halt(int delay = 0); + + /** Takes over execution of a thread from another CPU. */ + virtual void takeOverFrom(ThreadContext *old_context); + + /** Registers statistics associated with this TC. */ + virtual void regStats(const std::string &name); + + /** Serializes state. */ + virtual void serialize(std::ostream &os); + + /** Unserializes state. */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** Returns this thread's ID number. */ + virtual int getThreadNum() { return thread->readTid(); } + + /** Returns the instruction this thread is currently committing. + * Only used when an instruction faults. + */ + virtual TheISA::MachInst getInst(); + + /** Copies the architectural registers from another TC into this TC. */ + virtual void copyArchRegs(ThreadContext *src_tc); + + /** Resets all architectural registers to 0. */ + virtual void clearArchRegs(); + + /** Reads an integer register. */ + virtual uint64_t readIntReg(int reg_idx); + + virtual FloatReg readFloatReg(int reg_idx, int width); + + virtual FloatReg readFloatReg(int reg_idx); + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width); + + virtual FloatRegBits readFloatRegBits(int reg_idx); + + virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid); + + /** Sets an integer register to a value. */ + virtual void setIntReg(int reg_idx, uint64_t val); + + virtual void setFloatReg(int reg_idx, FloatReg val, int width); + + virtual void setFloatReg(int reg_idx, FloatReg val); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val); + + virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid); + + /** Reads this thread's PC. */ + virtual uint64_t readPC() + { return cpu->readPC(thread->readTid()); } + + /** Sets this thread's PC. */ + virtual void setPC(uint64_t val); + + /** Reads this thread's next PC. */ + virtual uint64_t readNextPC() + { return cpu->readNextPC(thread->readTid()); } + + /** Sets this thread's next PC. */ + virtual void setNextPC(uint64_t val); + + virtual uint64_t readNextNPC() + { return cpu->readNextNPC(thread->readTid()); } + + virtual void setNextNPC(uint64_t val); + + /** Reads a miscellaneous register. */ + virtual MiscReg readMiscRegNoEffect(int misc_reg) + { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + + /** Reads a misc. register, including any side-effects the + * read might have as defined by the architecture. */ + virtual MiscReg readMiscReg(int misc_reg) + { return cpu->readMiscReg(misc_reg, thread->readTid()); } + + /** Sets a misc. register. */ + virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + + /** Sets a misc. register, including any side-effects the + * write might have as defined by the architecture. */ + virtual void setMiscReg(int misc_reg, const MiscReg &val); + + virtual void activateContext(int delay) + { cpu->activateContext(thread->readTid(), delay); } + + virtual void deallocateContext() + { cpu->deallocateContext(thread->readTid()); } + + /** Returns the number of consecutive store conditional failures. */ + // @todo: Figure out where these store cond failures should go. + virtual unsigned readStCondFailures() + { return thread->storeCondFailures; } + + /** Sets the number of consecutive store conditional failures. */ + virtual void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + + // Only really makes sense for old CPU model. Lots of code + // outside the CPU still checks this function, so it will + // always return false to keep everything working. + /** Checks if the thread is misspeculating. Because it is + * very difficult to determine if the thread is + * misspeculating, this is set as false. */ + virtual bool misspeculating() { return false; } + + /** Executes a syscall in SE mode. */ + virtual void syscall(int64_t callnum) + { return cpu->syscall(callnum, thread->readTid()); } + + /** Reads the funcExeInst counter. */ + virtual Counter readFuncExeInst() { return thread->funcExeInst; } + + virtual void changeRegFileContext(unsigned param, + unsigned val) + { panic("Not supported!"); } + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system (for now + // this single cpu) + if (this->cpu->numActiveThreads() - 1 > 0) + return 0; // don't exit simulation + else + return 1; // exit simulation + } + + virtual void setThreadRescheduleCondition(uint64_t cond) + { + this->deallocate(); + + this->setStatus(ThreadContext::Suspended); + + activateContext(cond); + } +}; + +#endif diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh new file mode 100644 index 000000000..eb4fe40b2 --- /dev/null +++ b/src/cpu/inorder/thread_state.hh @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_INORDER_THREAD_STATE_HH__ +#define __CPU_INORDER_THREAD_STATE_HH__ + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" + +class Event; +class FunctionalMemory; +class Process; +class InOrderCPU; + +/** + * Class that has various thread state, such as the status, the + * current instruction being processed, whether or not the thread has + * a trap pending or is being externally updated, the ThreadContext + * pointer, etc. It also handles anything related to a specific + * thread's process, such as syscalls and checking valid addresses. + */ +class InOrderThreadState : public ThreadState { + typedef ThreadContext::Status Status; + + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Whether or not the thread is currently in syscall mode, and + * thus able to be externally updated without squashing. + */ + bool inSyscall; + + /** Whether or not the thread is currently waiting on a trap, and + * thus able to be externally updated without squashing. + */ + bool trapPending; + + + InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid) + : ThreadState(reinterpret_cast<BaseCPU*>(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/), + cpu(_cpu), inSyscall(0), trapPending(0) + { } + + /** Handles the syscall. */ + void syscall(int64_t callnum) { process->syscall(callnum, tc); } + + /** Pointer to the ThreadContext of this thread. */ + ThreadContext *tc; + + /** Returns a pointer to the TC of this thread. */ + ThreadContext *getTC() { return tc; } + + int readTid() { return 0; } + + /** Pointer to the last graduated instruction in the thread */ + //DynInstPtr lastGradInst; +}; + +#endif // __CPU_INORDER_THREAD_STATE_HH__ diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh index 5d5bcda8e..e34658b58 100644 --- a/src/cpu/inteltrace.hh +++ b/src/cpu/inteltrace.hh @@ -47,8 +47,10 @@ class IntelTraceRecord : public InstRecord { public: IntelTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -64,7 +66,8 @@ class IntelTrace : public InstTracer IntelTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +79,7 @@ class IntelTrace : public InstTracer return NULL; return new IntelTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc index c3a11ad91..de7f9245e 100644 --- a/src/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc @@ -50,7 +50,7 @@ IntrControl::post(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->post_interrupt(int_num, index); + cpu->postInterrupt(int_num, index); } void @@ -59,7 +59,7 @@ IntrControl::clear(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->clear_interrupt(int_num, index); + cpu->clearInterrupt(int_num, index); } IntrControl * diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh index 97193ff1a..9962063e4 100644 --- a/src/cpu/legiontrace.hh +++ b/src/cpu/legiontrace.hh @@ -46,8 +46,10 @@ class LegionTraceRecord : public InstRecord { public: LegionTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -63,13 +65,14 @@ class LegionTrace : public InstTracer LegionTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new LegionTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc index 42889163a..3c57f85b7 100644 --- a/src/cpu/memtest/memtest.cc +++ b/src/cpu/memtest/memtest.cc @@ -152,7 +152,7 @@ MemTest::MemTest(const Params *p) // set up counters noResponseCycles = 0; numReads = 0; - tickEvent.schedule(0); + schedule(tickEvent, 0); id = TESTER_ALLOCATOR++; @@ -262,7 +262,7 @@ void MemTest::tick() { if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + ticks(1)); + schedule(tickEvent, curTick + ticks(1)); if (++noResponseCycles >= 500000) { cerr << name() << ": deadlocked at cycle " << curTick << endl; @@ -279,7 +279,7 @@ MemTest::tick() unsigned base = random() % 2; uint64_t data = random(); unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; + bool uncacheable = (random() % 100) < percentUncacheable; //If we aren't doing copies, use id as offset, and do a false sharing //mem tester @@ -290,17 +290,16 @@ MemTest::tick() access_size = 0; Request *req = new Request(); - uint32_t flags = 0; + Request::Flags flags; Addr paddr; - if (cacheable < percentUncacheable) { - flags |= UNCACHEABLE; + if (uncacheable) { + flags.set(Request::UNCACHEABLE); paddr = uncacheAddr + offset; } else { paddr = ((base) ? baseAddr1 : baseAddr2) + offset; } - bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE); - //bool probe = false; + bool probe = (random() % 100 < percentFunctional) && !uncacheable; paddr &= ~((1 << access_size) - 1); req->setPhys(paddr, 1 << access_size, flags); diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index ac2d0a058..907659f69 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -35,6 +35,7 @@ #include <set> #include "base/statistics.hh" +#include "base/fast_alloc.hh" #include "params/MemTest.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" @@ -73,10 +74,10 @@ class MemTest : public MemObject { private: MemTest *cpu; + public: - TickEvent(MemTest *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} - void process() {cpu->tick();} + TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {} + void process() { cpu->tick(); } virtual const char *description() const { return "MemTest tick"; } }; @@ -116,7 +117,7 @@ class MemTest : public MemObject bool snoopRangeSent; - class MemTestSenderState : public Packet::SenderState + class MemTestSenderState : public Packet::SenderState, public FastAlloc { public: /** Constructor. */ @@ -132,10 +133,10 @@ class MemTest : public MemObject bool accessRetry; - unsigned size; // size of testing memory region + unsigned size; // size of testing memory region - unsigned percentReads; // target percentage of read accesses - unsigned percentFunctional; // target percentage of functional accesses + unsigned percentReads; // target percentage of read accesses + unsigned percentFunctional; // target percentage of functional accesses unsigned percentUncacheable; int id; @@ -153,12 +154,12 @@ class MemTest : public MemObject Addr traceBlockAddr; - Addr baseAddr1; // fix this to option - Addr baseAddr2; // fix this to option + Addr baseAddr1; // fix this to option + Addr baseAddr2; // fix this to option Addr uncacheAddr; - unsigned progressInterval; // frequency of progress reports - Tick nextProgressMessage; // access # for next progress report + unsigned progressInterval; // frequency of progress reports + Tick nextProgressMessage; // access # for next progress report unsigned percentSourceUnaligned; unsigned percentDestUnaligned; @@ -170,9 +171,9 @@ class MemTest : public MemObject bool atomic; - Stats::Scalar<> numReadsStat; - Stats::Scalar<> numWritesStat; - Stats::Scalar<> numCopiesStat; + Stats::Scalar numReadsStat; + Stats::Scalar numWritesStat; + Stats::Scalar numCopiesStat; // called by MemCompleteEvent::process() void completeRequest(PacketPtr pkt); diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 7152602fe..c23a9e4ad 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -50,8 +50,12 @@ using namespace TheISA; namespace Trace { -NativeTrace::NativeTrace(const Params *p) : InstTracer(p) +NativeTrace::NativeTrace(const Params *p) + : InstTracer(p) { + if (ListenSocket::allDisabled()) + fatal("All listeners are disabled!"); + int port = 8000; while(!native_listener.listen(port, true)) { diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh index ab038c4c3..9e912d92f 100644 --- a/src/cpu/nativetrace.hh +++ b/src/cpu/nativetrace.hh @@ -54,8 +54,11 @@ class NativeTraceRecord : public InstRecord public: NativeTraceRecord(NativeTrace * _parent, Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc), + parent(_parent) { } @@ -192,13 +195,14 @@ class NativeTrace : public InstTracer NativeTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new NativeTraceRecord(this, when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } void diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index f0284b2cf..56e537ad2 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -38,10 +38,7 @@ if build_env['USE_CHECKER']: class DerivO3CPU(BaseCPU): type = 'DerivO3CPU' activity = Param.Unsigned(0, "Initial count") - numThreads = Param.Unsigned(1, "number of HW thread contexts") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") if build_env['USE_CHECKER']: if not build_env['FULL_SYSTEM']: checker = Param.BaseCPU(O3Checker(workload=Parent.workload, @@ -134,9 +131,6 @@ class DerivO3CPU(BaseCPU): instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - smtNumFetchingThreads = Param.Unsigned(1, "SMT Number of Fetching Threads") smtFetchPolicy = Param.String('SingleThread', "SMT Fetch policy") smtLSQPolicy = Param.String('Partitioned', "SMT LSQ Sharing Policy") diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py index 43a71d67b..edc6dc9b6 100644 --- a/src/cpu/o3/O3Checker.py +++ b/src/cpu/o3/O3Checker.py @@ -39,5 +39,3 @@ class O3Checker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript index 2de106d8b..f05986bf5 100755 --- a/src/cpu/o3/SConscript +++ b/src/cpu/o3/SConscript @@ -51,7 +51,9 @@ if 'O3CPU' in env['CPU_MODELS']: Source('bpred_unit.cc') Source('commit.cc') Source('cpu.cc') + Source('cpu_builder.cc') Source('decode.cc') + Source('dyn_inst.cc') Source('fetch.cc') Source('free_list.cc') Source('fu_pool.cc') @@ -65,6 +67,7 @@ if 'O3CPU' in env['CPU_MODELS']: Source('rob.cc') Source('scoreboard.cc') Source('store_set.cc') + Source('thread_context.cc') TraceFlag('FreeList') TraceFlag('LSQ') @@ -81,24 +84,6 @@ if 'O3CPU' in env['CPU_MODELS']: 'IQ', 'ROB', 'FreeList', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'O3CPU', 'Activity', 'Scoreboard', 'Writeback' ]) - if env['TARGET_ISA'] == 'alpha': - Source('alpha/cpu.cc') - Source('alpha/cpu_builder.cc') - Source('alpha/dyn_inst.cc') - Source('alpha/thread_context.cc') - elif env['TARGET_ISA'] == 'mips': - Source('mips/cpu.cc') - Source('mips/cpu_builder.cc') - Source('mips/dyn_inst.cc') - Source('mips/thread_context.cc') - elif env['TARGET_ISA'] == 'sparc': - Source('sparc/cpu.cc') - Source('sparc/cpu_builder.cc') - Source('sparc/dyn_inst.cc') - Source('sparc/thread_context.cc') - else: - sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA']) - if env['USE_CHECKER']: SimObject('O3Checker.py') Source('checker_builder.cc') diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc deleted file mode 100644 index ed10b2fd1..000000000 --- a/src/cpu/o3/alpha/cpu.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/alpha/cpu_impl.hh" -#include "cpu/o3/alpha/dyn_inst.hh" - -// Force instantiation of AlphaO3CPU for all the implemntations that are -// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (alpha_impl.cc?). -template class AlphaO3CPU<AlphaSimpleImpl>; diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh deleted file mode 100644 index ebc4e7b23..000000000 --- a/src/cpu/o3/alpha/cpu.hh +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_CPU_HH__ -#define __CPU_O3_ALPHA_CPU_HH__ - -#include "arch/regfile.hh" -#include "arch/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * AlphaO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class AlphaO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaO3CPU with the given parameters. */ - AlphaO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_CPU_HH__ diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc deleted file mode 100644 index f569c048b..000000000 --- a/src/cpu/o3/alpha/cpu_builder.cc +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#include <string> - -#include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/alpha/params.hh" -#include "cpu/o3/fu_pool.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public AlphaO3CPU<AlphaSimpleImpl> -{ - public: - DerivO3CPU(AlphaSimpleParams *p) - : AlphaO3CPU<AlphaSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - AlphaSimpleParams *params = new AlphaSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh deleted file mode 100644 index 7f8f0547b..000000000 --- a/src/cpu/o3/alpha/cpu_impl.hh +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#include "config/use_checker.hh" - -#include "arch/alpha/faults.hh" -#include "arch/alpha/isa_traits.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/params.hh" -#include "cpu/o3/alpha/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/alpha/osfpal.hh" -#include "arch/isa_traits.hh" -#include "arch/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -template <class Impl> -AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - AlphaTC<Impl> *alpha_tc = - new AlphaTC<Impl>; - - tc = alpha_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<AlphaTC<Impl> >( - alpha_tc, this->checker); - } -#endif - - alpha_tc->cpu = this; - alpha_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -AlphaO3CPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template <class Impl> -TheISA::MiscReg -AlphaO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -TheISA::MiscReg -AlphaO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template <class Impl> -Fault -AlphaO3CPU<Impl>::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); - - this->thread[tid]->kernelStats->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -bool -AlphaO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->threadContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - exitSimLoop("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template <class Impl> -Fault -AlphaO3CPU<Impl>::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::processInterrupts(Fault interrupt) -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -AlphaO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -AlphaO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(AlphaISA::ArgumentReg[i], tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(AlphaISA::ArgumentReg[i], val, tid); -} - -template <class Impl> -void -AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc deleted file mode 100644 index 97d2f3d08..000000000 --- a/src/cpu/o3/alpha/dyn_inst.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#include "cpu/o3/alpha/dyn_inst_impl.hh" -#include "cpu/o3/alpha/impl.hh" - -// Force instantiation of AlphaDynInst for all the implementations that -// are needed. -template class AlphaDynInst<AlphaSimpleImpl>; diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh deleted file mode 100644 index a6fb7b885..000000000 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific AlphaDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The AlphaDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class AlphaDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - AlphaDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_ALPHA_DYN_INST_HH__ - diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh deleted file mode 100644 index b928ae654..000000000 --- a/src/cpu/o3/alpha/impl.hh +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_IMPL_HH__ -#define __CPU_O3_ALPHA_IMPL_HH__ - -#include "arch/alpha/isa_traits.hh" - -#include "cpu/o3/alpha/params.hh" -#include "cpu/o3/cpu_policy.hh" - - -// Forward declarations. -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class AlphaO3CPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific O3CPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct AlphaSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol; - - /** The DynInst type to be used. */ - typedef AlphaDynInst<AlphaSimpleImpl> DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr<DynInst> DynInstPtr; - - /** The O3CPU type to be used. */ - typedef AlphaO3CPU<AlphaSimpleImpl> O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - /** The Params to be passed to each stage. */ - typedef AlphaSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef AlphaSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc index 0979c5c8f..510109d8a 100644 --- a/src/cpu/o3/base_dyn_inst.cc +++ b/src/cpu/o3/base_dyn_inst.cc @@ -29,11 +29,8 @@ */ #include "cpu/base_dyn_inst_impl.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/isa_specific.hh" // Explicit instantiation template class BaseDynInst<O3CPUImpl>; - -template <> -int -BaseDynInst<O3CPUImpl>::instcount = 0; diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 3c4c8e478..b32d2bd23 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -43,6 +43,8 @@ #include <list> +class DerivO3CPUParams; + /** * Basically a wrapper class to hold both the branch predictor * and the BTB. @@ -51,7 +53,6 @@ template<class Impl> class BPredUnit { private: - typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; enum PredType { @@ -61,12 +62,16 @@ class BPredUnit PredType predictor; + const std::string _name; + public: /** * @param params The params object, that has the size of the BP and BTB. */ - BPredUnit(Params *params); + BPredUnit(DerivO3CPUParams *params); + + const std::string &name() const { return _name; } /** * Registers statistics. @@ -236,21 +241,21 @@ class BPredUnit ReturnAddrStack RAS[Impl::MaxThreads]; /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; + Stats::Scalar lookups; /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; + Stats::Scalar condPredicted; /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; + Stats::Scalar condIncorrect; /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; + Stats::Scalar BTBLookups; /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; + Stats::Scalar BTBHits; /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; + Stats::Scalar BTBCorrect; /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; + Stats::Scalar usedRAS; /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; + Stats::Scalar RASIncorrect; }; #endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh index 84c50b4da..2fa59280d 100644 --- a/src/cpu/o3/bpred_unit_impl.hh +++ b/src/cpu/o3/bpred_unit_impl.hh @@ -34,11 +34,14 @@ #include "base/traceflags.hh" #include "cpu/o3/bpred_unit.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> -BPredUnit<Impl>::BPredUnit(Params *params) - : BTB(params->BTBEntries, - params->BTBTagSize, - params->instShiftAmt) +BPredUnit<Impl>::BPredUnit(DerivO3CPUParams *params) + : _name(params->name + ".BPredUnit"), + BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) { // Setup the selected predictor. if (params->predType == "local") { @@ -71,43 +74,43 @@ void BPredUnit<Impl>::regStats() { lookups - .name(name() + ".BPredUnit.lookups") + .name(name() + ".lookups") .desc("Number of BP lookups") ; condPredicted - .name(name() + ".BPredUnit.condPredicted") + .name(name() + ".condPredicted") .desc("Number of conditional branches predicted") ; condIncorrect - .name(name() + ".BPredUnit.condIncorrect") + .name(name() + ".condIncorrect") .desc("Number of conditional branches incorrect") ; BTBLookups - .name(name() + ".BPredUnit.BTBLookups") + .name(name() + ".BTBLookups") .desc("Number of BTB lookups") ; BTBHits - .name(name() + ".BPredUnit.BTBHits") + .name(name() + ".BTBHits") .desc("Number of BTB hits") ; BTBCorrect - .name(name() + ".BPredUnit.BTBCorrect") + .name(name() + ".BTBCorrect") .desc("Number of correct BTB predictions (this stat may not " "work properly.") ; usedRAS - .name(name() + ".BPredUnit.usedRAS") + .name(name() + ".usedRAS") .desc("Number of times the RAS was used to get a target.") ; RASIncorrect - .name(name() + ".BPredUnit.RASInCorrect") + .name(name() + ".RASInCorrect") .desc("Number of incorrect RAS predictions.") ; } diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index 80e42fa8b..f21c14569 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -37,6 +37,8 @@ #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" +class DerivO3CPUParams; + template <class> class O3ThreadState; @@ -69,7 +71,6 @@ class DefaultCommit // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; typedef typename CPUPol::RenameMap RenameMap; @@ -136,7 +137,7 @@ class DefaultCommit public: /** Construct a DefaultCommit with the given parameters. */ - DefaultCommit(O3CPU *_cpu, Params *params); + DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultCommit. */ std::string name() const; @@ -451,40 +452,40 @@ class DefaultCommit void updateComInstStats(DynInstPtr &inst); /** Stat for the total number of committed instructions. */ - Stats::Scalar<> commitCommittedInsts; + Stats::Scalar commitCommittedInsts; /** Stat for the total number of squashed instructions discarded by commit. */ - Stats::Scalar<> commitSquashedInsts; + Stats::Scalar commitSquashedInsts; /** Stat for the total number of times commit is told to squash. * @todo: Actually increment this stat. */ - Stats::Scalar<> commitSquashEvents; + Stats::Scalar commitSquashEvents; /** Stat for the total number of times commit has had to stall due to a non- * speculative instruction reaching the head of the ROB. */ - Stats::Scalar<> commitNonSpecStalls; + Stats::Scalar commitNonSpecStalls; /** Stat for the total number of branch mispredicts that caused a squash. */ - Stats::Scalar<> branchMispredicts; + Stats::Scalar branchMispredicts; /** Distribution of the number of committed instructions each cycle. */ - Stats::Distribution<> numCommittedDist; + Stats::Distribution numCommittedDist; /** Total number of instructions committed. */ - Stats::Vector<> statComInst; + Stats::Vector statComInst; /** Total number of software prefetches committed. */ - Stats::Vector<> statComSwp; + Stats::Vector statComSwp; /** Stat for the total number of committed memory references. */ - Stats::Vector<> statComRefs; + Stats::Vector statComRefs; /** Stat for the total number of committed loads. */ - Stats::Vector<> statComLoads; + Stats::Vector statComLoads; /** Total number of committed memory barriers. */ - Stats::Vector<> statComMembars; + Stats::Vector statComMembars; /** Total number of committed branches. */ - Stats::Vector<> statComBranches; + Stats::Vector statComBranches; /** Number of cycles where the commit bandwidth limit is reached. */ - Stats::Scalar<> commitEligibleSamples; + Stats::Scalar commitEligibleSamples; /** Number of instructions not committed due to bandwidth limits. */ - Stats::Vector<> commitEligible; + Stats::Vector commitEligible; }; #endif // __CPU_O3_COMMIT_HH__ diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index ee0f2bb59..7cd88b49b 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -36,6 +36,7 @@ #include <string> #include "arch/utility.hh" +#include "base/cp_annotate.hh" #include "base/loader/symtab.hh" #include "base/timebuf.hh" #include "cpu/exetrace.hh" @@ -46,12 +47,14 @@ #include "cpu/checker/cpu.hh" #endif +#include "params/DerivO3CPU.hh" + template <class Impl> DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid) - : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) + : Event(CPU_Tick_Pri), commit(_commit), tid(_tid) { - this->setFlags(Event::AutoDelete); + this->setFlags(AutoDelete); } template <class Impl> @@ -71,7 +74,7 @@ DefaultCommit<Impl>::TrapEvent::description() const } template <class Impl> -DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params) +DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), squashCounter(0), iewToCommitDelay(params->iewToCommitDelay), @@ -80,7 +83,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params) fetchToCommitDelay(params->commitToFetchDelay), renameWidth(params->renameWidth), commitWidth(params->commitWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), drainPending(false), switchedOut(false), trapLatency(params->trapLatency) @@ -460,7 +463,7 @@ DefaultCommit<Impl>::generateTrapEvent(unsigned tid) TrapEvent *trap = new TrapEvent(this, tid); - trap->schedule(curTick + trapLatency); + cpu->schedule(trap, curTick + trapLatency); trapInFlight[tid] = true; } @@ -663,7 +666,7 @@ DefaultCommit<Impl>::handleInterrupt() DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); } } else if (commitStatus[0] != TrapPending && - cpu->check_interrupts(cpu->tcBase(0)) && + cpu->checkInterrupts(cpu->tcBase(0)) && !trapSquash[0] && !tcSquash[0]) { // Process interrupts if interrupts are enabled, not in PAL @@ -693,7 +696,7 @@ DefaultCommit<Impl>::commit() // Check for any interrupt, and start processing it. Or if we // have an outstanding interrupt and are at a point when it is // valid to take an interrupt, process it. - if (cpu->check_interrupts(cpu->tcBase(0))) { + if (cpu->checkInterrupts(cpu->tcBase(0))) { handleInterrupt(); } #endif // FULL_SYSTEM @@ -812,7 +815,7 @@ DefaultCommit<Impl>::commit() // @todo: Make this handle multi-cycle communication between // commit and IEW. if (checkEmptyROB[tid] && rob->isEmpty(tid) && - !iewStage->hasStoresToWB() && !committedStores[tid]) { + !iewStage->hasStoresToWB(tid) && !committedStores[tid]) { checkEmptyROB[tid] = false; toIEW->commitInfo[tid].usedROB = true; toIEW->commitInfo[tid].emptyROB = true; @@ -966,7 +969,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", head_inst->seqNum, head_inst->readPC()); - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -981,7 +984,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) return false; } else if (head_inst->isLoad()) { - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -1036,7 +1039,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", head_inst->seqNum, head_inst->readPC()); - if (iewStage->hasStoresToWB() || inst_num > 0) { + if (iewStage->hasStoresToWB(tid) || inst_num > 0) { DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); return false; } @@ -1095,6 +1098,12 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) if (node) thread[tid]->profileNode = node; } + if (CPA::available()) { + if (head_inst->isControl()) { + ThreadContext *tc = thread[tid]->getTC(); + CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC()); + } + } #endif if (head_inst->traceData) { diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index c75a08213..1d7fb97c0 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -37,6 +37,7 @@ #include "cpu/thread_context.hh" #include "cpu/o3/isa_specific.hh" #include "cpu/o3/cpu.hh" +#include "cpu/o3/thread_context.hh" #include "enums/MemoryMode.hh" #include "sim/core.hh" #include "sim/stat_control.hh" @@ -52,10 +53,16 @@ #include "cpu/checker/cpu.hh" #endif +#if THE_ISA == ALPHA_ISA +#include "arch/alpha/osfpal.hh" +#endif + +class BaseCPUParams; + using namespace TheISA; -BaseO3CPU::BaseO3CPU(Params *params) - : BaseCPU(params), cpu_id(0) +BaseO3CPU::BaseO3CPU(BaseCPUParams *params) + : BaseCPU(params) { } @@ -67,7 +74,7 @@ BaseO3CPU::regStats() template <class Impl> FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -87,7 +94,7 @@ FullO3CPU<Impl>::TickEvent::description() const template <class Impl> FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent() - : Event(&mainEventQueue, CPU_Switch_Pri) + : Event(CPU_Switch_Pri) { } @@ -116,7 +123,7 @@ FullO3CPU<Impl>::ActivateThreadEvent::description() const template <class Impl> FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent() - : Event(&mainEventQueue, CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) + : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) { } @@ -147,31 +154,34 @@ FullO3CPU<Impl>::DeallocateContextEvent::description() const } template <class Impl> -FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) +FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params) : BaseO3CPU(params), itb(params->itb), dtb(params->dtb), tickEvent(this), +#ifndef NDEBUG + instcount(0), +#endif removeInstsThisCycle(false), - fetch(o3_cpu, params), - decode(o3_cpu, params), - rename(o3_cpu, params), - iew(o3_cpu, params), - commit(o3_cpu, params), + fetch(this, params), + decode(this, params), + rename(this, params), + iew(this, params), + commit(this, params), - regFile(o3_cpu, params->numPhysIntRegs, + regFile(this, params->numPhysIntRegs, params->numPhysFloatRegs), - freeList(params->numberOfThreads, + freeList(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs), - rob(o3_cpu, + rob(this, params->numROBEntries, params->squashWidth, params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), + params->numThreads), - scoreboard(params->numberOfThreads, + scoreboard(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs, TheISA::NumMiscRegs * number_of_threads, @@ -182,7 +192,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) decodeQueue(params->backComSize, params->forwardComSize), renameQueue(params->backComSize, params->forwardComSize), iewQueue(params->backComSize, params->forwardComSize), - activityRec(NumStages, + activityRec(name(), NumStages, params->backComSize + params->forwardComSize, params->activity), @@ -192,7 +202,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) physmem(system->physmem), #endif // FULL_SYSTEM drainCount(0), - deferRegistration(params->deferRegistration), + deferRegistration(params->defer_registration), numThreads(number_of_threads) { if (!deferRegistration) { @@ -336,6 +346,78 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params) //} contextSwitch = false; + DPRINTF(O3CPU, "Creating O3CPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(O3CPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new typename FullO3CPU<Impl>::Thread( + (typename Impl::O3CPU *)(this), + i, params->workload[i], i); + + this->thread[i]->setStatus(ThreadContext::Suspended); + + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new typename FullO3CPU<Impl>::Thread( + (typename Impl::O3CPU *)(this), + i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>; + + tc = o3_tc; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. +#if USE_CHECKER + if (params->checker) { + tc = new CheckerThreadContext<O3ThreadContext<Impl> >( + o3_tc, this->checker); + } +#endif + + o3_tc->cpu = (typename Impl::O3CPU *)(this); + assert(o3_tc->cpu); + o3_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + lockAddr = 0; + lockFlag = false; } template <class Impl> @@ -345,7 +427,7 @@ FullO3CPU<Impl>::~FullO3CPU() template <class Impl> void -FullO3CPU<Impl>::fullCPURegStats() +FullO3CPU<Impl>::regStats() { BaseO3CPU::regStats(); @@ -399,6 +481,11 @@ FullO3CPU<Impl>::fullCPURegStats() .precision(6); totalIpc = totalCommittedInsts / numCycles; + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); } template <class Impl> @@ -463,7 +550,7 @@ FullO3CPU<Impl>::tick() lastRunningCycle = curTick; timesIdled++; } else { - tickEvent.schedule(nextCycle(curTick + ticks(1))); + schedule(tickEvent, nextCycle(curTick + ticks(1))); DPRINTF(O3CPU, "Scheduling next tick!\n"); } } @@ -471,16 +558,13 @@ FullO3CPU<Impl>::tick() #if !FULL_SYSTEM updateThreadPriority(); #endif - } template <class Impl> void FullO3CPU<Impl>::init() { - if (!deferRegistration) { - registerThreadContexts(); - } + BaseCPU::init(); // Set inSyscall so that the CPU doesn't squash when initially // setting up registers. @@ -499,7 +583,7 @@ FullO3CPU<Impl>::init() } #if FULL_SYSTEM - TheISA::initCPU(src_tc, src_tc->readCpuId()); + TheISA::initCPU(src_tc, src_tc->contextId()); #endif } @@ -602,7 +686,7 @@ FullO3CPU<Impl>::suspendContext(int tid) DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); bool deallocated = deallocateContext(tid, false, 1); // If this was the last thread then unschedule the tick event. - if (activeThreads.size() == 1 && !deallocated || + if ((activeThreads.size() == 1 && !deallocated) || activeThreads.size() == 0) unscheduleTickEvent(); _status = Idle; @@ -782,18 +866,116 @@ FullO3CPU<Impl>::activateWhenReady(int tid) #if FULL_SYSTEM template <class Impl> +Fault +FullO3CPU<Impl>::hwrei(unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + // Need to clear the lock flag upon returning from an interrupt. + this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); + + this->thread[tid]->kernelStats->hwrei(); + + // FIXME: XXX check for interrupts? XXX +#endif + return NoFault; +} + +template <class Impl> +bool +FullO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->threadContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } +#endif + return true; +} + +template <class Impl> +Fault +FullO3CPU<Impl>::getInterrupts() +{ + // Check if there are any outstanding interrupts + return this->interrupts->getInterrupt(this->threadContexts[0]); +} + +template <class Impl> +void +FullO3CPU<Impl>::processInterrupts(Fault interrupt) +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + assert(interrupt != NoFault); + this->interrupts->updateIntrInfo(this->threadContexts[0]); + + DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); + this->trap(interrupt, 0); +} + +template <class Impl> void FullO3CPU<Impl>::updateMemPorts() { // Update all ThreadContext's memory ports (Functional/Virtual // Ports) for (int i = 0; i < thread.size(); ++i) - thread[i]->connectMemPorts(); + thread[i]->connectMemPorts(thread[i]->getTC()); } #endif template <class Impl> void +FullO3CPU<Impl>::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +#if !FULL_SYSTEM + +template <class Impl> +void +FullO3CPU<Impl>::syscall(int64_t callnum, int tid) +{ + DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +#endif + +template <class Impl> +void FullO3CPU<Impl>::serialize(std::ostream &os) { SimObject::State so_state = SimObject::getState(); @@ -891,7 +1073,7 @@ FullO3CPU<Impl>::resume() #endif if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); _status = Running; } @@ -984,11 +1166,41 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } } if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); +} + +template <class Impl> +TheISA::MiscReg +FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscRegNoEffect(misc_reg, tid); +} + +template <class Impl> +TheISA::MiscReg +FullO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscRegNoEffect(misc_reg, val, tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setMiscReg(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscReg(misc_reg, val, tid); } template <class Impl> @@ -1210,6 +1422,14 @@ FullO3CPU<Impl>::setNextMicroPC(Addr new_PC,unsigned tid) } template <class Impl> +void +FullO3CPU<Impl>::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + +template <class Impl> typename FullO3CPU<Impl>::ListIt FullO3CPU<Impl>::addInst(DynInstPtr &inst) { @@ -1419,9 +1639,24 @@ FullO3CPU<Impl>::wakeCPU() idleCycles += tickToCycles((curTick - 1) - lastRunningCycle); numCycles += tickToCycles((curTick - 1) - lastRunningCycle); - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } +#if FULL_SYSTEM +template <class Impl> +void +FullO3CPU<Impl>::wakeup() +{ + if (this->thread[0]->status() != ThreadContext::Suspended) + return; + + this->wakeCPU(); + + DPRINTF(Quiesce, "Suspended Processor woken\n"); + this->threadContexts[0]->activate(); +} +#endif + template <class Impl> int FullO3CPU<Impl>::getFreeTid() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 61d7dcf22..942970f5f 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -53,6 +53,8 @@ //#include "cpu/o3/thread_context.hh" #include "sim/process.hh" +#include "params/DerivO3CPU.hh" + template <class> class Checker; class ThreadContext; @@ -63,24 +65,15 @@ class Checkpoint; class MemObject; class Process; +class BaseCPUParams; + class BaseO3CPU : public BaseCPU { //Stuff that's pretty ISA independent will go here. public: - typedef BaseCPU::Params Params; - - BaseO3CPU(Params *params); + BaseO3CPU(BaseCPUParams *params); void regStats(); - - /** Sets this CPU's ID. */ - void setCpuId(int id) { cpu_id = id; } - - /** Reads this CPU's ID. */ - int readCpuId() { return cpu_id; } - - protected: - int cpu_id; }; /** @@ -96,8 +89,8 @@ class FullO3CPU : public BaseO3CPU typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; + typedef O3ThreadState<Impl> ImplState; typedef O3ThreadState<Impl> Thread; typedef typename std::list<DynInstPtr>::iterator ListIt; @@ -146,9 +139,9 @@ class FullO3CPU : public BaseO3CPU void scheduleTickEvent(int delay) { if (tickEvent.squashed()) - tickEvent.reschedule(nextCycle(curTick + ticks(delay))); + reschedule(tickEvent, nextCycle(curTick + ticks(delay))); else if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); } /** Unschedule tick event, regardless of its current state. */ @@ -186,11 +179,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (activateThreadEvent[tid].squashed()) - activateThreadEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!activateThreadEvent[tid].scheduled()) - activateThreadEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule actiavte thread event, regardless of its current state. */ @@ -237,11 +230,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (deallocateContextEvent[tid].squashed()) - deallocateContextEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!deallocateContextEvent[tid].scheduled()) - deallocateContextEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule thread deallocation in CPU */ @@ -256,12 +249,12 @@ class FullO3CPU : public BaseO3CPU public: /** Constructs a CPU with the given parameters. */ - FullO3CPU(O3CPU *o3_cpu, Params *params); + FullO3CPU(DerivO3CPUParams *params); /** Destructor. */ ~FullO3CPU(); /** Registers statistics. */ - void fullCPURegStats(); + void regStats(); void demapPage(Addr vaddr, uint64_t asn) { @@ -279,24 +272,6 @@ class FullO3CPU : public BaseO3CPU this->dtb->demapPage(vaddr, asn); } - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, Thread *thread) - { - return this->itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), true); - } - /** Returns a specific port. */ Port *getPort(const std::string &if_name, int idx); @@ -367,12 +342,12 @@ class FullO3CPU : public BaseO3CPU virtual void unserialize(Checkpoint *cp, const std::string §ion); public: - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. */ - virtual void syscall(int tid) { panic("Unimplemented!"); } + void syscall(int64_t callnum, int tid); +#endif /** Starts draining the CPU's pipeline of all instructions in * order to stop all memory accesses. */ @@ -394,7 +369,24 @@ class FullO3CPU : public BaseO3CPU InstSeqNum getAndIncrementInstSeq() { return globalSeqNum++; } + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + #if FULL_SYSTEM + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + + /** Returns the Fault for any valid interrupt. */ + Fault getInterrupts(); + + /** Processes any an interrupt fault. */ + void processInterrupts(Fault interrupt); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } + /** Update the Virt and Phys ports of all ThreadContexts to * reflect change in memory connections. */ void updateMemPorts(); @@ -424,6 +416,24 @@ class FullO3CPU : public BaseO3CPU #endif /** Register accessors. Index refers to the physical register index. */ + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); + uint64_t readIntReg(int reg_idx); TheISA::FloatReg readFloatReg(int reg_idx); @@ -495,6 +505,12 @@ class FullO3CPU : public BaseO3CPU /** Sets the commit next micro PC of a specific thread. */ void setNextMicroPC(Addr val, unsigned tid); + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + /** Function to add instruction onto the head of the list of the * instructions. Used when new instructions are fetched. */ @@ -528,6 +544,11 @@ class FullO3CPU : public BaseO3CPU void dumpInsts(); public: +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + /** List of all the instructions in flight. */ std::list<DynInstPtr> instList; @@ -648,6 +669,10 @@ class FullO3CPU : public BaseO3CPU /** Wakes the CPU, rescheduling the CPU if it's not already active. */ void wakeCPU(); +#if FULL_SYSTEM + virtual void wakeup(); +#endif + /** Gets a free thread id. Use if thread ids change across system. */ int getFreeTid(); @@ -710,14 +735,33 @@ class FullO3CPU : public BaseO3CPU /** Available thread ids in the cpu*/ std::vector<unsigned> tids; + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; + /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; + Stats::Scalar timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; + Stats::Scalar idleCycles; /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; + Stats::Vector committedInsts; /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; + Stats::Scalar totalCommittedInsts; /** Stat for the CPI per thread. */ Stats::Formula cpi; /** Stat for the total CPI. */ diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/cpu_builder.cc index 6d61501ac..77d7091ad 100644 --- a/src/cpu/o3/alpha/thread_context.hh +++ b/src/cpu/o3/cpu_builder.cc @@ -28,49 +28,51 @@ * Authors: Kevin Lim */ -#include "arch/alpha/types.hh" -#include "cpu/o3/thread_context.hh" +#include <string> -template <class Impl> -class AlphaTC : public O3ThreadContext<Impl> +#include "config/full_system.hh" +#include "config/use_checker.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/impl.hh" +#include "params/DerivO3CPU.hh" + +class DerivO3CPU : public FullO3CPU<O3CPUImpl> { public: + DerivO3CPU(DerivO3CPUParams *p) + : FullO3CPU<O3CPUImpl>(p) + { } +}; + +DerivO3CPU * +DerivO3CPUParams::create() +{ #if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() - { - return this->thread->quiesceEvent; - } -#endif + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + (numThreads >= workload.size()) ? numThreads : workload.size(); - virtual uint64_t readNextNPC() - { - return this->readNextPC() + sizeof(TheISA::MachInst); + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); } +#endif - virtual void setNextNPC(uint64_t val) - { - panic("Alpha has no NextNPC!"); - } + numThreads = actual_num_threads; - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } + // Default smtFetchPolicy to "RoundRobin", if necessary. + std::string round_robin_policy = "RoundRobin"; + std::string single_thread = "SingleThread"; + if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) + smtFetchPolicy = round_robin_policy; + else + smtFetchPolicy = smtFetchPolicy; - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() - { - this->deallocate(); + instShiftAmt = 2; - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } -}; + return new DerivO3CPU(this); +} diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh index 32a0adcf1..c06c9a201 100644 --- a/src/cpu/o3/cpu_policy.hh +++ b/src/cpu/o3/cpu_policy.hh @@ -65,7 +65,7 @@ struct SimpleCPUPolicy /** Typedef for the branch prediction unit (which includes the BP, * RAS, and BTB). */ - typedef BPredUnit<Impl> BPredUnit; + typedef ::BPredUnit<Impl> BPredUnit; /** Typedef for the register file. Most classes assume a unified * physical register file. */ @@ -75,15 +75,15 @@ struct SimpleCPUPolicy /** Typedef for the rename map. */ typedef SimpleRenameMap RenameMap; /** Typedef for the ROB. */ - typedef ROB<Impl> ROB; + typedef ::ROB<Impl> ROB; /** Typedef for the instruction queue/scheduler. */ typedef InstructionQueue<Impl> IQ; /** Typedef for the memory dependence unit. */ - typedef MemDepUnit<StoreSet, Impl> MemDepUnit; + typedef ::MemDepUnit<StoreSet, Impl> MemDepUnit; /** Typedef for the LSQ. */ - typedef LSQ<Impl> LSQ; + typedef ::LSQ<Impl> LSQ; /** Typedef for the thread-specific LSQ units. */ - typedef LSQUnit<Impl> LSQUnit; + typedef ::LSQUnit<Impl> LSQUnit; /** Typedef for fetch. */ typedef DefaultFetch<Impl> Fetch; @@ -109,7 +109,7 @@ struct SimpleCPUPolicy typedef DefaultIEWDefaultCommit<Impl> IEWStruct; /** The struct for communication within the IEW stage. */ - typedef IssueStruct<Impl> IssueStruct; + typedef ::IssueStruct<Impl> IssueStruct; /** The struct for all backwards communication. */ typedef TimeBufStruct<Impl> TimeStruct; diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index 3e82033ca..294b5b623 100644 --- a/src/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultDecode class handles both single threaded and SMT * decode. Its width is specified by the parameters; each cycles it @@ -50,7 +52,6 @@ class DefaultDecode // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; // Typedefs from the CPU policy. @@ -86,7 +87,7 @@ class DefaultDecode public: /** DefaultDecode constructor. */ - DefaultDecode(O3CPU *_cpu, Params *params); + DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of decode. */ std::string name() const; @@ -287,27 +288,27 @@ class DefaultDecode /** Stat for total number of idle cycles. */ - Stats::Scalar<> decodeIdleCycles; + Stats::Scalar decodeIdleCycles; /** Stat for total number of blocked cycles. */ - Stats::Scalar<> decodeBlockedCycles; + Stats::Scalar decodeBlockedCycles; /** Stat for total number of normal running cycles. */ - Stats::Scalar<> decodeRunCycles; + Stats::Scalar decodeRunCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> decodeUnblockCycles; + Stats::Scalar decodeUnblockCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> decodeSquashCycles; + Stats::Scalar decodeSquashCycles; /** Stat for number of times a branch is resolved at decode. */ - Stats::Scalar<> decodeBranchResolved; + Stats::Scalar decodeBranchResolved; /** Stat for number of times a branch mispredict is detected. */ - Stats::Scalar<> decodeBranchMispred; + Stats::Scalar decodeBranchMispred; /** Stat for number of times decode detected a non-control instruction * incorrectly predicted as a branch. */ - Stats::Scalar<> decodeControlMispred; + Stats::Scalar decodeControlMispred; /** Stat for total number of decoded instructions. */ - Stats::Scalar<> decodeDecodedInsts; + Stats::Scalar decodeDecodedInsts; /** Stat for total number of squashed instructions. */ - Stats::Scalar<> decodeSquashedInsts; + Stats::Scalar decodeSquashedInsts; }; #endif // __CPU_O3_DECODE_HH__ diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh index ce6738456..015bc8d7f 100644 --- a/src/cpu/o3/decode_impl.hh +++ b/src/cpu/o3/decode_impl.hh @@ -30,15 +30,17 @@ #include "cpu/o3/decode.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> -DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, Params *params) +DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), renameToDecodeDelay(params->renameToDecodeDelay), iewToDecodeDelay(params->iewToDecodeDelay), commitToDecodeDelay(params->commitToDecodeDelay), fetchToDecodeDelay(params->fetchToDecodeDelay), decodeWidth(params->decodeWidth), - numThreads(params->numberOfThreads) + numThreads(params->numThreads) { _status = Inactive; diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc index 984b58f4b..d828ef1b0 100644 --- a/src/cpu/o3/sparc/dyn_inst.cc +++ b/src/cpu/o3/dyn_inst.cc @@ -28,9 +28,9 @@ * Authors: Gabe Black */ -#include "cpu/o3/sparc/dyn_inst_impl.hh" -#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/dyn_inst_impl.hh" +#include "cpu/o3/impl.hh" -// Force instantiation of SparcDynInst for all the implementations that +// Force instantiation of BaseO3DynInst for all the implementations that // are needed. -template class SparcDynInst<SparcSimpleImpl>; +template class BaseO3DynInst<O3CPUImpl>; diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index a1f9e0591..292547b6b 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,36 +25,266 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Korey Sewell + * Authors: Kevin Lim */ #ifndef __CPU_O3_DYN_INST_HH__ #define __CPU_O3_DYN_INST_HH__ -#include "arch/isa_specific.hh" - -#if THE_ISA == ALPHA_ISA - template <class Impl> class AlphaDynInst; - struct AlphaSimpleImpl; - typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst; -#elif THE_ISA == MIPS_ISA - template <class Impl> class MipsDynInst; - struct MipsSimpleImpl; - typedef MipsDynInst<MipsSimpleImpl> O3DynInst; -#elif THE_ISA == SPARC_ISA - template <class Impl> class SparcDynInst; - struct SparcSimpleImpl; - typedef SparcDynInst<SparcSimpleImpl> O3DynInst; -#elif THE_ISA == X86_ISA - template <class Impl> class X86DynInst; - struct X86SimpleImpl; - typedef X86DynInst<X86SimpleImpl> O3DynInst; -#elif THE_ISA == ARM_ISA - template <class Impl> class ArmDynInst; - struct ArmSimpleImpl; - typedef ArmDynInst<ArmSimpleImpl> O3DynInst; +#include "arch/isa_traits.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/isa_specific.hh" + +class Packet; + +/** + * Mostly implementation & ISA specific AlphaDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The AlphaDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template <class Impl> +class BaseO3DynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::O3CPU O3CPU; + + /** Binary machine instruction type. */ + typedef TheISA::MachInst MachInst; + /** Extended machine instruction type. */ + typedef TheISA::ExtMachInst ExtMachInst; + /** Logical register index type. */ + typedef TheISA::RegIndex RegIndex; + /** Integer register index type. */ + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + /** Misc register index type. */ + typedef TheISA::MiscReg MiscReg; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. */ + BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a binary instruction. */ + BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + BaseO3DynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(PacketPtr pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg) + { + return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val) + { + return this->cpu->setMiscReg(misc_reg, val, + this->threadNumber); + } + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) + { + return this->cpu->readMiscRegNoEffect( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readMiscReg( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) + { + return this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); #else - #error "O3DynInst not defined for this ISA" + /** Calls a syscall. */ + void syscall(int64_t callnum); #endif -#endif // __CPU_O3_DYN_INST_HH__ + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(this->_srcRegIdx[idx]); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntRegOperand(si, idx, val); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); + } + +#if THE_ISA == MIPS_ISA + uint64_t readRegOtherThread(int misc_reg) + { + panic("MIPS MT not defined for O3 CPU.\n"); + return 0; + } + + void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) + { + panic("MIPS MT not defined for O3 CPU.\n"); + } +#endif + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_ALPHA_DYN_INST_HH__ + diff --git a/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 6dfe0ccdd..8d391ceaf 100644 --- a/src/cpu/o3/alpha/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -28,34 +28,35 @@ * Authors: Kevin Lim */ -#include "cpu/o3/alpha/dyn_inst.hh" +#include "base/cp_annotate.hh" +#include "cpu/o3/dyn_inst.hh" template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) +BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) { initVars(); } template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) +BaseO3DynInst<Impl>::BaseO3DynInst(ExtMachInst inst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) { initVars(); } template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) +BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr &_staticInst) : BaseDynInst<Impl>(_staticInst) { initVars(); @@ -63,7 +64,7 @@ AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) template <class Impl> void -AlphaDynInst<Impl>::initVars() +BaseO3DynInst<Impl>::initVars() { // Make sure to have the renamed register entries set to the same // as the normal register entries. It will allow the IQ to work @@ -80,7 +81,7 @@ AlphaDynInst<Impl>::initVars() template <class Impl> Fault -AlphaDynInst<Impl>::execute() +BaseO3DynInst<Impl>::execute() { // @todo: Pretty convoluted way to avoid squashing from happening // when using the TC during an instruction's execution @@ -98,7 +99,7 @@ AlphaDynInst<Impl>::execute() template <class Impl> Fault -AlphaDynInst<Impl>::initiateAcc() +BaseO3DynInst<Impl>::initiateAcc() { // @todo: Pretty convoluted way to avoid squashing from happening // when using the TC during an instruction's execution @@ -116,7 +117,7 @@ AlphaDynInst<Impl>::initiateAcc() template <class Impl> Fault -AlphaDynInst<Impl>::completeAcc(PacketPtr pkt) +BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt) { this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); @@ -126,8 +127,9 @@ AlphaDynInst<Impl>::completeAcc(PacketPtr pkt) #if FULL_SYSTEM template <class Impl> Fault -AlphaDynInst<Impl>::hwrei() +BaseO3DynInst<Impl>::hwrei() { +#if THE_ISA == ALPHA_ISA // Can only do a hwrei when in pal mode. if (!(this->readPC() & 0x3)) return new AlphaISA::UnimplementedOpcodeFault; @@ -135,33 +137,50 @@ AlphaDynInst<Impl>::hwrei() // Set the next PC based on the value of the EXC_ADDR IPR. this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, this->threadNumber)); + if (CPA::available()) { + ThreadContext *tc = this->cpu->tcBase(this->threadNumber); + CPA::cpa()->swAutoBegin(tc, this->readNextPC()); + } // Tell CPU to clear any state it needs to if a hwrei is taken. this->cpu->hwrei(this->threadNumber); +#else +#endif // FIXME: XXX check for interrupts? XXX return NoFault; } template <class Impl> void -AlphaDynInst<Impl>::trap(Fault fault) +BaseO3DynInst<Impl>::trap(Fault fault) { this->cpu->trap(fault, this->threadNumber); } template <class Impl> bool -AlphaDynInst<Impl>::simPalCheck(int palFunc) +BaseO3DynInst<Impl>::simPalCheck(int palFunc) { +#if THE_ISA != ALPHA_ISA + panic("simPalCheck called, but PAL only exists in Alpha!\n"); +#endif return this->cpu->simPalCheck(palFunc, this->threadNumber); } #else template <class Impl> void -AlphaDynInst<Impl>::syscall(int64_t callnum) +BaseO3DynInst<Impl>::syscall(int64_t callnum) { + // HACK: check CPU's nextPC before and after syscall. If it + // changes, update this instruction's nextPC because the syscall + // must have changed the nextPC. + Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber); this->cpu->syscall(callnum, this->threadNumber); + Addr new_next_pc = this->cpu->readNextPC(this->threadNumber); + if (cpu_next_pc != new_next_pc) { + this->setNextPC(new_next_pc); + } } #endif diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index d954bd1e7..08ccb094b 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -41,6 +41,8 @@ #include "mem/port.hh" #include "sim/eventq.hh" +class DerivO3CPUParams; + /** * DefaultFetch class handles both single threaded and SMT fetch. Its * width is specified by the parameters; each cycle it tries to fetch @@ -58,7 +60,6 @@ class DefaultFetch typedef typename Impl::DynInst DynInst; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; /** Typedefs from the CPU policy. */ typedef typename CPUPol::BPredUnit BPredUnit; @@ -81,7 +82,7 @@ class DefaultFetch public: /** Default constructor. */ IcachePort(DefaultFetch<Impl> *_fetch) - : Port(_fetch->name() + "-iport"), fetch(_fetch) + : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch) { } bool snoopRangeSent; @@ -160,7 +161,7 @@ class DefaultFetch public: /** DefaultFetch constructor. */ - DefaultFetch(O3CPU *_cpu, Params *params); + DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of fetch. */ std::string name() const; @@ -447,33 +448,33 @@ class DefaultFetch // @todo: Consider making these vectors and tracking on a per thread basis. /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; + Stats::Scalar fetchedInsts; /** Total number of fetched branches. */ - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Total number of cycles spent blocked. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Total number of cycles spent in any other state. */ - Stats::Scalar<> fetchMiscStallCycles; + Stats::Scalar fetchMiscStallCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; /** Total number of outstanding icache accesses that were dropped * due to a squash. */ - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; + Stats::Distribution fetchNisnDist; /** Rate of how often fetch was idle. */ Stats::Formula idleRate; /** Number of branch fetches per cycle. */ diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 7d344fa33..79a4f2b7a 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -51,6 +51,8 @@ #include "sim/system.hh" #endif // FULL_SYSTEM +#include "params/DerivO3CPU.hh" + template<class Impl> void DefaultFetch<Impl>::IcachePort::setPeer(Port *port) @@ -111,7 +113,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry() } template<class Impl> -DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params) +DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), branchPred(params), predecoder(NULL), @@ -123,14 +125,16 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params) cacheBlocked(false), retryPkt(NULL), retryTid(-1), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), numFetchingThreads(params->smtNumFetchingThreads), interruptPending(false), drainPending(false), switchedOut(false) { if (numThreads > Impl::MaxThreads) - fatal("numThreads is not a valid value\n"); + fatal("numThreads (%d) is larger than compiled limit (%d),\n" + "\tincrease MaxThreads in src/cpu/o3/impl.hh\n", + numThreads, static_cast<int>(Impl::MaxThreads)); // Set fetch stage's status to inactive. _status = Inactive; @@ -360,7 +364,7 @@ template<class Impl> void DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt) { - unsigned tid = pkt->req->getThreadNum(); + unsigned tid = pkt->req->threadId(); DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); @@ -591,12 +595,13 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid // Set the appropriate read size and flags as well. // Build request here. RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0, - fetch_PC, cpu->readCpuId(), tid); + fetch_PC, cpu->thread[tid]->contextId(), + tid); memReq[tid] = mem_req; // Translate the instruction request. - fault = cpu->translateInstReq(mem_req, cpu->thread[tid]); + fault = cpu->itb->translateAtomic(mem_req, cpu->thread[tid]->getTC()); // In the case of faults, the fetch stage may need to stall and wait // for the ITB miss to be handled. diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 457e2a024..3458f09d6 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -41,6 +41,7 @@ #include "cpu/o3/scoreboard.hh" #include "cpu/o3/lsq.hh" +class DerivO3CPUParams; class FUPool; /** @@ -70,7 +71,6 @@ class DefaultIEW typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; typedef typename CPUPol::IQ IQ; typedef typename CPUPol::RenameMap RenameMap; @@ -115,7 +115,7 @@ class DefaultIEW public: /** Constructs a DefaultIEW with the given parameters. */ - DefaultIEW(O3CPU *_cpu, Params *params); + DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultIEW stage. */ std::string name() const; @@ -208,6 +208,9 @@ class DefaultIEW /** Returns if the LSQ has any stores to writeback. */ bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } + /** Returns if the LSQ has any stores to writeback. */ + bool hasStoresToWB(unsigned tid) { return ldstQueue.hasStoresToWB(tid); } + void incrWb(InstSeqNum &sn) { if (++wbOutstanding == wbMax) @@ -462,69 +465,69 @@ class DefaultIEW bool switchedOut; /** Stat for total number of idle cycles. */ - Stats::Scalar<> iewIdleCycles; + Stats::Scalar iewIdleCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> iewSquashCycles; + Stats::Scalar iewSquashCycles; /** Stat for total number of blocking cycles. */ - Stats::Scalar<> iewBlockCycles; + Stats::Scalar iewBlockCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> iewUnblockCycles; + Stats::Scalar iewUnblockCycles; /** Stat for total number of instructions dispatched. */ - Stats::Scalar<> iewDispatchedInsts; + Stats::Scalar iewDispatchedInsts; /** Stat for total number of squashed instructions dispatch skips. */ - Stats::Scalar<> iewDispSquashedInsts; + Stats::Scalar iewDispSquashedInsts; /** Stat for total number of dispatched load instructions. */ - Stats::Scalar<> iewDispLoadInsts; + Stats::Scalar iewDispLoadInsts; /** Stat for total number of dispatched store instructions. */ - Stats::Scalar<> iewDispStoreInsts; + Stats::Scalar iewDispStoreInsts; /** Stat for total number of dispatched non speculative instructions. */ - Stats::Scalar<> iewDispNonSpecInsts; + Stats::Scalar iewDispNonSpecInsts; /** Stat for number of times the IQ becomes full. */ - Stats::Scalar<> iewIQFullEvents; + Stats::Scalar iewIQFullEvents; /** Stat for number of times the LSQ becomes full. */ - Stats::Scalar<> iewLSQFullEvents; + Stats::Scalar iewLSQFullEvents; /** Stat for total number of memory ordering violation events. */ - Stats::Scalar<> memOrderViolationEvents; + Stats::Scalar memOrderViolationEvents; /** Stat for total number of incorrect predicted taken branches. */ - Stats::Scalar<> predictedTakenIncorrect; + Stats::Scalar predictedTakenIncorrect; /** Stat for total number of incorrect predicted not taken branches. */ - Stats::Scalar<> predictedNotTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; /** Stat for total number of mispredicted branches detected at execute. */ Stats::Formula branchMispredicts; /** Stat for total number of executed instructions. */ - Stats::Scalar<> iewExecutedInsts; + Stats::Scalar iewExecutedInsts; /** Stat for total number of executed load instructions. */ - Stats::Vector<> iewExecLoadInsts; + Stats::Vector iewExecLoadInsts; /** Stat for total number of executed store instructions. */ -// Stats::Scalar<> iewExecStoreInsts; +// Stats::Scalar iewExecStoreInsts; /** Stat for total number of squashed instructions skipped at execute. */ - Stats::Scalar<> iewExecSquashedInsts; + Stats::Scalar iewExecSquashedInsts; /** Number of executed software prefetches. */ - Stats::Vector<> iewExecutedSwp; + Stats::Vector iewExecutedSwp; /** Number of executed nops. */ - Stats::Vector<> iewExecutedNop; + Stats::Vector iewExecutedNop; /** Number of executed meomory references. */ - Stats::Vector<> iewExecutedRefs; + Stats::Vector iewExecutedRefs; /** Number of executed branches. */ - Stats::Vector<> iewExecutedBranches; + Stats::Vector iewExecutedBranches; /** Number of executed store instructions. */ Stats::Formula iewExecStoreInsts; /** Number of instructions executed per cycle. */ Stats::Formula iewExecRate; /** Number of instructions sent to commit. */ - Stats::Vector<> iewInstsToCommit; + Stats::Vector iewInstsToCommit; /** Number of instructions that writeback. */ - Stats::Vector<> writebackCount; + Stats::Vector writebackCount; /** Number of instructions that wake consumers. */ - Stats::Vector<> producerInst; + Stats::Vector producerInst; /** Number of instructions that wake up from producers. */ - Stats::Vector<> consumerInst; + Stats::Vector consumerInst; /** Number of instructions that were delayed in writing back due * to resource contention. */ - Stats::Vector<> wbPenalized; + Stats::Vector wbPenalized; /** Number of instructions per cycle written back. */ Stats::Formula wbRate; /** Average number of woken instructions per writeback. */ diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 84d10e966..1daecd669 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -37,9 +37,10 @@ #include "base/timebuf.hh" #include "cpu/o3/fu_pool.hh" #include "cpu/o3/iew.hh" +#include "params/DerivO3CPU.hh" template<class Impl> -DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params) +DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params) : issueToExecQueue(params->backComSize, params->forwardComSize), cpu(_cpu), instQueue(_cpu, this, params), @@ -52,7 +53,7 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params) issueWidth(params->issueWidth), wbOutstanding(0), wbWidth(params->wbWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), switchedOut(false) { _status = Active; diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/impl.hh index 0a970c2f0..4b29b4daa 100644 --- a/src/cpu/o3/sparc/impl.hh +++ b/src/cpu/o3/impl.hh @@ -25,24 +25,23 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Gabe Black + * Authors: Kevin Lim */ -#ifndef __CPU_O3_SPARC_IMPL_HH__ -#define __CPU_O3_SPARC_IMPL_HH__ +#ifndef __CPU_O3_IMPL_HH__ +#define __CPU_O3_IMPL_HH__ -#include "arch/sparc/isa_traits.hh" +#include "arch/isa_traits.hh" -#include "cpu/o3/sparc/params.hh" #include "cpu/o3/cpu_policy.hh" // Forward declarations. template <class Impl> -class SparcDynInst; +class BaseO3DynInst; template <class Impl> -class SparcO3CPU; +class FullO3CPU; /** Implementation specific struct that defines several key types to the * CPU, the stages within the CPU, the time buffers, and the DynInst. @@ -52,16 +51,16 @@ class SparcO3CPU; * This is one of the key things that must be defined for each hardware * specific CPU implementation. */ -struct SparcSimpleImpl +struct O3CPUImpl { /** The type of MachInst. */ typedef TheISA::MachInst MachInst; /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol; + typedef SimpleCPUPolicy<O3CPUImpl> CPUPol; /** The DynInst type to be used. */ - typedef SparcDynInst<SparcSimpleImpl> DynInst; + typedef BaseO3DynInst<O3CPUImpl> DynInst; /** The refcounted DynInst pointer to be used. In most cases this is * what should be used, and not DynInst *. @@ -69,7 +68,7 @@ struct SparcSimpleImpl typedef RefCountingPtr<DynInst> DynInstPtr; /** The O3CPU type to be used. */ - typedef SparcO3CPU<SparcSimpleImpl> O3CPU; + typedef FullO3CPU<O3CPUImpl> O3CPU; /** Same typedef, but for CPUType. BaseDynInst may not always use * an O3 CPU, so it's clearer to call it CPUType instead in that @@ -77,16 +76,10 @@ struct SparcSimpleImpl */ typedef O3CPU CPUType; - /** The Params to be passed to each stage. */ - typedef SparcSimpleParams Params; - enum { MaxWidth = 8, MaxThreads = 4 }; }; -/** The O3Impl to be used. */ -typedef SparcSimpleImpl O3CPUImpl; - #endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index d0f503977..0c3f44436 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -41,8 +41,10 @@ #include "cpu/inst_seq.hh" #include "cpu/o3/dep_graph.hh" #include "cpu/op_class.hh" +#include "sim/eventq.hh" #include "sim/host.hh" +class DerivO3CPUParams; class FUPool; class MemInterface; @@ -70,7 +72,6 @@ class InstructionQueue //Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol::IEW IEW; typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; @@ -110,7 +111,7 @@ class InstructionQueue }; /** Constructs an IQ. */ - InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Destructs the IQ. */ ~InstructionQueue(); @@ -442,58 +443,58 @@ class InstructionQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; - Stats::Scalar<> iqInstsIssued; + Stats::Scalar iqInstsIssued; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; + Stats::Scalar iqIntInstsIssued; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; + Stats::Scalar iqFloatInstsIssued; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; + Stats::Scalar iqBranchInstsIssued; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; + Stats::Scalar iqMemInstsIssued; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; // Also include number of instructions rescheduled and replayed. /** Distribution of number of instructions in the queue. * @todo: Need to create struct to track the entry time for each * instruction. */ -// Stats::VectorDistribution<> queueResDist; +// Stats::VectorDistribution queueResDist; /** Distribution of the number of instructions issued. */ - Stats::Distribution<> numIssuedDist; + Stats::Distribution numIssuedDist; /** Distribution of the cycles it takes to issue an instruction. * @todo: Need to create struct to track the ready time for each * instruction. */ -// Stats::VectorDistribution<> issueDelayDist; +// Stats::VectorDistribution issueDelayDist; /** Number of times an instruction could not be issued because a * FU was busy. */ - Stats::Vector<> statFuBusy; -// Stats::Vector<> dist_unissued; + Stats::Vector statFuBusy; +// Stats::Vector dist_unissued; /** Stat for total number issued for each instruction type. */ - Stats::Vector2d<> statIssuedInstType; + Stats::Vector2d statIssuedInstType; /** Number of instructions issued per cycle. */ Stats::Formula issueRate; /** Number of times the FU was busy. */ - Stats::Vector<> fuBusy; + Stats::Vector fuBusy; /** Number of times the FU was busy per instruction issued. */ Stats::Formula fuBusyRate; }; diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index fb06f20df..1d0f4b9f6 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -37,12 +37,13 @@ #include "enums/OpClass.hh" #include "sim/core.hh" +#include "params/DerivO3CPU.hh" + template <class Impl> InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, - int fu_idx, - InstructionQueue<Impl> *iq_ptr) - : Event(&mainEventQueue, Stat_Event_Pri), - inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) + int fu_idx, InstructionQueue<Impl> *iq_ptr) + : Event(Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), + freeFU(false) { this->setFlags(Event::AutoDelete); } @@ -65,7 +66,7 @@ InstructionQueue<Impl>::FUCompletion::description() const template <class Impl> InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, - Params *params) + DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), fuPool(params->fuPool), @@ -79,7 +80,7 @@ InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, switchedOut = false; - numThreads = params->numberOfThreads; + numThreads = params->numThreads; // Set the number of physical registers as the number of int + float numPhysRegs = numPhysIntRegs + numPhysFloatRegs; @@ -752,7 +753,7 @@ InstructionQueue<Impl>::scheduleReadyInsts() FUCompletion *execution = new FUCompletion(issuing_inst, idx, this); - execution->schedule(curTick + cpu->ticks(op_latency - 1)); + cpu->schedule(execution, curTick + cpu->ticks(op_latency - 1)); // @todo: Enforce that issue_latency == 1 or op_latency if (issue_latency > 1) { diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 72a8d4021..e9347af91 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -30,21 +30,5 @@ #include "cpu/base.hh" -#if THE_ISA == ALPHA_ISA - #include "cpu/o3/alpha/cpu.hh" - #include "cpu/o3/alpha/impl.hh" - #include "cpu/o3/alpha/params.hh" - #include "cpu/o3/alpha/dyn_inst.hh" -#elif THE_ISA == MIPS_ISA - #include "cpu/o3/mips/cpu.hh" - #include "cpu/o3/mips/impl.hh" - #include "cpu/o3/mips/params.hh" - #include "cpu/o3/mips/dyn_inst.hh" -#elif THE_ISA == SPARC_ISA - #include "cpu/o3/sparc/cpu.hh" - #include "cpu/o3/sparc/impl.hh" - #include "cpu/o3/sparc/params.hh" - #include "cpu/o3/sparc/dyn_inst.hh" -#else - #error "ISA-specific header files O3CPU not defined ISA" -#endif +#include "cpu/o3/impl.hh" +#include "cpu/o3/dyn_inst.hh" diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 06de608e0..cf27552d4 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -40,10 +40,11 @@ #include "mem/port.hh" #include "sim/sim_object.hh" +class DerivO3CPUParams; + template <class Impl> class LSQ { public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -57,7 +58,7 @@ class LSQ { }; /** Constructs an LSQ with the given parameters. */ - LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Returns the name of the LSQ. */ std::string name() const; @@ -297,7 +298,7 @@ class LSQ { public: /** Default constructor. */ DcachePort(LSQ *_lsq) - : Port(_lsq->name() + "-dport"), lsq(_lsq) + : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq) { } bool snoopRangeSent; @@ -370,7 +371,7 @@ template <class T> Fault LSQ<Impl>::read(RequestPtr req, T &data, int load_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].read(req, data, load_idx); } @@ -380,7 +381,7 @@ template <class T> Fault LSQ<Impl>::write(RequestPtr req, T &data, int store_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].write(req, data, store_idx); } diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 8ed6f7f54..8f9f63081 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -34,6 +34,8 @@ #include "cpu/o3/lsq.hh" +#include "params/DerivO3CPU.hh" + template<class Impl> void LSQ<Impl>::DcachePort::setPeer(Port *port) @@ -83,7 +85,7 @@ LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt) if (pkt->isError()) DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr()); if (pkt->isResponse()) { - lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt); + lsq->thread[pkt->req->threadId()].completeDataAccess(pkt); } else { // must be a snoop @@ -111,11 +113,11 @@ LSQ<Impl>::DcachePort::recvRetry() } template <class Impl> -LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) +LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), LQEntries(params->LQEntries), SQEntries(params->SQEntries), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), retryTid(-1) { dcachePort.snoopRangeSent = false; @@ -582,17 +584,14 @@ LSQ<Impl>::hasStoresToWB() std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); - if (threads == end) - return false; - while (threads != end) { unsigned tid = *threads++; - if (!hasStoresToWB(tid)) - return false; + if (hasStoresToWB(tid)) + return true; } - return true; + return false; } template<class Impl> @@ -605,11 +604,11 @@ LSQ<Impl>::willWB() while (threads != end) { unsigned tid = *threads++; - if (!willWB(tid)) - return false; + if (willWB(tid)) + return true; } - return true; + return false; } template<class Impl> diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 128a71dbc..5323e3a47 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -40,11 +40,14 @@ #include "arch/faults.hh" #include "arch/locked_mem.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" #include "mem/port.hh" +class DerivO3CPUParams; + /** * Class that implements the actual LQ and SQ for each specific * thread. Both are circular queues; load entries are freed upon @@ -62,7 +65,6 @@ class LSQUnit { protected: typedef TheISA::IntReg IntReg; public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -74,8 +76,9 @@ class LSQUnit { LSQUnit(); /** Initializes the LSQ unit with the specified number of entries. */ - void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id); + void init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id); /** Returns the name of the LSQ unit. */ std::string name() const; @@ -245,7 +248,7 @@ class LSQUnit { Port *dcachePort; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ @@ -406,35 +409,35 @@ class LSQUnit { // of that in stage that is one level up, and only call executeLoad/Store // the appropriate number of times. /** Total number of loads forwaded from LSQ stores. */ - Stats::Scalar<> lsqForwLoads; + Stats::Scalar lsqForwLoads; /** Total number of loads ignored due to invalid addresses. */ - Stats::Scalar<> invAddrLoads; + Stats::Scalar invAddrLoads; /** Total number of squashed loads. */ - Stats::Scalar<> lsqSquashedLoads; + Stats::Scalar lsqSquashedLoads; /** Total number of responses from the memory system that are * ignored due to the instruction already being squashed. */ - Stats::Scalar<> lsqIgnoredResponses; + Stats::Scalar lsqIgnoredResponses; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; /** Total number of squashed stores. */ - Stats::Scalar<> lsqSquashedStores; + Stats::Scalar lsqSquashedStores; /** Total number of software prefetches ignored due to invalid addresses. */ - Stats::Scalar<> invAddrSwpfs; + Stats::Scalar invAddrSwpfs; /** Ready loads blocked due to partial store-forwarding. */ - Stats::Scalar<> lsqBlockedLoads; + Stats::Scalar lsqBlockedLoads; /** Number of loads that were rescheduled. */ - Stats::Scalar<> lsqRescheduledLoads; + Stats::Scalar lsqRescheduledLoads; /** Number of times the LSQ is blocked due to the cache. */ - Stats::Scalar<> lsqCacheBlocked; + Stats::Scalar lsqCacheBlocked; public: /** Executes the load at the given index. */ @@ -581,7 +584,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx) // We'll say this has a 1 cycle load-store forwarding latency // for now. // @todo: Need to make this a parameter. - wb->schedule(curTick); + cpu->schedule(wb, curTick); ++lsqForwLoads; return NoFault; diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index e6ff5e931..85662d496 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -45,7 +45,7 @@ template<class Impl> LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt, LSQUnit *lsq_ptr) - : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) + : inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) { this->setFlags(Event::AutoDelete); } @@ -112,8 +112,9 @@ LSQUnit<Impl>::LSQUnit() template<class Impl> void -LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id) +LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id) { cpu = cpu_ptr; iewStage = iew_ptr; @@ -683,7 +684,7 @@ LSQUnit<Impl>::writebackStores() "Instantly completing it.\n", inst->seqNum); WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this); - wb->schedule(curTick + 1); + cpu->schedule(wb, curTick + 1); completeStore(storeWBIdx); incrStIdx(storeWBIdx); continue; diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index a12a3001b..4f9e7c9f7 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -48,6 +48,8 @@ struct SNHash { } }; +class DerivO3CPUParams; + template <class Impl> class InstructionQueue; @@ -63,25 +65,28 @@ class InstructionQueue; * dependence prediction schemes. */ template <class MemDepPred, class Impl> -class MemDepUnit { +class MemDepUnit +{ + protected: + std::string _name; + public: - typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; /** Empty constructor. Must call init() prior to using in this case. */ MemDepUnit(); /** Constructs a MemDepUnit with given parameters. */ - MemDepUnit(Params *params); + MemDepUnit(DerivO3CPUParams *params); /** Frees up any memory allocated. */ ~MemDepUnit(); /** Returns the name of the memory dependence unit. */ - std::string name() const; + std::string name() const { return _name; } /** Initializes the unit with parameters and a thread id. */ - void init(Params *params, int tid); + void init(DerivO3CPUParams *params, int tid); /** Registers statistics. */ void regStats(); @@ -252,13 +257,13 @@ class MemDepUnit { int id; /** Stat for number of inserted loads. */ - Stats::Scalar<> insertedLoads; + Stats::Scalar insertedLoads; /** Stat for number of inserted stores. */ - Stats::Scalar<> insertedStores; + Stats::Scalar insertedStores; /** Stat for number of conflicting loads that had to wait for a store. */ - Stats::Scalar<> conflictingLoads; + Stats::Scalar conflictingLoads; /** Stat for number of conflicting stores that had to wait for a store. */ - Stats::Scalar<> conflictingStores; + Stats::Scalar conflictingStores; }; #endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh index 64558efaa..8754539f9 100644 --- a/src/cpu/o3/mem_dep_unit_impl.hh +++ b/src/cpu/o3/mem_dep_unit_impl.hh @@ -33,6 +33,8 @@ #include "cpu/o3/inst_queue.hh" #include "cpu/o3/mem_dep_unit.hh" +#include "params/DerivO3CPU.hh" + template <class MemDepPred, class Impl> MemDepUnit<MemDepPred, Impl>::MemDepUnit() : loadBarrier(false), loadBarrierSN(0), storeBarrier(false), @@ -41,8 +43,9 @@ MemDepUnit<MemDepPred, Impl>::MemDepUnit() } template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params) - : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), +MemDepUnit<MemDepPred, Impl>::MemDepUnit(DerivO3CPUParams *params) + : _name(params->name + ".memdepunit"), + depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) { DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); @@ -74,18 +77,12 @@ MemDepUnit<MemDepPred, Impl>::~MemDepUnit() } template <class MemDepPred, class Impl> -std::string -MemDepUnit<MemDepPred, Impl>::name() const -{ - return "memdepunit"; -} - -template <class MemDepPred, class Impl> void -MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid) +MemDepUnit<MemDepPred, Impl>::init(DerivO3CPUParams *params, int tid) { DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); + _name = csprintf("%s.memDep%d", params->name, tid); id = tid; depPred.init(params->SSITSize, params->LFSTSize); @@ -96,19 +93,19 @@ void MemDepUnit<MemDepPred, Impl>::regStats() { insertedLoads - .name(name() + ".memDep.insertedLoads") + .name(name() + ".insertedLoads") .desc("Number of loads inserted to the mem dependence unit."); insertedStores - .name(name() + ".memDep.insertedStores") + .name(name() + ".insertedStores") .desc("Number of stores inserted to the mem dependence unit."); conflictingLoads - .name(name() + ".memDep.conflictingLoads") + .name(name() + ".conflictingLoads") .desc("Number of conflicting loads."); conflictingStores - .name(name() + ".memDep.conflictingStores") + .name(name() + ".conflictingStores") .desc("Number of conflicting stores."); } diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc deleted file mode 100755 index 420f460b2..000000000 --- a/src/cpu/o3/mips/cpu.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/cpu_impl.hh" -#include "cpu/o3/mips/dyn_inst.hh" - -// Force instantiation of MipsO3CPU for all the implemntations that are -// needed. Consider merging this and mips_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (mips_impl.cc?). -template class MipsO3CPU<MipsSimpleImpl>; diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh deleted file mode 100755 index 3724ced46..000000000 --- a/src/cpu/o3/mips/cpu.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_CPU_HH__ -#define __CPU_O3_MIPS_CPU_HH__ - -#include "arch/mips/regfile.hh" -#include "arch/mips/syscallreturn.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" -#include "sim/faults.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * MipsO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class MipsO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an MipsO3CPU with the given parameters. */ - MipsO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_MIPS_CPU_HH__ diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc deleted file mode 100644 index 4690b9804..000000000 --- a/src/cpu/o3/mips/cpu_builder.cc +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include <string> - -#include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/fu_pool.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public MipsO3CPU<MipsSimpleImpl> -{ - public: - DerivO3CPU(MipsSimpleParams *p) - : MipsO3CPU<MipsSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *cpu; - - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - - MipsSimpleParams *params = new MipsSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->workload = workload; - -#if USE_CHECKER - params->checker = checker; -#endif - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh deleted file mode 100644 index 09d73b4a2..000000000 --- a/src/cpu/o3/mips/cpu_impl.hh +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "config/use_checker.hh" - -#include "arch/mips/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/mips/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -template <class Impl> -MipsO3CPU<Impl>::MipsO3CPU(Params *params) - : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating MipsO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - MipsTC<Impl> *mips_tc = - new MipsTC<Impl>; - - tc = mips_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<MipsTC<Impl> >( - mips_tc, this->checker); - } -#endif - - mips_tc->cpu = this; - mips_tc->thread = this->thread[i]; - - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -MipsO3CPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template <class Impl> -MiscReg -MipsO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -MiscReg -MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -MipsO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); - - DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2)); -} - -template <class Impl> -TheISA::IntReg -MipsO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(MipsISA::ArgumentReg[i], tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(MipsISA::ArgumentReg[i], val, tid); -} - -template <class Impl> -void -MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc deleted file mode 100755 index 216aa7d2c..000000000 --- a/src/cpu/o3/mips/dyn_inst.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/mips/dyn_inst_impl.hh" -#include "cpu/o3/mips/impl.hh" - -// Force instantiation of MipsDynInst for all the implementations that -// are needed. -template class MipsDynInst<MipsSimpleImpl>; diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh deleted file mode 100755 index b1a29ccf9..000000000 --- a/src/cpu/o3/mips/dyn_inst.hh +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_DYN_INST_HH__ -#define __CPU_O3_MIPS_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific MipsDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The MipsDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class MipsDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - MipsDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - /** TODO: Use thread number from argument if given, will probably not work for MIPS MT as is */ - MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - this->instResult.integer = val; - this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - - /** Calls a syscall. */ - void syscall(int64_t callnum); - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - uint64_t readRegOtherThread(int misc_reg) - { - panic("MIPS MT not defined for O3 CPU.\n"); - return 0; - } - - void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) - { - panic("MIPS MT not defined for O3 CPU.\n"); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_MIPS_DYN_INST_HH__ - diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh deleted file mode 100755 index 7e8697b32..000000000 --- a/src/cpu/o3/mips/dyn_inst_impl.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#include "cpu/o3/mips/dyn_inst.hh" - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -MipsDynInst<Impl>::MipsDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -MipsDynInst<Impl>::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template <class Impl> -Fault -MipsDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -MipsDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -MipsDynInst<Impl>::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -template <class Impl> -void -MipsDynInst<Impl>::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} - diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh deleted file mode 100644 index ac7181a19..000000000 --- a/src/cpu/o3/mips/impl.hh +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_IMPL_HH__ -#define __CPU_O3_MIPS_IMPL_HH__ - -#include "arch/mips/isa_traits.hh" - -#include "cpu/o3/mips/params.hh" -#include "cpu/o3/cpu_policy.hh" - - -// Forward declarations. -template <class Impl> -class MipsDynInst; - -template <class Impl> -class MipsO3CPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific O3CPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct MipsSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<MipsSimpleImpl> CPUPol; - - /** The DynInst type to be used. */ - typedef MipsDynInst<MipsSimpleImpl> DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr<DynInst> DynInstPtr; - - /** The O3CPU type to be used. */ - typedef MipsO3CPU<MipsSimpleImpl> O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - /** The Params to be passed to each stage. */ - typedef MipsSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef MipsSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_MIPS_IMPL_HH__ diff --git a/src/cpu/o3/mips/params.hh b/src/cpu/o3/mips/params.hh deleted file mode 100644 index 2688d3fb3..000000000 --- a/src/cpu/o3/mips/params.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_PARAMS_HH__ -#define __CPU_O3_MIPS_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace MipsISA -{ - class MipsDTB; - class MipsITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the MipsO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ - -class MipsSimpleParams : public O3Params -{ - public: - MipsSimpleParams() {} - - //Full System Paramater Objects place here - MipsISA::ITB *itb; - MipsISA::DTB *dtb; -}; - -#endif // __CPU_O3_MIPS_PARAMS_HH__ diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh index 97846ed16..f0621c5b5 100644 --- a/src/cpu/o3/ras.hh +++ b/src/cpu/o3/ras.hh @@ -71,6 +71,9 @@ class ReturnAddrStack */ void restore(unsigned top_entry_idx, const Addr &restored_target); + bool empty() { return usedEntries == 0; } + + bool full() { return usedEntries == numEntries; } private: /** Increments the top of stack index. */ inline void incrTos() diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh index 75d3fa6eb..53ac2d683 100644 --- a/src/cpu/o3/regfile.hh +++ b/src/cpu/o3/regfile.hh @@ -33,6 +33,7 @@ #define __CPU_O3_REGFILE_HH__ #include "arch/isa_traits.hh" +#include "arch/regfile.hh" #include "arch/types.hh" #include "base/trace.hh" #include "config/full_system.hh" @@ -264,7 +265,7 @@ class PhysRegFile #if FULL_SYSTEM private: - int intrflag; // interrupt flag + int intrflag; // interrupt flag #endif private: diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index b2faffe43..0fdf28b19 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultRename handles both single threaded and SMT rename. Its * width is specified by the parameters; each cycle it tries to rename @@ -56,7 +58,6 @@ class DefaultRename typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; // Typedefs from the CPUPol typedef typename CPUPol::DecodeStruct DecodeStruct; @@ -107,7 +108,7 @@ class DefaultRename public: /** DefaultRename constructor. */ - DefaultRename(O3CPU *_cpu, Params *params); + DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of rename. */ std::string name() const; @@ -440,44 +441,44 @@ class DefaultRename inline void incrFullStat(const FullSource &source); /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> renameSquashCycles; + Stats::Scalar renameSquashCycles; /** Stat for total number of cycles spent idle. */ - Stats::Scalar<> renameIdleCycles; + Stats::Scalar renameIdleCycles; /** Stat for total number of cycles spent blocking. */ - Stats::Scalar<> renameBlockCycles; + Stats::Scalar renameBlockCycles; /** Stat for total number of cycles spent stalling for a serializing inst. */ - Stats::Scalar<> renameSerializeStallCycles; + Stats::Scalar renameSerializeStallCycles; /** Stat for total number of cycles spent running normally. */ - Stats::Scalar<> renameRunCycles; + Stats::Scalar renameRunCycles; /** Stat for total number of cycles spent unblocking. */ - Stats::Scalar<> renameUnblockCycles; + Stats::Scalar renameUnblockCycles; /** Stat for total number of renamed instructions. */ - Stats::Scalar<> renameRenamedInsts; + Stats::Scalar renameRenamedInsts; /** Stat for total number of squashed instructions that rename discards. */ - Stats::Scalar<> renameSquashedInsts; + Stats::Scalar renameSquashedInsts; /** Stat for total number of times that the ROB starts a stall in rename. */ - Stats::Scalar<> renameROBFullEvents; + Stats::Scalar renameROBFullEvents; /** Stat for total number of times that the IQ starts a stall in rename. */ - Stats::Scalar<> renameIQFullEvents; + Stats::Scalar renameIQFullEvents; /** Stat for total number of times that the LSQ starts a stall in rename. */ - Stats::Scalar<> renameLSQFullEvents; + Stats::Scalar renameLSQFullEvents; /** Stat for total number of times that rename runs out of free registers * to use to rename. */ - Stats::Scalar<> renameFullRegistersEvents; + Stats::Scalar renameFullRegistersEvents; /** Stat for total number of renamed destination registers. */ - Stats::Scalar<> renameRenamedOperands; + Stats::Scalar renameRenamedOperands; /** Stat for total number of source register rename lookups. */ - Stats::Scalar<> renameRenameLookups; + Stats::Scalar renameRenameLookups; /** Stat for total number of committed renaming mappings. */ - Stats::Scalar<> renameCommittedMaps; + Stats::Scalar renameCommittedMaps; /** Stat for total number of mappings that were undone due to a squash. */ - Stats::Scalar<> renameUndoneMaps; + Stats::Scalar renameUndoneMaps; /** Number of serialize instructions handled. */ - Stats::Scalar<> renamedSerializing; + Stats::Scalar renamedSerializing; /** Number of instructions marked as temporarily serializing. */ - Stats::Scalar<> renamedTempSerializing; + Stats::Scalar renamedTempSerializing; /** Number of instructions inserted into skid buffers. */ - Stats::Scalar<> renameSkidInsts; + Stats::Scalar renameSkidInsts; }; #endif // __CPU_O3_RENAME_HH__ diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 49c885753..81647b133 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -35,9 +35,10 @@ #include "arch/regfile.hh" #include "config/full_system.hh" #include "cpu/o3/rename.hh" +#include "params/DerivO3CPU.hh" template <class Impl> -DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params) +DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), iewToRenameDelay(params->iewToRenameDelay), decodeToRenameDelay(params->decodeToRenameDelay), @@ -46,7 +47,7 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params) commitWidth(params->commitWidth), resumeSerialize(false), resumeUnblocking(false), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs) { _status = Inactive; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh deleted file mode 100644 index 3fd193e0f..000000000 --- a/src/cpu/o3/sparc/cpu.hh +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Kevin Lim - */ - -#ifndef __CPU_O3_SPARC_CPU_HH__ -#define __CPU_O3_SPARC_CPU_HH__ - -#include "arch/sparc/regfile.hh" -#include "arch/sparc/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * SparcO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template <class Impl> -class SparcO3CPU : public FullO3CPU<Impl> -{ - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaO3CPU with the given parameters. */ - SparcO3CPU(Params *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_SPARC_CPU_HH__ diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc deleted file mode 100644 index b08845b4e..000000000 --- a/src/cpu/o3/sparc/cpu_builder.cc +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Gabe Black - */ - -#include <string> - -#include "config/full_system.hh" -#include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/params.hh" -#include "cpu/o3/fu_pool.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl> -{ - public: - DerivO3CPU(SparcSimpleParams *p) - : SparcO3CPU<SparcSimpleImpl>(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ - DerivO3CPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - SparcSimpleParams *params = new SparcSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; - else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivO3CPU(params); - - return cpu; -} diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh deleted file mode 100644 index 068057fc0..000000000 --- a/src/cpu/o3/sparc/cpu_impl.hh +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Gabe Black - */ - -#include "config/use_checker.hh" - -#include "arch/sparc/faults.hh" -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/miscregfile.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/params.hh" -#include "cpu/o3/sparc/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -template <class Impl> -SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(this, params) -{ - DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - SparcTC<Impl> *sparc_tc = new SparcTC<Impl>; - - tc = sparc_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext<SparcTC<Impl> >( - sparc_tc, this->checker); - } -#endif - - sparc_tc->cpu = this; - sparc_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -SparcO3CPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template <class Impl> -TheISA::MiscReg -SparcO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template <class Impl> -TheISA::MiscReg -SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setMiscReg(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template <class Impl> -Fault -SparcO3CPU<Impl>::hwrei(unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return NoFault; -} - -template <class Impl> -bool -SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return true; -} - -template <class Impl> -Fault -SparcO3CPU<Impl>::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template <class Impl> -void -SparcO3CPU<Impl>::processInterrupts(Fault interrupt) -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template <class Impl> -void -SparcO3CPU<Impl>::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -SparcO3CPU<Impl>::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - TheISA::IntReg val = this->readArchIntReg(idx, tid); - if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3)) - val = bits(val, 31, 0); - return val; -} - -template <class Impl> -void -SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - this->setArchIntReg(idx, val, tid); -} - -template <class Impl> -void -SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh deleted file mode 100644 index a7ab6cd79..000000000 --- a/src/cpu/o3/sparc/dyn_inst.hh +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Gabe Black - */ - -#ifndef __CPU_O3_SPARC_DYN_INST_HH__ -#define __CPU_O3_SPARC_DYN_INST_HH__ - -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/types.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific SparcDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The SparcDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class SparcDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - public: - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - SparcDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, - int idx, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand( - const StaticInst *si, int idx, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]); - DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val); - return val; - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val); - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, - TheISA::FloatReg val, int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - TheISA::FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, - int idx, TheISA::FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_SPARC_DYN_INST_HH__ - diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh deleted file mode 100644 index 6bfe97717..000000000 --- a/src/cpu/o3/sparc/dyn_inst_impl.hh +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Gabe Black - */ - -#include "cpu/o3/sparc/dyn_inst.hh" - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst<Impl>(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -SparcDynInst<Impl>::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template <class Impl> -Fault -SparcDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -SparcDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -SparcDynInst<Impl>::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -#if FULL_SYSTEM -template <class Impl> -Fault -SparcDynInst<Impl>::hwrei() -{ - return NoFault; -} - -template <class Impl> -void -SparcDynInst<Impl>::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template <class Impl> -bool -SparcDynInst<Impl>::simPalCheck(int palFunc) -{ - panic("simPalCheck called, but there's no PAL in SPARC!\n"); - return false; -} -#else -template <class Impl> -void -SparcDynInst<Impl>::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} -#endif - diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/thread_context.cc index 4a02715bc..0d8c67643 100755 --- a/src/cpu/o3/alpha/thread_context.cc +++ b/src/cpu/o3/thread_context.cc @@ -26,11 +26,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim - * Korey Sewell */ #include "cpu/o3/thread_context.hh" #include "cpu/o3/thread_context_impl.hh" +#include "cpu/o3/impl.hh" -template class O3ThreadContext<AlphaSimpleImpl>; +template class O3ThreadContext<O3CPUImpl>; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index e7bdc6de5..f3058925d 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -75,16 +75,21 @@ class O3ThreadContext : public ThreadContext /** Returns a pointer to this CPU. */ virtual BaseCPU *getCpuPtr() { return cpu; } - /** Sets this CPU's ID. */ - virtual void setCpuId(int id) { cpu->setCpuId(id); } - /** Reads this CPU's ID. */ - virtual int readCpuId() { return cpu->readCpuId(); } + virtual int cpuId() { return cpu->cpuId(); } + + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } -#if FULL_SYSTEM /** Returns a pointer to the system. */ virtual System *getSystemPtr() { return cpu->system; } +#if FULL_SYSTEM /** Returns a pointer to physical memory. */ virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } @@ -94,11 +99,9 @@ class O3ThreadContext : public ThreadContext virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL); - - void delVirtPort(VirtualPort *vp); + virtual VirtualPort *getVirtPort(); - virtual void connectMemPorts() { thread->connectMemPorts(); } + virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); } #else virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } @@ -153,9 +156,6 @@ class O3ThreadContext : public ThreadContext /** Samples the function profiling information. */ virtual void profileSample(); #endif - /** Returns this thread's ID number. */ - virtual int getThreadNum() { return thread->readTid(); } - /** Returns the instruction this thread is currently committing. * Only used when an instruction faults. */ @@ -191,36 +191,36 @@ class O3ThreadContext : public ThreadContext /** Reads this thread's PC. */ virtual uint64_t readPC() - { return cpu->readPC(thread->readTid()); } + { return cpu->readPC(thread->threadId()); } /** Sets this thread's PC. */ virtual void setPC(uint64_t val); /** Reads this thread's next PC. */ virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->readTid()); } + { return cpu->readNextPC(thread->threadId()); } /** Sets this thread's next PC. */ virtual void setNextPC(uint64_t val); virtual uint64_t readMicroPC() - { return cpu->readMicroPC(thread->readTid()); } + { return cpu->readMicroPC(thread->threadId()); } virtual void setMicroPC(uint64_t val); virtual uint64_t readNextMicroPC() - { return cpu->readNextMicroPC(thread->readTid()); } + { return cpu->readNextMicroPC(thread->threadId()); } virtual void setNextMicroPC(uint64_t val); /** Reads a miscellaneous register. */ virtual MiscReg readMiscRegNoEffect(int misc_reg) - { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + { return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); } /** Reads a misc. register, including any side-effects the * read might have as defined by the architecture. */ virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->readTid()); } + { return cpu->readMiscReg(misc_reg, thread->threadId()); } /** Sets a misc. register. */ virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); @@ -247,22 +247,48 @@ class O3ThreadContext : public ThreadContext virtual bool misspeculating() { return false; } #if !FULL_SYSTEM - /** Gets a syscall argument by index. */ - virtual IntReg getSyscallArg(int i); - - /** Sets a syscall argument. */ - virtual void setSyscallArg(int i, IntReg val); - - /** Sets the syscall return value. */ - virtual void setSyscallReturn(SyscallReturn return_value); - /** Executes a syscall in SE mode. */ virtual void syscall(int64_t callnum) - { return cpu->syscall(callnum, thread->readTid()); } + { return cpu->syscall(callnum, thread->threadId()); } /** Reads the funcExeInst counter. */ virtual Counter readFuncExeInst() { return thread->funcExeInst; } +#else + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent() + { + return this->thread->quiesceEvent; + } #endif + + virtual uint64_t readNextNPC() + { + return this->cpu->readNextNPC(this->thread->threadId()); + } + + virtual void setNextNPC(uint64_t val) + { +#if THE_ISA == ALPHA_ISA + panic("Not supported on Alpha!"); +#endif + this->cpu->setNextNPC(val, this->thread->threadId()); + } + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system + if (this->cpu->numActiveThreads()) + return 0; // don't exit simulation + else + return 1; // exit simulation + } }; #endif diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 865d58635..fc8b66b83 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -36,16 +36,9 @@ #if FULL_SYSTEM template <class Impl> VirtualPort * -O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc) +O3ThreadContext<Impl>::getVirtPort() { - if (!src_tc) - return thread->getVirtPort(); - - VirtualPort *vp; - - vp = new VirtualPort("tc-vport", src_tc); - thread->connectToMemFunc(vp); - return vp; + return thread->getVirtPort(); } template <class Impl> @@ -61,16 +54,16 @@ void O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context) { // some things should already be set up -#if FULL_SYSTEM assert(getSystemPtr() == old_context->getSystemPtr()); -#else +#if !FULL_SYSTEM assert(getProcessPtr() == old_context->getProcessPtr()); #endif // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); + setContextId(old_context->contextId()); + setThreadId(old_context->threadId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); @@ -97,24 +90,12 @@ O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context) thread->trapPending = false; } -#if FULL_SYSTEM -template <class Impl> -void -O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp) -{ - if (vp != thread->getVirtPort()) { - vp->removeConn(); - delete vp; - } -} -#endif - template <class Impl> void O3ThreadContext<Impl>::activate(int delay) { DPRINTF(O3CPU, "Calling activate on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Active) return; @@ -124,14 +105,14 @@ O3ThreadContext<Impl>::activate(int delay) #endif if (thread->status() == ThreadContext::Unallocated) { - cpu->activateWhenReady(thread->readTid()); + cpu->activateWhenReady(thread->threadId()); return; } thread->setStatus(ThreadContext::Active); // status() == Suspended - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } template <class Impl> @@ -139,7 +120,7 @@ void O3ThreadContext<Impl>::suspend(int delay) { DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Suspended) return; @@ -151,14 +132,14 @@ O3ThreadContext<Impl>::suspend(int delay) /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } #endif */ thread->setStatus(ThreadContext::Suspended); - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } template <class Impl> @@ -166,13 +147,13 @@ void O3ThreadContext<Impl>::deallocate(int delay) { DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n", - getThreadNum(), delay); + threadId(), delay); if (thread->status() == ThreadContext::Unallocated) return; thread->setStatus(ThreadContext::Unallocated); - cpu->deallocateContext(thread->readTid(), true, delay); + cpu->deallocateContext(thread->threadId(), true, delay); } template <class Impl> @@ -180,13 +161,13 @@ void O3ThreadContext<Impl>::halt(int delay) { DPRINTF(O3CPU, "Calling halt on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Halted) return; thread->setStatus(ThreadContext::Halted); - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } template <class Impl> @@ -264,7 +245,7 @@ O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc) { // This function will mess things up unless the ROB is empty and // there are no instructions in the pipeline. - unsigned tid = thread->readTid(); + unsigned tid = thread->threadId(); PhysRegIndex renamed_reg; // First loop through the integer registers. @@ -311,7 +292,7 @@ uint64_t O3ThreadContext<Impl>::readIntReg(int reg_idx) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - return cpu->readArchIntReg(reg_idx, thread->readTid()); + return cpu->readArchIntReg(reg_idx, thread->threadId()); } template <class Impl> @@ -321,9 +302,9 @@ O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); case 64: - return cpu->readArchFloatRegDouble(reg_idx, thread->readTid()); + return cpu->readArchFloatRegDouble(reg_idx, thread->threadId()); default: panic("Unsupported width!"); return 0; @@ -335,7 +316,7 @@ TheISA::FloatReg O3ThreadContext<Impl>::readFloatReg(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); } template <class Impl> @@ -344,7 +325,7 @@ O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width) { DPRINTF(Fault, "Reading floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template <class Impl> @@ -352,7 +333,7 @@ TheISA::FloatRegBits O3ThreadContext<Impl>::readFloatRegBits(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template <class Impl> @@ -360,11 +341,11 @@ void O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - cpu->setArchIntReg(reg_idx, val, thread->readTid()); + cpu->setArchIntReg(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -375,16 +356,16 @@ O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); break; case 64: - cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId()); break; } // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -393,10 +374,10 @@ void O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -407,11 +388,11 @@ O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, { DPRINTF(Fault, "Setting floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -420,11 +401,11 @@ void O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -432,11 +413,11 @@ template <class Impl> void O3ThreadContext<Impl>::setPC(uint64_t val) { - cpu->setPC(val, thread->readTid()); + cpu->setPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -444,11 +425,11 @@ template <class Impl> void O3ThreadContext<Impl>::setNextPC(uint64_t val) { - cpu->setNextPC(val, thread->readTid()); + cpu->setNextPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -456,11 +437,11 @@ template <class Impl> void O3ThreadContext<Impl>::setMicroPC(uint64_t val) { - cpu->setMicroPC(val, thread->readTid()); + cpu->setMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -468,11 +449,11 @@ template <class Impl> void O3ThreadContext<Impl>::setNextMicroPC(uint64_t val) { - cpu->setNextMicroPC(val, thread->readTid()); + cpu->setNextMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -480,11 +461,11 @@ template <class Impl> void O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { - cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); + cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -493,36 +474,11 @@ void O3ThreadContext<Impl>::setMiscReg(int misc_reg, const MiscReg &val) { - cpu->setMiscReg(misc_reg, val, thread->readTid()); + cpu->setMiscReg(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } -#if !FULL_SYSTEM - -template <class Impl> -TheISA::IntReg -O3ThreadContext<Impl>::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->readTid()); -} - -template <class Impl> -void -O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->readTid()); -} - -template <class Impl> -void -O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->readTid()); -} - -#endif // FULL_SYSTEM - diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh index d8720b3ab..1f0e7a3bb 100644 --- a/src/cpu/o3/thread_state.hh +++ b/src/cpu/o3/thread_state.hh @@ -77,11 +77,11 @@ struct O3ThreadState : public ThreadState { #if FULL_SYSTEM O3ThreadState(O3CPU *_cpu, int _thread_num) - : ThreadState(_cpu, -1, _thread_num), + : ThreadState(_cpu, _thread_num), cpu(_cpu), inSyscall(0), trapPending(0) { - if (cpu->params->profile) { - profile = new FunctionProfile(cpu->params->system->kernelSymtab); + if (cpu->params()->profile) { + profile = new FunctionProfile(cpu->params()->system->kernelSymtab); Callback *cb = new MakeCallback<O3ThreadState, &O3ThreadState::dumpFuncProfile>(this); @@ -96,7 +96,7 @@ struct O3ThreadState : public ThreadState { } #else O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), inSyscall(0), trapPending(0) { } #endif diff --git a/src/cpu/ozone/OzoneCPU.py b/src/cpu/ozone/OzoneCPU.py index b9cfb448f..37386898d 100644 --- a/src/cpu/ozone/OzoneCPU.py +++ b/src/cpu/ozone/OzoneCPU.py @@ -40,8 +40,6 @@ class DerivOzoneCPU(BaseCPU): if build_env['USE_CHECKER']: checker = Param.BaseCPU("Checker CPU") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") diff --git a/src/cpu/ozone/OzoneChecker.py b/src/cpu/ozone/OzoneChecker.py index f20b8770e..bfa39ead9 100644 --- a/src/cpu/ozone/OzoneChecker.py +++ b/src/cpu/ozone/OzoneChecker.py @@ -39,5 +39,3 @@ class OzoneChecker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh index 4cdc86c3c..ca858ce2e 100644 --- a/src/cpu/ozone/back_end.hh +++ b/src/cpu/ozone/back_end.hh @@ -157,13 +157,13 @@ class BackEnd int numInsts; int width; - Stats::VectorDistribution<> occ_dist; + Stats::VectorDistribution occ_dist; - Stats::Vector<> inst_count; - Stats::Vector<> peak_inst_count; - Stats::Scalar<> empty_count; - Stats::Scalar<> current_count; - Stats::Scalar<> fullCount; + Stats::Vector inst_count; + Stats::Vector peak_inst_count; + Stats::Scalar empty_count; + Stats::Scalar current_count; + Stats::Scalar fullCount; Stats::Formula occ_rate; Stats::Formula avg_residency; @@ -371,45 +371,45 @@ class BackEnd bool fetchRedirect[Impl::MaxThreads]; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> rob_cap_events; - Stats::Vector<> rob_cap_inst_count; - Stats::Vector<> iq_cap_events; - Stats::Vector<> iq_cap_inst_count; + Stats::Vector rob_cap_events; + Stats::Vector rob_cap_inst_count; + Stats::Vector iq_cap_events; + Stats::Vector iq_cap_inst_count; // total number of instructions executed - Stats::Vector<> exe_inst; - Stats::Vector<> exe_swp; - Stats::Vector<> exe_nop; - Stats::Vector<> exe_refs; - Stats::Vector<> exe_loads; - Stats::Vector<> exe_branches; + Stats::Vector exe_inst; + Stats::Vector exe_swp; + Stats::Vector exe_nop; + Stats::Vector exe_refs; + Stats::Vector exe_loads; + Stats::Vector exe_branches; - Stats::Vector<> issued_ops; + Stats::Vector issued_ops; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; + Stats::Vector lsq_forw_loads; // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; + Stats::Vector inv_addr_loads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; + Stats::Vector inv_addr_swpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; + Stats::Vector lsq_blocked_loads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> n_issued_dist; - Stats::VectorDistribution<> issue_delay_dist; + Stats::Vector n_issued_dist; + Stats::VectorDistribution issue_delay_dist; - Stats::VectorDistribution<> queue_res_dist; + Stats::VectorDistribution queue_res_dist; /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -422,34 +422,34 @@ class BackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writeback_count; - Stats::Vector<> producer_inst; - Stats::Vector<> consumer_inst; - Stats::Vector<> wb_penalized; + Stats::Vector writeback_count; + Stats::Vector producer_inst; + Stats::Vector consumer_inst; + Stats::Vector wb_penalized; Stats::Formula wb_rate; Stats::Formula wb_fanout; Stats::Formula wb_penalized_rate; // total number of instructions committed - Stats::Vector<> stat_com_inst; - Stats::Vector<> stat_com_swp; - Stats::Vector<> stat_com_refs; - Stats::Vector<> stat_com_loads; - Stats::Vector<> stat_com_membars; - Stats::Vector<> stat_com_branches; + Stats::Vector stat_com_inst; + Stats::Vector stat_com_swp; + Stats::Vector stat_com_refs; + Stats::Vector stat_com_loads; + Stats::Vector stat_com_membars; + Stats::Vector stat_com_branches; - Stats::Distribution<> n_committed_dist; + Stats::Distribution n_committed_dist; - Stats::Scalar<> commit_eligible_samples; - Stats::Vector<> commit_eligible; + Stats::Scalar commit_eligible_samples; + Stats::Vector commit_eligible; - Stats::Scalar<> ROB_fcount; + Stats::Scalar ROB_fcount; Stats::Formula ROB_full_rate; - Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Vector ROB_count; // cumulative ROB occupancy Stats::Formula ROB_occ_rate; - Stats::VectorDistribution<> ROB_occ_dist; + Stats::VectorDistribution ROB_occ_dist; public: void dumpInsts(); }; @@ -482,8 +482,8 @@ BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx) memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } else { // do functional access @@ -524,8 +524,8 @@ BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx) if (result != MA_HIT && dcacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } } diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc index 5a3a69dff..e0570fd16 100644 --- a/src/cpu/ozone/base_dyn_inst.cc +++ b/src/cpu/ozone/base_dyn_inst.cc @@ -33,7 +33,3 @@ // Explicit instantiation template class BaseDynInst<OzoneImpl>; - -template <> -int -BaseDynInst<OzoneImpl>::instcount = 0; diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index b0ea2cba9..0bfb4bfa9 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -116,10 +116,6 @@ class OzoneCPU : public BaseCPU BaseCPU *getCpuPtr(); - void setCpuId(int id); - - int readCpuId() { return thread->readCpuId(); } - TheISA::ITB *getITBPtr() { return cpu->itb; } TheISA::DTB * getDTBPtr() { return cpu->dtb; } @@ -134,10 +130,8 @@ class OzoneCPU : public BaseCPU FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) - { return thread->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp); + VirtualPort *getVirtPort() + { return thread->getVirtPort(); } #else TranslatingPort *getMemPort() { return thread->getMemPort(); } @@ -182,7 +176,7 @@ class OzoneCPU : public BaseCPU void profileSample(); #endif - int getThreadNum(); + int threadId(); // Also somewhat obnoxious. Really only used for the TLB fault. TheISA::MachInst getInst(); @@ -252,30 +246,11 @@ class OzoneCPU : public BaseCPU bool misspeculating() { return false; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - return thread->renameTable[TheISA::ArgumentReg[i]]->readIntResult(); - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - thread->renameTable[TheISA::ArgumentReg[i]]->setIntResult(i); - } - - void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->readTid()); } - Counter readFuncExeInst() { return thread->funcExeInst; } void setFuncExeInst(Counter new_val) { thread->funcExeInst = new_val; } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } }; // Ozone specific thread context @@ -296,6 +271,11 @@ class OzoneCPU : public BaseCPU // main simulation loop (one cycle) void tick(); +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + std::set<InstSeqNum> snList; std::set<Addr> lockAddrList; private: @@ -337,7 +317,7 @@ class OzoneCPU : public BaseCPU Status _status; public: - void post_interrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; @@ -358,12 +338,6 @@ class OzoneCPU : public BaseCPU public: BaseCPU *getCpuPtr() { return this; } - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } - - int cpuId; - void switchOut(); void signalSwitched(); void takeOverFrom(BaseCPU *oldCPU); @@ -416,7 +390,7 @@ class OzoneCPU : public BaseCPU Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; public: @@ -425,59 +399,20 @@ class OzoneCPU : public BaseCPU void demapPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); - dtb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); + cpu->dtb->demap(vaddr, asn); } void demapInstPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); } void demapDataPage(Addr vaddr, uint64_t asn) { - dtb->demap(vaddr, asn); - } - -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return dtb->translate(req, thread->getTC(), true); - } - -#else - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); + cpu->dtb->demap(vaddr, asn); } - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } -#endif - /** CPU read function, forwards read to LSQ. */ template <class T> Fault read(Request *req, T &data, int load_idx) @@ -517,7 +452,6 @@ class OzoneCPU : public BaseCPU void processInterrupts(); #else void syscall(uint64_t &callnum); - void setSyscallReturn(SyscallReturn return_value, int tid); #endif ThreadContext *tcBase() { return tc; } @@ -539,7 +473,7 @@ class OzoneCPU : public BaseCPU bool lockFlag; - Stats::Scalar<> quiesceCycles; + Stats::Scalar quiesceCycles; Checker<DynInstPtr> *checker; }; diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 0c7105382..aa76c8aa6 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -95,6 +95,9 @@ OzoneCPU<Impl>::OzoneCPU(Params *p) : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), #endif +#ifndef NDEBUG + instcount(0), +#endif comm(5, 5) { frontEnd = new FrontEnd(p); @@ -417,7 +420,7 @@ OzoneCPU<Impl>::init() ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, tc->readCpuId()); + TheISA::initCPU(tc, tc->contextId()); } #endif frontEnd->renameTable.copyFrom(thread.renameTable); @@ -579,16 +582,14 @@ OzoneCPU<Impl>::dbg_vtophys(Addr addr) #if FULL_SYSTEM template <class Impl> void -OzoneCPU<Impl>::post_interrupt(int int_num, int index) +OzoneCPU<Impl>::wakeup() { - BaseCPU::post_interrupt(int_num, index); - if (_status == Idle) { DPRINTF(IPI,"Suspended Processor awoke\n"); -// thread.activate(); +// thread.activate(); // Hack for now. Otherwise might have to go through the tc, or // I need to figure out what's the right thing to call. - activateContext(thread.readTid(), 1); + activateContext(thread.threadId(), 1); } } #endif // FULL_SYSTEM @@ -647,26 +648,6 @@ OzoneCPU<Impl>::syscall(uint64_t &callnum) frontEnd->renameTable.copyFrom(thread.renameTable); backEnd->renameTable.copyFrom(thread.renameTable); } - -template <class Impl> -void -OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - thread.renameTable[SyscallSuccessReg]->setIntResult(0); - thread.renameTable[ReturnValueReg]->setIntResult( - return_value.value()); - } else { - // got an error, return details - thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1); - thread.renameTable[ReturnValueReg]->setIntResult( - -return_value.value()); - } -} #else template <class Impl> Fault @@ -693,10 +674,10 @@ OzoneCPU<Impl>::processInterrupts() // Check if there are any outstanding interrupts //Handle the interrupts - Fault interrupt = this->interrupts.getInterrupt(thread.getTC()); + Fault interrupt = this->interrupts->getInterrupt(thread.getTC()); if (interrupt != NoFault) { - this->interrupts.updateIntrInfo(thread.getTC()); + this->interrupts->updateIntrInfo(thread.getTC()); interrupt->invoke(thread.getTC()); } } @@ -711,7 +692,7 @@ OzoneCPU<Impl>::simPalCheck(int palFunc) switch (palFunc) { case PAL::halt: - haltContext(thread.readTid()); + haltContext(thread.threadId()); if (--System::numSystemsRunning == 0) exitSimLoop("all cpus halted"); break; @@ -736,24 +717,6 @@ OzoneCPU<Impl>::OzoneTC::getCpuPtr() template <class Impl> void -OzoneCPU<Impl>::OzoneTC::setCpuId(int id) -{ - cpu->cpuId = id; - thread->setCpuId(id); -} - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp) -{ - vp->removeConn(); - delete vp; -} -#endif - -template <class Impl> -void OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status) { thread->setStatus(new_status); @@ -763,7 +726,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::activate(int delay) { - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } /// Set the status to Suspended. @@ -771,7 +734,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::suspend() { - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } /// Set the status to Unallocated. @@ -779,7 +742,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::deallocate(int delay) { - cpu->deallocateContext(thread->readTid(), delay); + cpu->deallocateContext(thread->threadId(), delay); } /// Set the status to Halted. @@ -787,7 +750,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::halt() { - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } #if FULL_SYSTEM @@ -813,7 +776,8 @@ OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); + setCpuId(old_context->cpuId()); + setContextId(old_context->contextId()); thread->setInst(old_context->getInst()); #if !FULL_SYSTEM @@ -901,9 +865,9 @@ OzoneCPU<Impl>::OzoneTC::profileSample() template <class Impl> int -OzoneCPU<Impl>::OzoneTC::getThreadNum() +OzoneCPU<Impl>::OzoneTC::threadId() { - return thread->readTid(); + return thread->threadId(); } template <class Impl> diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index 667392c06..38fc89e3f 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -275,48 +275,48 @@ class FrontEnd private: // number of idle cycles /* - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; */ // @todo: Consider making these vectors and tracking on a per thread basis. /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedInsts; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; -// Stats::Vector<> qfull_iq_occupancy; -// Stats::VectorDistribution<> qfull_iq_occ_dist_; + Stats::Distribution fetchNisnDist; +// Stats::Vector qfull_iq_occupancy; +// Stats::VectorDistribution qfull_iq_occ_dist_; Stats::Formula idleRate; Stats::Formula branchRate; Stats::Formula fetchRate; - Stats::Scalar<> IFQCount; // cumulative IFQ occupancy + Stats::Scalar IFQCount; // cumulative IFQ occupancy Stats::Formula IFQOccupancy; Stats::Formula IFQLatency; - Stats::Scalar<> IFQFcount; // cumulative IFQ full count + Stats::Scalar IFQFcount; // cumulative IFQ full count Stats::Formula IFQFullRate; - Stats::Scalar<> dispatchCountStat; - Stats::Scalar<> dispatchedSerializing; - Stats::Scalar<> dispatchedTempSerializing; - Stats::Scalar<> dispatchSerializeStallCycles; + Stats::Scalar dispatchCountStat; + Stats::Scalar dispatchedSerializing; + Stats::Scalar dispatchedTempSerializing; + Stats::Scalar dispatchSerializeStallCycles; Stats::Formula dispatchRate; Stats::Formula regIntFull; Stats::Formula regFpFull; diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index 198ce0308..6b47ef539 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -477,10 +477,10 @@ FrontEnd<Impl>::fetchCacheLine() // Setup the memReq to do a read of the first isntruction's address. // Set the appropriate read size and flags as well. memReq = new Request(0, fetch_PC, cacheBlkSize, 0, - PC, cpu->readCpuId(), 0); + PC, cpu->thread->contextId()); // Translate the instruction request. - fault = cpu->translateInstReq(memReq, thread); + fault = cpu->itb->translateAtomic(memReq, thread); // Now do the timing access to see whether or not the instruction // exists within the cache. diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index aef29b1e2..e930144be 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -192,7 +192,7 @@ class InorderBackEnd TimeBuffer<CommStruct> *comm; // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; }; @@ -204,7 +204,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataReadReq(memReq); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), false); // if we have a cache, do cache access too if (fault == NoFault && dcacheInterface) { @@ -222,7 +222,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) // are executed twice. memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -245,11 +245,11 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataWriteReq(memReq); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), true); if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; -// memcpy(memReq->data,(uint8_t *)&data,memReq->size); +// memcpy(memReq->data,(uint8_t *)&data,memReq->size); memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; @@ -261,7 +261,7 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) if (result != MA_HIT) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -307,7 +307,7 @@ InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss load stall!\n"); } else { @@ -372,7 +372,7 @@ InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss store stall!\n"); } else { diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh index cf8634a42..798b628d6 100644 --- a/src/cpu/ozone/inorder_back_end_impl.hh +++ b/src/cpu/ozone/inorder_back_end_impl.hh @@ -149,8 +149,7 @@ InorderBackEnd<Impl>::tick() // if (interrupt) then set thread PC, stall front end, record that // I'm waiting for it to drain. (for now just squash) #if FULL_SYSTEM - if (interruptBlocked || - cpu->check_interrupts(tc)) { + if (interruptBlocked || cpu->checkInterrupts(tc)) { if (!robEmpty()) { interruptBlocked = true; //AlphaDep diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh index a11d5204b..e840d5c21 100644 --- a/src/cpu/ozone/inst_queue.hh +++ b/src/cpu/ozone/inst_queue.hh @@ -473,35 +473,35 @@ class InstQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; -// Stats::Scalar<> iqIntInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; +// Stats::Scalar iqIntInstsAdded; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; -// Stats::Scalar<> iqFloatInstsAdded; + Stats::Scalar iqIntInstsIssued; +// Stats::Scalar iqFloatInstsAdded; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; -// Stats::Scalar<> iqBranchInstsAdded; + Stats::Scalar iqFloatInstsIssued; +// Stats::Scalar iqBranchInstsAdded; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; -// Stats::Scalar<> iqMemInstsAdded; + Stats::Scalar iqBranchInstsIssued; +// Stats::Scalar iqMemInstsAdded; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; -// Stats::Scalar<> iqMiscInstsAdded; + Stats::Scalar iqMemInstsIssued; +// Stats::Scalar iqMiscInstsAdded; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; }; diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh index 981682c26..47be245e5 100644 --- a/src/cpu/ozone/lsq_unit.hh +++ b/src/cpu/ozone/lsq_unit.hh @@ -331,7 +331,7 @@ class OzoneLSQ { //list<InstSeqNum> mshrSeqNums; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; /** Wire to read information from the issue stage time queue. */ diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh index 84a90eede..c24410520 100644 --- a/src/cpu/ozone/lsq_unit_impl.hh +++ b/src/cpu/ozone/lsq_unit_impl.hh @@ -553,7 +553,7 @@ OzoneLSQ<Impl>::writebackStores() MemReqPtr req = storeQueue[storeWBIdx].req; storeQueue[storeWBIdx].committed = true; -// Fault fault = cpu->translateDataReadReq(req); +// Fault fault = cpu->translateDataReadReq(req); req->cmd = Write; req->completionEvent = NULL; req->time = curTick; diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh index a335ab7dc..4a1657c9b 100644 --- a/src/cpu/ozone/lw_back_end.hh +++ b/src/cpu/ozone/lw_back_end.hh @@ -326,47 +326,47 @@ class LWBackEnd bool exactFullStall; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> robCapEvents; - Stats::Vector<> robCapInstCount; - Stats::Vector<> iqCapEvents; - Stats::Vector<> iqCapInstCount; + Stats::Vector robCapEvents; + Stats::Vector robCapInstCount; + Stats::Vector iqCapEvents; + Stats::Vector iqCapInstCount; // total number of instructions executed - Stats::Vector<> exeInst; - Stats::Vector<> exeSwp; - Stats::Vector<> exeNop; - Stats::Vector<> exeRefs; - Stats::Vector<> exeLoads; - Stats::Vector<> exeBranches; + Stats::Vector exeInst; + Stats::Vector exeSwp; + Stats::Vector exeNop; + Stats::Vector exeRefs; + Stats::Vector exeLoads; + Stats::Vector exeBranches; - Stats::Vector<> issuedOps; + Stats::Vector issuedOps; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsqForwLoads; + Stats::Vector lsqForwLoads; // total number of loads ignored due to invalid addresses - Stats::Vector<> invAddrLoads; + Stats::Vector invAddrLoads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> invAddrSwpfs; + Stats::Vector invAddrSwpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsqBlockedLoads; + Stats::Vector lsqBlockedLoads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> nIssuedDist; + Stats::Vector nIssuedDist; /* - Stats::VectorDistribution<> issueDelayDist; + Stats::VectorDistribution issueDelayDist; - Stats::VectorDistribution<> queueResDist; + Stats::VectorDistribution queueResDist; */ /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -379,37 +379,37 @@ class LWBackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writebackCount; - Stats::Vector<> producerInst; - Stats::Vector<> consumerInst; - Stats::Vector<> wbPenalized; + Stats::Vector writebackCount; + Stats::Vector producerInst; + Stats::Vector consumerInst; + Stats::Vector wbPenalized; Stats::Formula wbRate; Stats::Formula wbFanout; Stats::Formula wbPenalizedRate; // total number of instructions committed - Stats::Vector<> statComInst; - Stats::Vector<> statComSwp; - Stats::Vector<> statComRefs; - Stats::Vector<> statComLoads; - Stats::Vector<> statComMembars; - Stats::Vector<> statComBranches; + Stats::Vector statComInst; + Stats::Vector statComSwp; + Stats::Vector statComRefs; + Stats::Vector statComLoads; + Stats::Vector statComMembars; + Stats::Vector statComBranches; - Stats::Distribution<> nCommittedDist; + Stats::Distribution nCommittedDist; - Stats::Scalar<> commitEligibleSamples; - Stats::Vector<> commitEligible; + Stats::Scalar commitEligibleSamples; + Stats::Vector commitEligible; - Stats::Vector<> squashedInsts; - Stats::Vector<> ROBSquashedInsts; + Stats::Vector squashedInsts; + Stats::Vector ROBSquashedInsts; - Stats::Scalar<> ROBFcount; + Stats::Scalar ROBFcount; Stats::Formula ROBFullRate; - Stats::Vector<> ROBCount; // cumulative ROB occupancy + Stats::Vector ROBCount; // cumulative ROB occupancy Stats::Formula ROBOccRate; -// Stats::VectorDistribution<> ROBOccDist; +// Stats::VectorDistribution ROBOccDist; public: void dumpInsts(); diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh index a5d79a789..60c42edd3 100644 --- a/src/cpu/ozone/lw_back_end_impl.hh +++ b/src/cpu/ozone/lw_back_end_impl.hh @@ -525,10 +525,7 @@ template <class Impl> void LWBackEnd<Impl>::checkInterrupts() { - if (cpu->checkInterrupts && - cpu->check_interrupts(tc) && - !trapSquash && - !tcSquash) { + if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) { frontEnd->interruptPending = true; if (robEmpty() && !LSQ.hasStoresToWB()) { // Will need to squash all instructions currently in flight and have diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index 7fc8b6307..4f8101bc0 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -39,6 +39,7 @@ #include "arch/faults.hh" #include "arch/types.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" @@ -301,7 +302,7 @@ class OzoneLWLSQ { }; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ @@ -410,9 +411,9 @@ class OzoneLWLSQ { //list<InstSeqNum> mshrSeqNums; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // Make these per thread? diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc index 438218df2..79f5277d5 100644 --- a/src/cpu/pc_event.cc +++ b/src/cpu/pc_event.cc @@ -34,12 +34,12 @@ #include <string> #include <utility> +#include "base/debug.hh" #include "base/trace.hh" #include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "cpu/pc_event.hh" -#include "sim/debug.hh" #include "sim/core.hh" #include "sim/system.hh" diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc index 81384d529..38ffb74e4 100644 --- a/src/cpu/quiesce_event.cc +++ b/src/cpu/quiesce_event.cc @@ -33,7 +33,7 @@ #include "cpu/quiesce_event.hh" EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc) - : Event(&mainEventQueue), tc(_tc) + : tc(_tc) { } diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index 28c2aa9c9..b7174bb43 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -28,18 +28,15 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class AtomicSimpleCPU(BaseCPU): +class AtomicSimpleCPU(BaseSimpleCPU): type = 'AtomicSimpleCPU' width = Param.Int(1, "CPU width") - simulate_stalls = Param.Bool(False, "Simulate cache stall cycles") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") + simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles") + simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") - _mem_ports = BaseCPU._mem_ports + \ + _mem_ports = BaseSimpleCPU._mem_ports + \ ['icache_port', 'dcache_port', 'physmem_port'] diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py new file mode 100644 index 000000000..9f528bc20 --- /dev/null +++ b/src/cpu/simple/BaseSimpleCPU.py @@ -0,0 +1,34 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from BaseCPU import BaseCPU + +class BaseSimpleCPU(BaseCPU): + type = 'BaseSimpleCPU' + abstract = True diff --git a/src/cpu/simple/SConscript b/src/cpu/simple/SConscript index c090a938c..76598666f 100644 --- a/src/cpu/simple/SConscript +++ b/src/cpu/simple/SConscript @@ -47,3 +47,4 @@ if 'AtomicSimpleCPU' in env['CPU_MODELS'] or \ if need_simple_base: Source('base.cc') + SimObject('BaseSimpleCPU.py') diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index 7e777e813..ce6839241 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -28,14 +28,10 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class TimingSimpleCPU(BaseCPU): +class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") - _mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port'] + _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port'] diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 23bd40b9b..17f93c882 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -43,7 +43,7 @@ using namespace std; using namespace TheISA; AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -79,13 +79,12 @@ void AtomicSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, tc->contextId()); } #endif if (hasPhysMemPort) { @@ -94,9 +93,10 @@ AtomicSimpleCPU::init() physmemPort.getPeerAddressRanges(pmAddrList, snoop); physMemAddr = *pmAddrList.begin(); } - ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT - data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too - data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too + // Atomic doesn't do MT right now, so contextId == threadId + ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT + data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too + data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too } bool @@ -148,13 +148,14 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } -AtomicSimpleCPU::AtomicSimpleCPU(Params *p) - : BaseSimpleCPU(p), tickEvent(this), - width(p->width), simulate_stalls(p->simulate_stalls), +AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) + : BaseSimpleCPU(p), tickEvent(this), width(p->width), + simulate_data_stalls(p->simulate_data_stalls), + simulate_inst_stalls(p->simulate_inst_stalls), icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), physmemPort(name() + "-iport", this), hasPhysMemPort(false) { @@ -175,8 +176,6 @@ AtomicSimpleCPU::serialize(ostream &os) { SimObject::State so_state = SimObject::getState(); SERIALIZE_ENUM(so_state); - Status _status = status(); - SERIALIZE_ENUM(_status); BaseSimpleCPU::serialize(os); nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); @@ -187,7 +186,6 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { SimObject::State so_state; UNSERIALIZE_ENUM(so_state); - UNSERIALIZE_ENUM(_status); BaseSimpleCPU::unserialize(cp, section); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); } @@ -203,16 +201,15 @@ AtomicSimpleCPU::resume() changeState(SimObject::Running); if (thread->status() == ThreadContext::Active) { - if (!tickEvent.scheduled()) { - tickEvent.schedule(nextCycle()); - } + if (!tickEvent.scheduled()) + schedule(tickEvent, nextCycle()); } } void AtomicSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; tickEvent.squash(); @@ -232,7 +229,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); break; } } @@ -240,10 +237,9 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - cpuId = tc->readCpuId(); - ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT - data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too - data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too + ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT + data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too + data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too } @@ -262,7 +258,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay) numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend); //Make sure ticks are still on multiples of cycles - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); _status = Running; } @@ -280,7 +276,7 @@ AtomicSimpleCPU::suspendContext(int thread_num) // tick event may not be scheduled if this gets called from inside // an instruction's execution, e.g. "quiesce" if (tickEvent.scheduled()) - tickEvent.deschedule(); + deschedule(tickEvent); notIdleFraction--; _status = Idle; @@ -318,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataReadReq(req); + Fault fault = thread->dtb->translateAtomic(req, tc, false); // Now do the access. if (fault == NoFault) { @@ -355,6 +351,9 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) if (secondAddr <= addr) { data = gtoh(data); + if (traceData) { + traceData->setData(data); + } return fault; } @@ -371,61 +370,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) } } -Fault -AtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr, - int size, unsigned flags) -{ - // use the CPU's statically allocated read request and packet objects - Request *req = &data_read_req; - - if (traceData) { - traceData->setAddr(vaddr); - } - - //The block size of our peer. - int blockSize = dcachePort.peerBlockSize(); - //The size of the data we're trying to read. - int dataSize = size; - - bool firstTimeThrough = true; - - //The address of the second part of this access if it needs to be split - //across a cache line boundary. - Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize); - - if(secondAddr > vaddr) - dataSize = secondAddr - vaddr; - - while(1) { - req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); - - // translate to physical address - Fault fault = thread->translateDataReadReq(req); - - //If there's a fault, return it - if (fault != NoFault) - return fault; - - if (firstTimeThrough) { - paddr = req->getPaddr(); - firstTimeThrough = false; - } - - //If we don't need to access a second cache line, stop now. - if (secondAddr <= vaddr) - return fault; - - /* - * Set up for accessing the second cache line. - */ - - //Adjust the size to get the remaining bytes. - dataSize = vaddr + size - secondAddr; - //And access the right address. - vaddr = secondAddr; - } -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS template @@ -508,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataWriteReq(req); + Fault fault = thread->dtb->translateAtomic(req, tc, true); // Now do the access. if (fault == NoFault) { @@ -568,6 +512,9 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) // If the write needs to have a fault on the access, consider // calling changeStatus() and changing it to "bad addr write" // or something. + if (traceData) { + traceData->setData(gtoh(data)); + } return fault; } @@ -584,64 +531,6 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) } } -Fault -AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - // use the CPU's statically allocated write request and packet objects - Request *req = &data_write_req; - - if (traceData) { - traceData->setAddr(vaddr); - } - - //The block size of our peer. - int blockSize = dcachePort.peerBlockSize(); - - //The address of the second part of this access if it needs to be split - //across a cache line boundary. - Addr secondAddr = roundDown(vaddr + size - 1, blockSize); - - //The size of the data we're trying to read. - int dataSize = size; - - bool firstTimeThrough = true; - - if(secondAddr > vaddr) - dataSize = secondAddr - vaddr; - - dcache_latency = 0; - - while(1) { - req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); - - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - - //If there's a fault or we don't need to access a second cache line, - //stop now. - if (fault != NoFault) - return fault; - - if (firstTimeThrough) { - paddr = req->getPaddr(); - firstTimeThrough = false; - } - - if (secondAddr <= vaddr) - return fault; - - /* - * Set up for accessing the second cache line. - */ - - //Adjust the size to get the remaining bytes. - dataSize = vaddr + size - secondAddr; - //And access the right address. - vaddr = secondAddr; - } -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -705,7 +594,7 @@ AtomicSimpleCPU::tick() { DPRINTF(SimpleCPU, "Tick\n"); - Tick latency = ticks(1); // instruction takes one cycle by default + Tick latency = 0; for (int i = 0; i < width; ++i) { numCycles++; @@ -715,31 +604,43 @@ AtomicSimpleCPU::tick() checkPcEventQueue(); - Fault fault = setupFetchRequest(&ifetch_req); + Fault fault = NoFault; + + bool fromRom = isRomMicroPC(thread->readMicroPC()); + if (!fromRom && !curMacroStaticInst) { + setupFetchRequest(&ifetch_req); + fault = thread->itb->translateAtomic(&ifetch_req, tc); + } if (fault == NoFault) { Tick icache_latency = 0; bool icache_access = false; dcache_access = false; // assume no dcache access - //Fetch more instruction memory if necessary - //if(predecoder.needMoreBytes()) - //{ - icache_access = true; - Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, - Packet::Broadcast); - ifetch_pkt.dataStatic(&inst); - - if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) - icache_latency = physmemPort.sendAtomic(&ifetch_pkt); - else - icache_latency = icachePort.sendAtomic(&ifetch_pkt); + if (!fromRom && !curMacroStaticInst) { + // This is commented out because the predecoder would act like + // a tiny cache otherwise. It wouldn't be flushed when needed + // like the I cache. It should be flushed, and when that works + // this code should be uncommented. + //Fetch more instruction memory if necessary + //if(predecoder.needMoreBytes()) + //{ + icache_access = true; + Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, + Packet::Broadcast); + ifetch_pkt.dataStatic(&inst); + + if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) + icache_latency = physmemPort.sendAtomic(&ifetch_pkt); + else + icache_latency = icachePort.sendAtomic(&ifetch_pkt); - assert(!ifetch_pkt.isError()); + assert(!ifetch_pkt.isError()); - // ifetch_req is initialized to read the instruction directly - // into the CPU object's inst field. - //} + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + //} + } preExecute(); @@ -763,16 +664,21 @@ AtomicSimpleCPU::tick() curStaticInst->isFirstMicroop())) instCnt++; - if (simulate_stalls) { - Tick icache_stall = - icache_access ? icache_latency - ticks(1) : 0; - Tick dcache_stall = - dcache_access ? dcache_latency - ticks(1) : 0; - Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1); - if (ticks(stall_cycles) < (icache_stall + dcache_stall)) - latency += ticks(stall_cycles+1); - else - latency += ticks(stall_cycles); + Tick stall_ticks = 0; + if (simulate_inst_stalls && icache_access) + stall_ticks += icache_latency; + + if (simulate_data_stalls && dcache_access) + stall_ticks += dcache_latency; + + if (stall_ticks) { + Tick stall_cycles = stall_ticks / ticks(1); + Tick aligned_stall_ticks = ticks(stall_cycles); + + if (aligned_stall_ticks < stall_ticks) + aligned_stall_ticks += 1; + + latency += aligned_stall_ticks; } } @@ -780,8 +686,12 @@ AtomicSimpleCPU::tick() advancePC(fault); } + // instruction takes at least one cycle + if (latency < ticks(1)) + latency = ticks(1); + if (_status != Idle) - tickEvent.schedule(curTick + latency); + schedule(tickEvent, curTick + latency); } @@ -799,38 +709,10 @@ AtomicSimpleCPU::printAddr(Addr a) AtomicSimpleCPU * AtomicSimpleCPUParams::create() { - AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); - params->name = name; - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->phase = phase; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->width = width; - params->simulate_stalls = simulate_stalls; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); - return cpu; + return new AtomicSimpleCPU(this); } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 19bc0e13b..190097637 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -32,34 +32,17 @@ #define __CPU_SIMPLE_ATOMIC_HH__ #include "cpu/simple/base.hh" +#include "params/AtomicSimpleCPU.hh" class AtomicSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - int width; - bool simulate_stalls; - }; - - AtomicSimpleCPU(Params *params); + AtomicSimpleCPU(AtomicSimpleCPUParams *params); virtual ~AtomicSimpleCPU(); virtual void init(); - public: - // - enum Status { - Running, - Idle, - SwitchedOut - }; - - protected: - Status _status; - - Status status() const { return _status; } - private: struct TickEvent : public Event @@ -74,7 +57,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU TickEvent tickEvent; const int width; - const bool simulate_stalls; + const bool simulate_data_stalls; + const bool simulate_inst_stalls; // main simulation loop (one cycle) void tick(); @@ -152,11 +136,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU template <class T> Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Print state of address in memory system via PrintReq (for * debugging). diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4a91a9e12..348d2392f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -31,6 +31,7 @@ #include "arch/utility.hh" #include "arch/faults.hh" #include "base/cprintf.hh" +#include "base/cp_annotate.hh" #include "base/inifile.hh" #include "base/loader/symtab.hh" #include "base/misc.hh" @@ -65,16 +66,18 @@ #include "mem/mem_object.hh" #endif // FULL_SYSTEM +#include "params/BaseSimpleCPU.hh" + using namespace std; using namespace TheISA; -BaseSimpleCPU::BaseSimpleCPU(Params *p) +BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p) : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL) { #if FULL_SYSTEM thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); #else - thread = new SimpleThread(this, /* thread_num */ 0, p->process, + thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0], p->itb, p->dtb, /* asid */ 0); #endif // !FULL_SYSTEM @@ -174,12 +177,13 @@ void BaseSimpleCPU::resetStats() { // startNumInst = numInst; - // notIdleFraction = (_status != Idle); + notIdleFraction = (_status != Idle); } void BaseSimpleCPU::serialize(ostream &os) { + SERIALIZE_ENUM(_status); BaseCPU::serialize(os); // SERIALIZE_SCALAR(inst); nameOut(os, csprintf("%s.xc.0", name())); @@ -189,6 +193,7 @@ BaseSimpleCPU::serialize(ostream &os) void BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { + UNSERIALIZE_ENUM(_status); BaseCPU::unserialize(cp, section); // UNSERIALIZE_SCALAR(inst); thread->unserialize(cp, csprintf("%s.xc.0", section)); @@ -299,14 +304,13 @@ BaseSimpleCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM void -BaseSimpleCPU::post_interrupt(int int_num, int index) +BaseSimpleCPU::wakeup() { - BaseCPU::post_interrupt(int_num, index); + if (thread->status() != ThreadContext::Suspended) + return; - if (thread->status() == ThreadContext::Suspended) { - DPRINTF(Quiesce,"Suspended Processor awoke\n"); - thread->activate(); - } + DPRINTF(Quiesce,"Suspended Processor awoke\n"); + thread->activate(); } #endif // FULL_SYSTEM @@ -314,11 +318,12 @@ void BaseSimpleCPU::checkForInterrupts() { #if FULL_SYSTEM - if (check_interrupts(tc)) { - Fault interrupt = interrupts.getInterrupt(tc); + if (checkInterrupts(tc)) { + Fault interrupt = interrupts->getInterrupt(tc); if (interrupt != NoFault) { - interrupts.updateIntrInfo(tc); + predecoder.reset(); + interrupts->updateIntrInfo(tc); interrupt->invoke(tc); } } @@ -326,7 +331,7 @@ BaseSimpleCPU::checkForInterrupts() } -Fault +void BaseSimpleCPU::setupFetchRequest(Request *req) { Addr threadPC = thread->readPC(); @@ -342,10 +347,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - - Fault fault = thread->translateInstReq(req); - - return fault; } @@ -364,9 +365,13 @@ BaseSimpleCPU::preExecute() // decode the instruction inst = gtoh(inst); - //If we're not in the middle of a macro instruction - if (!curMacroStaticInst) { + MicroPC upc = thread->readMicroPC(); + if (isRomMicroPC(upc)) { + stayAtPC = false; + curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst); + } else if (!curMacroStaticInst) { + //We're not in the middle of a macro instruction StaticInstPtr instPtr = NULL; //Predecode, ie bundle up an ExtMachInst @@ -397,23 +402,22 @@ BaseSimpleCPU::preExecute() //out micro ops if (instPtr && instPtr->isMacroop()) { curMacroStaticInst = instPtr; - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } else { curStaticInst = instPtr; } } else { //Read the next micro op from the macro op - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } //If we decoded an instruction this "tick", record information about it. if(curStaticInst) { #if TRACING_ON - traceData = tracer->getInstRecord(curTick, tc, curStaticInst, - thread->readPC()); + traceData = tracer->getInstRecord(curTick, tc, + curStaticInst, thread->readPC(), + curMacroStaticInst, thread->readMicroPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", curStaticInst->getName(), curStaticInst->machInst); @@ -447,6 +451,10 @@ BaseSimpleCPU::postExecute() comLoadEventQueue[0]->serviceEvents(numLoad); } + if (CPA::available()) { + CPA::cpa()->swAutoBegin(tc, thread->readNextPC()); + } + traceFunctions(thread->readPC()); if (traceData) { @@ -465,22 +473,21 @@ BaseSimpleCPU::advancePC(Fault fault) if (fault != NoFault) { curMacroStaticInst = StaticInst::nullStaticInstPtr; predecoder.reset(); - thread->setMicroPC(0); - thread->setNextMicroPC(1); fault->invoke(tc); } else { //If we're at the last micro op for this instruction if (curStaticInst && curStaticInst->isLastMicroop()) { - //We should be working with a macro op - assert(curMacroStaticInst); + //We should be working with a macro op or be in the ROM + assert(curMacroStaticInst || + isRomMicroPC(thread->readMicroPC())); //Close out this macro op, and clean up the //microcode state curMacroStaticInst = StaticInst::nullStaticInstPtr; - thread->setMicroPC(0); - thread->setNextMicroPC(1); + thread->setMicroPC(normalMicroPC(0)); + thread->setNextMicroPC(normalMicroPC(1)); } //If we're still in a macro op - if (curMacroStaticInst) { + if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) { //Advance the micro pc thread->setMicroPC(thread->readNextMicroPC()); //Advance the "next" micro pc. Note that there are no delay diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 918965fdb..e80606388 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -76,6 +76,8 @@ namespace Trace { class InstRecord; } +class BaseSimpleCPUParams; + class BaseSimpleCPU : public BaseCPU { @@ -96,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU } public: - void post_interrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; @@ -107,15 +109,7 @@ class BaseSimpleCPU : public BaseCPU }; public: - struct Params : public BaseCPU::Params - { - TheISA::ITB *itb; - TheISA::DTB *dtb; -#if !FULL_SYSTEM - Process *process; -#endif - }; - BaseSimpleCPU(Params *params); + BaseSimpleCPU(BaseSimpleCPUParams *params); virtual ~BaseSimpleCPU(); public: @@ -127,7 +121,22 @@ class BaseSimpleCPU : public BaseCPU */ ThreadContext *tc; protected: - int cpuId; + + enum Status { + Idle, + Running, + ITBWaitResponse, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DTBWaitResponse, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + Status _status; public: @@ -153,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU bool stayAtPC; void checkForInterrupts(); - Fault setupFetchRequest(Request *req); + void setupFetchRequest(Request *req); void preExecute(); void postExecute(); void advancePC(Fault fault); @@ -168,7 +177,7 @@ class BaseSimpleCPU : public BaseCPU // number of simulated instructions Counter numInst; Counter startNumInst; - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; void countInst() { @@ -187,30 +196,30 @@ class BaseSimpleCPU : public BaseCPU static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1); // number of simulated memory references - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; // number of simulated loads Counter numLoad; Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; // number of cycles stalled for I-cache responses - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; Counter lastIcacheStall; // number of cycles stalled for I-cache retries - Stats::Scalar<> icacheRetryCycles; + Stats::Scalar icacheRetryCycles; Counter lastIcacheRetry; // number of cycles stalled for D-cache responses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // number of cycles stalled for D-cache retries - Stats::Scalar<> dcacheRetryCycles; + Stats::Scalar dcacheRetryCycles; Counter lastDcacheRetry; virtual void serialize(std::ostream &os); @@ -219,7 +228,7 @@ class BaseSimpleCPU : public BaseCPU // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); M5_DUMMY_RETURN} void prefetch(Addr addr, unsigned flags) diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index a76824ff3..a8f86f8d2 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -57,13 +57,12 @@ void TimingSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, _cpuId); } #endif } @@ -101,11 +100,12 @@ void TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) { pkt = _pkt; - Event::schedule(t); + cpu->schedule(this, t); } -TimingSimpleCPU::TimingSimpleCPU(Params *p) - : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) +TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) + : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), + dcachePort(this, p->clock), fetchEvent(this) { _status = Idle; @@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p) ifetch_pkt = dcache_pkt = NULL; drainEvent = NULL; - fetchEvent = NULL; previousTick = 0; changeState(SimObject::Running); } @@ -145,7 +144,7 @@ TimingSimpleCPU::drain(Event *drain_event) { // TimingSimpleCPU is ready to drain if it's not waiting for // an access to complete. - if (status() == Idle || status() == Running || status() == SwitchedOut) { + if (_status == Idle || _status == Running || _status == SwitchedOut) { changeState(SimObject::Drained); return 0; } else { @@ -162,15 +161,10 @@ TimingSimpleCPU::resume() if (_status != SwitchedOut && _status != Idle) { assert(system->getMemoryMode() == Enums::timing); - // Delete the old event if it existed. - if (fetchEvent) { - if (fetchEvent->scheduled()) - fetchEvent->deschedule(); + if (fetchEvent.scheduled()) + deschedule(fetchEvent); - delete fetchEvent; - } - - fetchEvent = new FetchEvent(this, nextCycle()); + schedule(fetchEvent, nextCycle()); } changeState(SimObject::Running); @@ -179,14 +173,14 @@ TimingSimpleCPU::resume() void TimingSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; numCycles += tickToCycles(curTick - previousTick); // If we've been scheduled to resume but are then told to switch out, // we'll need to cancel it. - if (fetchEvent && fetchEvent->scheduled()) - fetchEvent->deschedule(); + if (fetchEvent.scheduled()) + deschedule(fetchEvent); } @@ -209,7 +203,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - cpuId = tc->readCpuId(); previousTick = curTick; } @@ -228,7 +221,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay) _status = Running; // kick things off by initiating the fetch of the next instruction - fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay))); + schedule(fetchEvent, nextCycle(curTick + ticks(delay))); } @@ -249,74 +242,239 @@ TimingSimpleCPU::suspendContext(int thread_num) _status = Idle; } +bool +TimingSimpleCPU::handleReadPacket(PacketPtr pkt) +{ + RequestPtr req = pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprRead(thread->getTC(), pkt); + new IprEvent(pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(pkt)) { + _status = DcacheRetry; + dcache_pkt = pkt; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} -template <class T> -Fault -TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) +void +TimingSimpleCPU::sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + _status = Running; + if (fault != NoFault) { + delete data; + delete req; - if (traceData) { - traceData->setAddr(req->getVaddr()); + translationFault(fault); + return; } + PacketPtr pkt; + buildPacket(pkt, req, read); + pkt->dataDynamic<uint8_t>(data); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt->makeResponse(); + completeDataAccess(pkt); + } else if (read) { + handleReadPacket(pkt); + } else { + bool do_access = true; // flag to suppress cache access - // translate to physical address - Fault fault = thread->translateDataReadReq(req); + if (req->isLocked()) { + do_access = TheISA::handleLockedWrite(thread, req); + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } - // Now do the access. - if (fault == NoFault) { - PacketPtr pkt = - new Packet(req, - (req->isLocked() ? - MemCmd::LoadLockedReq : MemCmd::ReadReq), - Packet::Broadcast); - pkt->dataDynamic<T>(new T); - - if (req->isMmapedIpr()) { - Tick delay; - delay = TheISA::handleIprRead(thread->getTC(), pkt); - new IprEvent(pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(pkt)) { - _status = DcacheRetry; + if (do_access) { dcache_pkt = pkt; + handleWritePacket(); } else { _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; + completeDataAccess(pkt); } + } +} - // This will need a new way to tell if it has a dcache attached. - if (req->isUncacheable()) - recordEvent("Uncached Read"); +void +TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + _status = Running; + if (fault1 != NoFault || fault2 != NoFault) { + delete data; + delete req1; + delete req2; + if (fault1 != NoFault) + translationFault(fault1); + else if (fault2 != NoFault) + translationFault(fault2); + return; + } + PacketPtr pkt1, pkt2; + buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt1->makeResponse(); + completeDataAccess(pkt1); + } else if (read) { + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = dynamic_cast<SplitFragmentSenderState *>( + pkt1->senderState); + send_state->clearFromParent(); + } + } } else { - delete req; + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleWritePacket()) { + send_state = dynamic_cast<SplitFragmentSenderState *>( + pkt1->senderState); + send_state->clearFromParent(); + } + } + } +} + +void +TimingSimpleCPU::translationFault(Fault fault) +{ + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + + if (traceData) { + // Since there was a fault, we shouldn't trace this instruction. + delete traceData; + traceData = NULL; } - return fault; + postExecute(); + + if (getState() == SimObject::Draining) { + advancePC(fault); + completeDrain(); + } else { + advanceInst(fault); + } } +void +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) +{ + MemCmd cmd; + if (read) { + cmd = MemCmd::ReadReq; + if (req->isLocked()) + cmd = MemCmd::LoadLockedReq; + } else { + cmd = MemCmd::WriteReq; + if (req->isLocked()) { + cmd = MemCmd::StoreCondReq; + } else if (req->isSwap()) { + cmd = MemCmd::SwapReq; + } + } + pkt = new Packet(req, cmd, Packet::Broadcast); +} + +void +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + pkt1 = pkt2 = NULL; + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + if (req->getFlags().isSet(Request::NO_ACCESS)) { + buildPacket(pkt1, req, read); + return; + } + + buildPacket(pkt1, req1, read); + buildPacket(pkt2, req2, read); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic<uint8_t>(data); + pkt1->dataStatic<uint8_t>(data); + pkt2->dataStatic<uint8_t>(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); +} + +template <class T> Fault -TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) +TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) { - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); + Fault fault; + const int asid = 0; + const int thread_id = 0; + const Addr pc = thread->readPC(); + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + + _status = DTBWaitResponse; + if (split_addr > addr) { + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)(new T), true); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), false); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), false); + } else { + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)(new T), NULL, true), + false); + } if (traceData) { - traceData->setAddr(vaddr); + traceData->setData(data); + traceData->setAddr(addr); } - Fault fault = thread->translateDataWriteReq(req); + // This will need a new way to tell if it has a dcache attached. + if (req->isUncacheable()) + recordEvent("Uncached Read"); - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; + return NoFault; } #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -369,92 +527,75 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) return read(addr, (uint32_t&)data, flags); } +bool +TimingSimpleCPU::handleWritePacket() +{ + RequestPtr req = dcache_pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); + new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(dcache_pkt)) { + _status = DcacheRetry; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} template <class T> Fault TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + const int asid = 0; + const int thread_id = 0; + const Addr pc = thread->readPC(); + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + T *dataP = new T; + *dataP = TheISA::htog(data); + _status = DTBWaitResponse; + if (split_addr > addr) { + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)dataP, false); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), true); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), true); + } else { + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)dataP, res, false), + true); + } if (traceData) { traceData->setAddr(req->getVaddr()); + traceData->setData(data); } - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - - // Now do the access. - if (fault == NoFault) { - MemCmd cmd = MemCmd::WriteReq; // default - bool do_access = true; // flag to suppress cache access - - if (req->isLocked()) { - cmd = MemCmd::StoreCondReq; - do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isSwap()) { - cmd = MemCmd::SwapReq; - if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } - } - - // Note: need to allocate dcache_pkt even if do_access is - // false, as it's used unconditionally to call completeAcc(). - assert(dcache_pkt == NULL); - dcache_pkt = new Packet(req, cmd, Packet::Broadcast); - dcache_pkt->allocate(); - dcache_pkt->set(data); - - if (do_access) { - if (req->isMmapedIpr()) { - Tick delay; - dcache_pkt->set(htog(data)); - delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); - new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(dcache_pkt)) { - _status = DcacheRetry; - } else { - _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; - } - } - // This will need a new way to tell if it's hooked up to a cache or not. - if (req->isUncacheable()) - recordEvent("Uncached Write"); - } else { - delete req; - } - + // This will need a new way to tell if it's hooked up to a cache or not. + if (req->isUncacheable()) + recordEvent("Uncached Write"); // If the write needs to have a fault on the access, consider calling // changeStatus() and changing it to "bad addr write" or something. - return fault; -} - -Fault -TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); - - if (traceData) { - traceData->setAddr(vaddr); - } - - Fault fault = thread->translateDataWriteReq(req); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; + return NoFault; } @@ -524,14 +665,31 @@ TimingSimpleCPU::fetch() checkPcEventQueue(); - Request *ifetch_req = new Request(); - ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); - Fault fault = setupFetchRequest(ifetch_req); + bool fromRom = isRomMicroPC(thread->readMicroPC()); - ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); - ifetch_pkt->dataStatic(&inst); + if (!fromRom && !curMacroStaticInst) { + Request *ifetch_req = new Request(); + ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); + setupFetchRequest(ifetch_req); + thread->itb->translateTiming(ifetch_req, tc, + &fetchTranslation); + } else { + _status = IcacheWaitResponse; + completeIfetch(NULL); + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + } +} + + +void +TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) +{ if (fault == NoFault) { + ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + if (!icachePort.sendTiming(ifetch_pkt)) { // Need to wait for retry _status = IcacheRetry; @@ -542,8 +700,7 @@ TimingSimpleCPU::fetch() ifetch_pkt = NULL; } } else { - delete ifetch_req; - delete ifetch_pkt; + delete req; // fetch fault: advance directly to next instruction (fault handler) advanceInst(fault); } @@ -556,7 +713,8 @@ TimingSimpleCPU::fetch() void TimingSimpleCPU::advanceInst(Fault fault) { - advancePC(fault); + if (fault != NoFault || !stayAtPC) + advancePC(fault); if (_status == Running) { // kick off fetch of next instruction... callback from icache @@ -574,7 +732,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) // received a response from the icache: execute the received // instruction - assert(!pkt->isError()); + + assert(!pkt || !pkt->isError()); assert(_status == IcacheWaitResponse); _status = Running; @@ -583,41 +742,27 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) previousTick = curTick; if (getState() == SimObject::Draining) { - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } completeDrain(); return; } preExecute(); - if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { + if (curStaticInst && + curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { // load or store: just send to dcache Fault fault = curStaticInst->initiateAcc(this, traceData); if (_status != Running) { // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || _status == DcacheRetry); + assert(_status == DcacheWaitResponse || + _status == DcacheRetry || DTBWaitResponse); assert(fault == NoFault); } else { - if (fault == NoFault) { - // Note that ARM can have NULL packets if the instruction gets - // squashed due to predication - // early fail on store conditional: complete now - assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); - - fault = curStaticInst->completeAcc(dcache_pkt, this, - traceData); - if (dcache_pkt != NULL) - { - delete dcache_pkt->req; - delete dcache_pkt; - dcache_pkt = NULL; - } - - // keep an instruction count - if (fault == NoFault) - countInst(); - } else if (traceData) { + if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; traceData = NULL; @@ -630,7 +775,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) instCnt++; advanceInst(fault); } - } else { + } else if (curStaticInst) { // non-memory instruction: execute completely now Fault fault = curStaticInst->execute(this, traceData); @@ -649,10 +794,14 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) curStaticInst->isFirstMicroop())) instCnt++; advanceInst(fault); + } else { + advanceInst(NoFault); } - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } } void @@ -707,12 +856,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) // received a response from the dcache: complete the load or store // instruction assert(!pkt->isError()); - assert(_status == DcacheWaitResponse); - _status = Running; numCycles += tickToCycles(curTick - previousTick); previousTick = curTick; + if (pkt->senderState) { + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); + assert(send_state); + delete pkt->req; + delete pkt; + PacketPtr big_pkt = send_state->bigPkt; + delete send_state; + + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); + assert(main_send_state); + // Record the fact that this packet is no longer outstanding. + assert(main_send_state->outstanding != 0); + main_send_state->outstanding--; + + if (main_send_state->outstanding) { + return; + } else { + delete main_send_state; + big_pkt->senderState = NULL; + pkt = big_pkt; + } + } + + assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); + _status = Running; + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); // keep an instruction count @@ -724,7 +899,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) traceData = NULL; } - if (pkt->isRead() && pkt->isLocked()) { + // the locked flag may be cleared on the response packet, so check + // pkt->req and not pkt to see if it was a load-locked + if (pkt->isRead() && pkt->req->isLocked()) { TheISA::handleLockedRead(thread, pkt->req); } @@ -760,7 +937,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } @@ -771,10 +948,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) // delay processing of returned data until next CPU clock edge Tick next_tick = cpu->nextCycle(curTick); - if (next_tick == curTick) + if (next_tick == curTick) { cpu->completeDataAccess(pkt); - else + } else { tickEvent.schedule(pkt, next_tick); + } return true; } @@ -804,17 +982,47 @@ TimingSimpleCPU::DcachePort::recvRetry() assert(cpu->dcache_pkt != NULL); assert(cpu->_status == DcacheRetry); PacketPtr tmp = cpu->dcache_pkt; - if (sendTiming(tmp)) { + if (tmp->senderState) { + // This is a packet from a split access. + SplitFragmentSenderState * send_state = + dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); + assert(send_state); + PacketPtr big_pkt = send_state->bigPkt; + + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); + assert(main_send_state); + + if (sendTiming(tmp)) { + // If we were able to send without retrying, record that fact + // and try sending the other fragment. + send_state->clearFromParent(); + int other_index = main_send_state->getPendingFragment(); + if (other_index > 0) { + tmp = main_send_state->fragments[other_index]; + cpu->dcache_pkt = tmp; + if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || + (big_pkt->isWrite() && cpu->handleWritePacket())) { + main_send_state->fragments[other_index] = NULL; + } + } else { + cpu->_status = DcacheWaitResponse; + // memory system takes ownership of packet + cpu->dcache_pkt = NULL; + } + } + } else if (sendTiming(tmp)) { cpu->_status = DcacheWaitResponse; // memory system takes ownership of packet cpu->dcache_pkt = NULL; } } -TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t) - : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu) +TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, + Tick t) + : pkt(_pkt), cpu(_cpu) { - schedule(t); + cpu->schedule(this, t); } void @@ -844,36 +1052,10 @@ TimingSimpleCPU::printAddr(Addr a) TimingSimpleCPU * TimingSimpleCPUParams::create() { - TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); - params->name = name; - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->clock = clock; - params->phase = phase; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - TimingSimpleCPU *cpu = new TimingSimpleCPU(params); - return cpu; + return new TimingSimpleCPU(this); } diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index f8b77604a..a02ec48c9 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -33,40 +33,181 @@ #include "cpu/simple/base.hh" +#include "params/TimingSimpleCPU.hh" + class TimingSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - }; - - TimingSimpleCPU(Params *params); + TimingSimpleCPU(TimingSimpleCPUParams * params); virtual ~TimingSimpleCPU(); virtual void init(); public: - // - enum Status { - Idle, - Running, - IcacheRetry, - IcacheWaitResponse, - IcacheWaitSwitch, - DcacheRetry, - DcacheWaitResponse, - DcacheWaitSwitch, - SwitchedOut + Event *drainEvent; + + private: + + /* + * If an access needs to be broken into fragments, currently at most two, + * the the following two classes are used as the sender state of the + * packets so the CPU can keep track of everything. In the main packet + * sender state, there's an array with a spot for each fragment. If a + * fragment has already been accepted by the CPU, aka isn't waiting for + * a retry, it's pointer is NULL. After each fragment has successfully + * been processed, the "outstanding" counter is decremented. Once the + * count is zero, the entire larger access is complete. + */ + class SplitMainSenderState : public Packet::SenderState + { + public: + int outstanding; + PacketPtr fragments[2]; + + int + getPendingFragment() + { + if (fragments[0]) { + return 0; + } else if (fragments[1]) { + return 1; + } else { + return -1; + } + } }; - protected: - Status _status; + class SplitFragmentSenderState : public Packet::SenderState + { + public: + SplitFragmentSenderState(PacketPtr _bigPkt, int _index) : + bigPkt(_bigPkt), index(_index) + {} + PacketPtr bigPkt; + int index; + + void + clearFromParent() + { + SplitMainSenderState * main_send_state = + dynamic_cast<SplitMainSenderState *>(bigPkt->senderState); + main_send_state->fragments[index] = NULL; + } + }; - Status status() const { return _status; } + class FetchTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; - Event *drainEvent; + public: + FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu) + {} - private: + void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendFetch(fault, req, tc); + } + }; + FetchTranslation fetchTranslation; + + class DataTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + uint8_t *data; + uint64_t *res; + bool read; + + public: + DataTranslation(TimingSimpleCPU *_cpu, + uint8_t *_data, uint64_t *_res, bool _read) : + cpu(_cpu), data(_data), res(_res), read(_read) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendData(fault, req, data, res, read); + delete this; + } + }; + + class SplitDataTranslation : public BaseTLB::Translation + { + public: + struct WholeTranslationState + { + public: + int outstanding; + RequestPtr requests[2]; + RequestPtr mainReq; + Fault faults[2]; + uint8_t *data; + bool read; + + WholeTranslationState(RequestPtr req1, RequestPtr req2, + RequestPtr main, uint8_t *_data, bool _read) + { + outstanding = 2; + requests[0] = req1; + requests[1] = req2; + mainReq = main; + faults[0] = faults[1] = NoFault; + data = _data; + read = _read; + } + }; + + TimingSimpleCPU *cpu; + int index; + WholeTranslationState *state; + + SplitDataTranslation(TimingSimpleCPU *_cpu, int _index, + WholeTranslationState *_state) : + cpu(_cpu), index(_index), state(_state) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + assert(state); + assert(state->outstanding); + state->faults[index] = fault; + if (--state->outstanding == 0) { + cpu->sendSplitData(state->faults[0], + state->faults[1], + state->requests[0], + state->requests[1], + state->mainReq, + state->data, + state->read); + delete state; + } + delete this; + } + }; + + void sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read); + void sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + void translationFault(Fault fault); + + void buildPacket(PacketPtr &pkt, RequestPtr req, bool read); + void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + bool handleReadPacket(PacketPtr pkt); + // This function always implicitly uses dcache_pkt. + bool handleWritePacket(); class CpuPort : public Port { @@ -99,8 +240,7 @@ class TimingSimpleCPU : public BaseSimpleCPU PacketPtr pkt; TimingSimpleCPU *cpu; - TickEvent(TimingSimpleCPU *_cpu) - :Event(&mainEventQueue), cpu(_cpu) {} + TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {} const char *description() const { return "Timing CPU tick"; } void schedule(PacketPtr _pkt, Tick t); }; @@ -189,18 +329,13 @@ class TimingSimpleCPU : public BaseSimpleCPU template <class T> Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - template <class T> Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void fetch(); + void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); void completeIfetch(PacketPtr ); - void completeDataAccess(PacketPtr ); + void completeDataAccess(PacketPtr pkt); void advanceInst(Fault fault); /** @@ -212,7 +347,7 @@ class TimingSimpleCPU : public BaseSimpleCPU private: typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; - FetchEvent *fetchEvent; + FetchEvent fetchEvent; struct IprEvent : Event { Packet *pkt; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 93772fbe1..af0bb4490 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -37,9 +37,11 @@ #include "cpu/base.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" +#include "params/BaseCPU.hh" #if FULL_SYSTEM #include "arch/kernel_stats.hh" +#include "arch/stacktrace.hh" #include "base/callback.hh" #include "base/cprintf.hh" #include "base/output.hh" @@ -48,11 +50,10 @@ #include "cpu/quiesce_event.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" -#include "arch/stacktrace.hh" #else +#include "mem/translating_port.hh" #include "sim/process.hh" #include "sim/system.hh" -#include "mem/translating_port.hh" #endif using namespace std; @@ -62,7 +63,7 @@ using namespace std; SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, TheISA::ITB *_itb, TheISA::DTB *_dtb, bool use_kernel_stats) - : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), system(_sys), itb(_itb), + : ThreadState(_cpu, _thread_num), cpu(_cpu), system(_sys), itb(_itb), dtb(_dtb) { @@ -72,7 +73,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, regs.clear(); - if (cpu->params->profile) { + if (cpu->params()->profile) { profile = new FunctionProfile(system->kernelSymtab); Callback *cb = new MakeCallback<SimpleThread, @@ -86,16 +87,13 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, profileNode = &dummyNode; profilePC = 3; - if (use_kernel_stats) { + if (use_kernel_stats) kernelStats = new TheISA::Kernel::Statistics(system); - } else { - kernelStats = NULL; - } } #else SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, TheISA::ITB *_itb, TheISA::DTB *_dtb, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), itb(_itb), dtb(_dtb) { regs.clear(); @@ -106,9 +104,9 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, SimpleThread::SimpleThread() #if FULL_SYSTEM - : ThreadState(NULL, -1, -1) + : ThreadState(NULL, -1) #else - : ThreadState(NULL, -1, -1, NULL, -1) + : ThreadState(NULL, -1, NULL, -1) #endif { tc = new ProxyThreadContext<SimpleThread>(this); @@ -180,18 +178,20 @@ SimpleThread::copyState(ThreadContext *oldContext) // copy over functional state _status = oldContext->status(); copyArchRegs(oldContext); - cpuId = oldContext->readCpuId(); #if !FULL_SYSTEM funcExeInst = oldContext->readFuncExeInst(); #endif inst = oldContext->getInst(); + + _threadId = oldContext->threadId(); + _contextId = oldContext->contextId(); } void SimpleThread::serialize(ostream &os) { ThreadState::serialize(os); - regs.serialize(os); + regs.serialize(cpu, os); // thread_num and cpu_id are deterministic from the config } @@ -200,7 +200,7 @@ void SimpleThread::unserialize(Checkpoint *cp, const std::string §ion) { ThreadState::unserialize(cp, section); - regs.unserialize(cp, section); + regs.unserialize(cpu, cp, section); // thread_num and cpu_id are deterministic from the config } @@ -222,14 +222,14 @@ SimpleThread::activate(int delay) lastActivate = curTick; // if (status() == ThreadContext::Unallocated) { -// cpu->activateWhenReady(tid); -// return; +// cpu->activateWhenReady(_threadId); +// return; // } _status = ThreadContext::Active; // status() == Suspended - cpu->activateContext(tid, delay); + cpu->activateContext(_threadId, delay); } void @@ -243,14 +243,14 @@ SimpleThread::suspend() /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } #endif */ _status = ThreadContext::Suspended; - cpu->suspendContext(tid); + cpu->suspendContext(_threadId); } void @@ -260,7 +260,7 @@ SimpleThread::deallocate() return; _status = ThreadContext::Unallocated; - cpu->deallocateContext(tid); + cpu->deallocateContext(_threadId); } void @@ -270,7 +270,7 @@ SimpleThread::halt() return; _status = ThreadContext::Halted; - cpu->haltContext(tid); + cpu->haltContext(_threadId); } @@ -289,26 +289,3 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc) TheISA::copyRegs(src_tc, tc); } -#if FULL_SYSTEM -VirtualPort* -SimpleThread::getVirtPort(ThreadContext *src_tc) -{ - if (!src_tc) - return virtPort; - - VirtualPort *vp = new VirtualPort("tc-vport", src_tc); - connectToMemFunc(vp); - return vp; -} - -void -SimpleThread::delVirtPort(VirtualPort *vp) -{ - if (vp != virtPort) { - vp->removeConn(); - delete vp; - } -} - -#endif - diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index fa80a283a..73929d362 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -34,7 +34,6 @@ #include "arch/isa_traits.hh" #include "arch/regfile.hh" -#include "arch/syscallreturn.hh" #include "arch/tlb.hh" #include "config/full_system.hh" #include "cpu/thread_context.hh" @@ -99,7 +98,7 @@ class SimpleThread : public ThreadState typedef ThreadContext::Status Status; protected: - RegFile regs; // correct-path register context + RegFile regs; // correct-path register context public: // pointer to CPU associated with this SimpleThread @@ -139,7 +138,7 @@ class SimpleThread : public ThreadState /*************************************************************** * SimpleThread functions to provide CPU with access to various - * state, and to provide address translation methods. + * state. **************************************************************/ /** Returns the pointer to this SimpleThread's ThreadContext. Used @@ -148,21 +147,6 @@ class SimpleThread : public ThreadState */ ThreadContext *getTC() { return tc; } - Fault translateInstReq(RequestPtr &req) - { - return itb->translate(req, tc); - } - - Fault translateDataReadReq(RequestPtr &req) - { - return dtb->translate(req, tc, false); - } - - Fault translateDataWriteReq(RequestPtr &req) - { - return dtb->translate(req, tc, true); - } - void demapPage(Addr vaddr, uint64_t asn) { itb->demapPage(vaddr, asn); @@ -197,23 +181,20 @@ class SimpleThread : public ThreadState BaseCPU *getCpuPtr() { return cpu; } - int getThreadNum() { return tid; } - TheISA::ITB *getITBPtr() { return itb; } TheISA::DTB *getDTBPtr() { return dtb; } -#if FULL_SYSTEM System *getSystemPtr() { return system; } +#if FULL_SYSTEM FunctionalPort *getPhysPort() { return physPort; } - /** Return a virtual port. If no thread context is specified then a static - * port is returned. Otherwise a port is created and returned. It must be - * deleted by deleteVirtPort(). */ - VirtualPort *getVirtPort(ThreadContext *tc); - - void delVirtPort(VirtualPort *vp); + /** Return a virtual port. This port cannot be cached locally in an object. + * After a CPU switch it may point to the wrong memory object which could + * mean stale data. + */ + VirtualPort *getVirtPort() { return virtPort; } #endif Status status() const { return _status; } @@ -385,37 +366,11 @@ class SimpleThread : public ThreadState { storeCondFailures = sc_failures; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - return regs.readIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i])); - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - regs.setIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i]), val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, getTC()); - } - void syscall(int64_t callnum) { process->syscall(callnum, tc); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - regs.changeContext(param, val); - } }; diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc index 52a7ede03..01136bda1 100644 --- a/src/cpu/static_inst.cc +++ b/src/cpu/static_inst.cc @@ -40,11 +40,17 @@ StaticInst::DecodeCache StaticInst::decodeCache; StaticInst::AddrDecodeCache StaticInst::addrDecodeCache; StaticInst::cacheElement StaticInst::recentDecodes[2]; +using namespace std; + +StaticInst::~StaticInst() +{ + if (cachedDisassembly) + delete cachedDisassembly; +} + void StaticInst::dumpDecodeCacheStats() { - using namespace std; - cerr << "Decode hash table stats @ " << curTick << ":" << endl; cerr << "\tnum entries = " << decodeCache.size() << endl; cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl; @@ -81,6 +87,37 @@ StaticInstPtr StaticInst::fetchMicroop(MicroPC micropc) { panic("StaticInst::fetchMicroop() called on instruction " - "that is not microcoded."); + "that is not microcoded."); } +Addr +StaticInst::branchTarget(Addr branchPC) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not a PC-relative branch."); + M5_DUMMY_RETURN; +} + +Addr +StaticInst::branchTarget(ThreadContext *tc) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not an indirect branch."); + M5_DUMMY_RETURN; +} + +Request::Flags +StaticInst::memAccFlags() +{ + panic("StaticInst::memAccFlags called on non-memory instruction"); + return 0; +} + +const string & +StaticInst::disassemble(Addr pc, const SymbolTable *symtab) const +{ + if (!cachedDisassembly) + cachedDisassembly = new string(generateDisassembly(pc, symtab)); + + return *cachedDisassembly; +} diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index ceda78d90..cb32f2333 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -42,7 +42,6 @@ #include "base/misc.hh" #include "base/refcnt.hh" #include "cpu/op_class.hh" -#include "cpu/o3/dyn_inst.hh" #include "sim/faults.hh" #include "sim/host.hh" @@ -54,8 +53,11 @@ class ThreadContext; class DynInst; class Packet; -template <class Impl> -class OzoneDynInst; +class O3CPUImpl; +template <class Impl> class BaseO3DynInst; +typedef BaseO3DynInst<O3CPUImpl> O3DynInst; +template <class Impl> class OzoneDynInst; +class InOrderDynInst; class CheckerCPU; class FastCPU; @@ -69,7 +71,27 @@ namespace Trace { class InstRecord; } -typedef uint32_t MicroPC; +typedef uint16_t MicroPC; + +static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1); + +static inline MicroPC +romMicroPC(MicroPC upc) +{ + return upc | MicroPCRomBit; +} + +static inline MicroPC +normalMicroPC(MicroPC upc) +{ + return upc & ~MicroPCRomBit; +} + +static inline bool +isRomMicroPC(MicroPC upc) +{ + return MicroPCRomBit & upc; +} /** * Base, ISA-independent static instruction class. @@ -105,38 +127,39 @@ class StaticInstBase : public RefCounted /// implement this behavior via the execute() methods. /// enum Flags { - IsNop, ///< Is a no-op (no effect at all). + IsNop, ///< Is a no-op (no effect at all). - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. + IsInteger, ///< References integer regs. + IsFloating, ///< References FP regs. - IsMemRef, ///< References memory (load, store, or prefetch). - IsLoad, ///< Reads from memory (load or prefetch). - IsStore, ///< Writes to memory. + IsMemRef, ///< References memory (load, store, or prefetch). + IsLoad, ///< Reads from memory (load or prefetch). + IsStore, ///< Writes to memory. IsStoreConditional, ///< Store conditional instruction. IsIndexed, ///< Accesses memory with an indexed address computation - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. + IsInstPrefetch, ///< Instruction-cache prefetch. + IsDataPrefetch, ///< Data-cache prefetch. IsCopy, ///< Fast Cache block copy - IsControl, ///< Control transfer instruction. - IsDirectControl, ///< PC relative control transfer. - IsIndirectControl, ///< Register indirect control transfer. - IsCondControl, ///< Conditional control transfer. - IsUncondControl, ///< Unconditional control transfer. - IsCall, ///< Subroutine call. - IsReturn, ///< Subroutine return. + IsControl, ///< Control transfer instruction. + IsDirectControl, ///< PC relative control transfer. + IsIndirectControl, ///< Register indirect control transfer. + IsCondControl, ///< Conditional control transfer. + IsUncondControl, ///< Unconditional control transfer. + IsCall, ///< Subroutine call. + IsReturn, ///< Subroutine return. IsCondDelaySlot,///< Conditional Delay-Slot Instruction - IsThreadSync, ///< Thread synchronization operation. + IsThreadSync, ///< Thread synchronization operation. - IsSerializing, ///< Serializes pipeline: won't execute until all + IsSerializing, ///< Serializes pipeline: won't execute until all /// older instructions have committed. IsSerializeBefore, IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier + IsMemBarrier, ///< Is a memory barrier + IsWriteBarrier, ///< Is a write barrier + IsReadBarrier, ///< Is a read barrier IsERET, /// <- Causes the IFU to stall (MIPS ISA) IsNonSpeculative, ///< Should not be executed speculatively @@ -150,12 +173,12 @@ class StaticInstBase : public RefCounted //Flags for microcode IsMacroop, ///< Is a macroop containing microops - IsMicroop, ///< Is a microop - IsDelayedCommit, ///< This microop doesn't commit right away - IsLastMicroop, ///< This microop ends a microop sequence - IsFirstMicroop, ///< This microop begins a microop sequence + IsMicroop, ///< Is a microop + IsDelayedCommit, ///< This microop doesn't commit right away + IsLastMicroop, ///< This microop ends a microop sequence + IsFirstMicroop, ///< This microop begins a microop sequence //This flag doesn't do anything yet - IsMicroBranch, ///< This microop branches within the microcode for a macroop + IsMicroBranch, ///< This microop branches within the microcode for a macroop IsDspOp, NumFlags @@ -215,26 +238,26 @@ class StaticInstBase : public RefCounted /// of the individual flags. //@{ - bool isNop() const { return flags[IsNop]; } + bool isNop() const { return flags[IsNop]; } - bool isMemRef() const { return flags[IsMemRef]; } - bool isLoad() const { return flags[IsLoad]; } - bool isStore() const { return flags[IsStore]; } - bool isStoreConditional() const { return flags[IsStoreConditional]; } + bool isMemRef() const { return flags[IsMemRef]; } + bool isLoad() const { return flags[IsLoad]; } + bool isStore() const { return flags[IsStore]; } + bool isStoreConditional() const { return flags[IsStoreConditional]; } bool isInstPrefetch() const { return flags[IsInstPrefetch]; } bool isDataPrefetch() const { return flags[IsDataPrefetch]; } bool isCopy() const { return flags[IsCopy];} - bool isInteger() const { return flags[IsInteger]; } - bool isFloating() const { return flags[IsFloating]; } + bool isInteger() const { return flags[IsInteger]; } + bool isFloating() const { return flags[IsFloating]; } - bool isControl() const { return flags[IsControl]; } - bool isCall() const { return flags[IsCall]; } - bool isReturn() const { return flags[IsReturn]; } - bool isDirectCtrl() const { return flags[IsDirectControl]; } + bool isControl() const { return flags[IsControl]; } + bool isCall() const { return flags[IsCall]; } + bool isReturn() const { return flags[IsReturn]; } + bool isDirectCtrl() const { return flags[IsDirectControl]; } bool isIndirectCtrl() const { return flags[IsIndirectControl]; } - bool isCondCtrl() const { return flags[IsCondControl]; } - bool isUncondCtrl() const { return flags[IsUncondControl]; } + bool isCondCtrl() const { return flags[IsCondControl]; } + bool isUncondCtrl() const { return flags[IsUncondControl]; } bool isCondDelaySlot() const { return flags[IsCondDelaySlot]; } bool isThreadSync() const { return flags[IsThreadSync]; } @@ -287,8 +310,8 @@ class StaticInst : public StaticInstBase typedef TheISA::RegIndex RegIndex; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs }; @@ -360,12 +383,7 @@ class StaticInst : public StaticInstBase { } public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } + virtual ~StaticInst(); /** * The execute() signatures are auto-generated by scons based on the @@ -384,12 +402,7 @@ class StaticInst : public StaticInstBase * Invalid if not a PC-relative branch (i.e. isDirectCtrl() * should be true). */ - virtual Addr branchTarget(Addr branchPC) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not a PC-relative branch."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(Addr branchPC) const; /** * Return the target address for an indirect branch (jump). The @@ -398,12 +411,7 @@ class StaticInst : public StaticInstBase * execute the branch in question. Invalid if not an indirect * branch (i.e. isIndirectCtrl() should be true). */ - virtual Addr branchTarget(ThreadContext *tc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(ThreadContext *tc) const; /** * Return true if the instruction is a control transfer, and if so, @@ -411,6 +419,8 @@ class StaticInst : public StaticInstBase */ bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const; + virtual Request::Flags memAccFlags(); + /** * Return string representation of disassembled instruction. * The default version of this function will call the internal @@ -419,14 +429,7 @@ class StaticInst : public StaticInstBase * should not be cached, this function should be overridden directly. */ virtual const std::string &disassemble(Addr pc, - const SymbolTable *symtab = 0) const - { - if (!cachedDisassembly) - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - - return *cachedDisassembly; - } + const SymbolTable *symtab = 0) const; /// Decoded instruction cache type. /// For now we're using a generic hash_map; this seems to work @@ -458,13 +461,13 @@ class StaticInst : public StaticInstBase /// A cache of decoded instruction objects from addresses. static AddrDecodeCache addrDecodeCache; - struct cacheElement { + struct cacheElement + { Addr page_addr; AddrDecodePage *decodePage; - cacheElement() - :decodePage(NULL) { } - } ; + cacheElement() : decodePage(NULL) { } + }; /// An array of recently decoded instructions. // might not use an array if there is only two elements @@ -493,7 +496,7 @@ class StaticInst : public StaticInstBase /// @retval A pointer to the corresponding StaticInst object. //This is defined as inlined below. static StaticInstPtr searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage); + AddrDecodePage *decodePage); }; typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; @@ -547,7 +550,8 @@ class AddrDecodePage public: /// Constructor - AddrDecodePage() { + AddrDecodePage() + { lowerMask = TheISA::PageBytes - 1; memset(valid, 0, TheISA::PageBytes); } @@ -557,7 +561,8 @@ class AddrDecodePage /// related to the address /// @param mach_inst The binary instruction to check /// @param addr The address containing the instruction - inline bool decoded(ExtMachInst mach_inst, Addr addr) + bool + decoded(ExtMachInst mach_inst, Addr addr) { return (valid[addr & lowerMask] && (instructions[addr & lowerMask]->machInst == mach_inst)); @@ -567,19 +572,22 @@ class AddrDecodePage /// to check if the instruction is valid. /// @param addr The address of the instruction. /// @retval A pointer to the corresponding StaticInst object. - inline StaticInstPtr getInst(Addr addr) - { return instructions[addr & lowerMask]; } + StaticInstPtr + getInst(Addr addr) + { + return instructions[addr & lowerMask]; + } /// Inserts a pointer to a StaticInst object into the list of decoded /// instructions on the page. /// @param addr The address of the instruction. /// @param si A pointer to the corresponding StaticInst object. - inline void insert(Addr addr, StaticInstPtr &si) + void + insert(Addr addr, StaticInstPtr &si) { instructions[addr & lowerMask] = si; valid[addr & lowerMask] = true; } - }; @@ -628,7 +636,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) } // creates a new object for a page of decoded instructions - AddrDecodePage * decodePage = new AddrDecodePage; + AddrDecodePage *decodePage = new AddrDecodePage; addrDecodeCache[page_addr] = decodePage; updateCache(page_addr, decodePage); return searchCache(mach_inst, addr, decodePage); @@ -636,7 +644,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) inline StaticInstPtr StaticInst::searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage) + AddrDecodePage *decodePage) { DecodeCache::iterator iter = decodeCache.find(mach_inst); if (iter != decodeCache.end()) { diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc index 10c94027d..ab105a435 100644 --- a/src/cpu/thread_context.cc +++ b/src/cpu/thread_context.cc @@ -74,8 +74,15 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two) if (npc1 != npc2) panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2); - int id1 = one->readCpuId(); - int id2 = two->readCpuId(); + int id1 = one->cpuId(); + int id2 = two->cpuId(); if (id1 != id2) panic("CPU ids don't match, one: %d, two: %d", id1, id2); + + id1 = one->contextId(); + id2 = two->contextId(); + if (id1 != id2) + panic("Context ids don't match, one: %d, two: %d", id1, id2); + + } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index cf51c1637..700f1571e 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -38,7 +38,6 @@ #include "sim/faults.hh" #include "sim/host.hh" #include "sim/serialize.hh" -#include "sim/syscallreturn.hh" #include "sim/byteswap.hh" // @todo: Figure out a more architecture independent way to obtain the ITB and @@ -115,26 +114,30 @@ class ThreadContext virtual BaseCPU *getCpuPtr() = 0; - virtual void setCpuId(int id) = 0; + virtual int cpuId() = 0; - virtual int readCpuId() = 0; + virtual int threadId() = 0; + + virtual void setThreadId(int id) = 0; + + virtual int contextId() = 0; + + virtual void setContextId(int id) = 0; virtual TheISA::ITB *getITBPtr() = 0; virtual TheISA::DTB *getDTBPtr() = 0; -#if FULL_SYSTEM virtual System *getSystemPtr() = 0; +#if FULL_SYSTEM virtual TheISA::Kernel::Statistics *getKernelStats() = 0; virtual FunctionalPort *getPhysPort() = 0; - virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0; - - virtual void delVirtPort(VirtualPort *vp) = 0; + virtual VirtualPort *getVirtPort() = 0; - virtual void connectMemPorts() = 0; + virtual void connectMemPorts(ThreadContext *tc) = 0; #else virtual TranslatingPort *getMemPort() = 0; @@ -181,8 +184,6 @@ class ThreadContext virtual void profileSample() = 0; #endif - virtual int getThreadNum() = 0; - // Also somewhat obnoxious. Really only used for the TLB fault. // However, may be quite useful in SPARC. virtual TheISA::MachInst getInst() = 0; @@ -256,13 +257,6 @@ class ThreadContext virtual bool misspeculating() = 0; #if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i) = 0; - - // used to shift args for indirect syscall - virtual void setSyscallArg(int i, IntReg val) = 0; - - virtual void setSyscallReturn(SyscallReturn return_value) = 0; - // Same with st cond failures. virtual Counter readFuncExeInst() = 0; @@ -274,9 +268,6 @@ class ThreadContext virtual int exit() { return 1; }; #endif - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) = 0; - /** function to compare two thread contexts (for debugging) */ static void compare(ThreadContext *one, ThreadContext *two); }; @@ -305,27 +296,31 @@ class ProxyThreadContext : public ThreadContext BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); } - void setCpuId(int id) { actualTC->setCpuId(id); } + int cpuId() { return actualTC->cpuId(); } + + int threadId() { return actualTC->threadId(); } - int readCpuId() { return actualTC->readCpuId(); } + void setThreadId(int id) { return actualTC->setThreadId(id); } + + int contextId() { return actualTC->contextId(); } + + void setContextId(int id) { actualTC->setContextId(id); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); } -#if FULL_SYSTEM System *getSystemPtr() { return actualTC->getSystemPtr(); } +#if FULL_SYSTEM TheISA::Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); } FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); } + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } - void connectMemPorts() { actualTC->connectMemPorts(); } + void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } @@ -371,9 +366,6 @@ class ProxyThreadContext : public ThreadContext void profileClear() { return actualTC->profileClear(); } void profileSample() { return actualTC->profileSample(); } #endif - - int getThreadNum() { return actualTC->getThreadNum(); } - // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } @@ -433,7 +425,7 @@ class ProxyThreadContext : public ThreadContext uint64_t readNextMicroPC() { return actualTC->readMicroPC(); } - void setNextMicroPC(uint64_t val) { actualTC->setMicroPC(val); } + void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); } MiscReg readMiscRegNoEffect(int misc_reg) { return actualTC->readMiscRegNoEffect(misc_reg); } @@ -457,26 +449,11 @@ class ProxyThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualTC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualTC->setSyscallReturn(return_value); } - void syscall(int64_t callnum) { actualTC->syscall(callnum); } Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - } }; #endif diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index be8f822f2..b0e719ddf 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -43,15 +43,15 @@ #endif #if FULL_SYSTEM -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), +ThreadState::ThreadState(BaseCPU *cpu, int _tid) + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), - physPort(NULL), virtPort(NULL), + kernelStats(NULL), physPort(NULL), virtPort(NULL), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #else -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, +ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), port(NULL), process(_process), asid(_asid), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #endif @@ -105,7 +105,7 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) Tick quiesceEndTick; UNSERIALIZE_SCALAR(quiesceEndTick); if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); + baseCpu->schedule(quiesceEvent, quiesceEndTick); if (kernelStats) kernelStats->unserialize(cp, section); #endif @@ -113,10 +113,10 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) #if FULL_SYSTEM void -ThreadState::connectMemPorts() +ThreadState::connectMemPorts(ThreadContext *tc) { connectPhysPort(); - connectVirtPort(); + connectVirtPort(tc); } void @@ -129,12 +129,12 @@ ThreadState::connectPhysPort() physPort->removeConn(); else physPort = new FunctionalPort(csprintf("%s-%d-funcport", - baseCpu->name(), tid)); + baseCpu->name(), _threadId)); connectToMemFunc(physPort); } void -ThreadState::connectVirtPort() +ThreadState::connectVirtPort(ThreadContext *tc) { // @todo: For now this disregards any older port that may have // already existed. Fix this memory leak once the bus port IDs @@ -143,7 +143,7 @@ ThreadState::connectVirtPort() virtPort->removeConn(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", - baseCpu->name(), tid)); + baseCpu->name(), _threadId), tc); connectToMemFunc(virtPort); } @@ -169,7 +169,7 @@ ThreadState::getMemPort() return port; /* Use this port to for syscall emulation writes to memory. */ - port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid), + port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), _threadId), process, TranslatingPort::NextPage); connectToMemFunc(port); diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 4f878db1f..99f0c2a87 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -34,6 +34,7 @@ #include "arch/types.hh" #include "cpu/profile.hh" #include "cpu/thread_context.hh" +#include "cpu/base.hh" #if !FULL_SYSTEM #include "mem/mem_object.hh" @@ -51,7 +52,6 @@ namespace TheISA { }; #endif -class BaseCPU; class Checkpoint; class Port; class TranslatingPort; @@ -66,9 +66,9 @@ struct ThreadState { typedef ThreadContext::Status Status; #if FULL_SYSTEM - ThreadState(BaseCPU *cpu, int _cpuId, int _tid); + ThreadState(BaseCPU *cpu, int _tid); #else - ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, + ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid); #endif @@ -78,24 +78,26 @@ struct ThreadState { void unserialize(Checkpoint *cp, const std::string §ion); - void setCpuId(int id) { cpuId = id; } + int cpuId() { return baseCpu->cpuId(); } - int readCpuId() { return cpuId; } + int contextId() { return _contextId; } - void setTid(int id) { tid = id; } + void setContextId(int id) { _contextId = id; } - int readTid() { return tid; } + void setThreadId(int id) { _threadId = id; } + + int threadId() { return _threadId; } Tick readLastActivate() { return lastActivate; } Tick readLastSuspend() { return lastSuspend; } #if FULL_SYSTEM - void connectMemPorts(); + void connectMemPorts(ThreadContext *tc); void connectPhysPort(); - void connectVirtPort(); + void connectVirtPort(ThreadContext *tc); void dumpFuncProfile(); @@ -111,9 +113,7 @@ struct ThreadState { void setPhysPort(FunctionalPort *port) { physPort = port; } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; } - - void setVirtPort(VirtualPort *port) { virtPort = port; } + VirtualPort *getVirtPort() { return virtPort; } #else Process *getProcessPtr() { return process; } @@ -155,9 +155,9 @@ struct ThreadState { /** Number of instructions committed. */ Counter numInst; /** Stat for number instructions committed. */ - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; /** Stat for number of memory references. */ - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; /** Number of simulated loads, used for tracking events based on * the number of loads committed. @@ -173,12 +173,11 @@ struct ThreadState { // Pointer to the base CPU. BaseCPU *baseCpu; - // ID of this context w.r.t. the System or Process object to which - // it belongs. For full-system mode, this is the system CPU ID. - int cpuId; + // system wide HW context id + int _contextId; // Index of hardware thread context on the CPU that this represents. - int tid; + int _threadId; public: /** Last time activate was called on this thread. */ @@ -201,7 +200,7 @@ struct ThreadState { FunctionalPort *physPort; /** A functional port, outgoing only, for functional accesse to virtual - * addresses. That doen't require execution context information */ + * addresses. */ VirtualPort *virtPort; #else TranslatingPort *port; diff --git a/src/dev/CopyEngine.py b/src/dev/CopyEngine.py new file mode 100644 index 000000000..29d9a23dd --- /dev/null +++ b/src/dev/CopyEngine.py @@ -0,0 +1,59 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Ali Saidi + +from m5.SimObject import SimObject +from m5.params import * +from m5.proxy import * +from Pci import PciDevice + +class CopyEngine(PciDevice): + type = 'CopyEngine' + VendorID = 0x8086 + DeviceID = 0x1a38 + Revision = 0xA2 # CM2 stepping (newest listed) + SubsystemID = 0 + SubsystemVendorID = 0 + Status = 0x0000 + SubClassCode = 0x08 + ClassCode = 0x80 + ProgIF = 0x00 + MaximumLatency = 0x00 + MinimumGrant = 0xff + InterruptLine = 0x20 + InterruptPin = 0x01 + BAR0Size = '1kB' + + ChanCnt = Param.UInt8(4, "Number of DMA channels that exist on device") + XferCap = Param.MemorySize('4kB', "Number of bits of transfer size that are supported") + + + clock = Param.Clock('500MHz', "Clock speed of the device") + latBeforeBegin = Param.Latency('20ns', "Latency after a DMA command is seen before it's proccessed") + latAfterCompletion = Param.Latency('20ns', "Latency after a DMA command is complete before it's reported as such") + + diff --git a/src/dev/DiskImage.py b/src/dev/DiskImage.py index af2407458..92eb0553c 100644 --- a/src/dev/DiskImage.py +++ b/src/dev/DiskImage.py @@ -42,3 +42,4 @@ class CowDiskImage(DiskImage): child = Param.DiskImage(RawDiskImage(read_only=True), "child image") table_size = Param.Int(65536, "initial table size") + image_file = "" diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py index 2beb0d537..d73d56d03 100644 --- a/src/dev/Ethernet.py +++ b/src/dev/Ethernet.py @@ -67,6 +67,7 @@ class EtherDevice(PciDevice): interface = Port("Ethernet Interrface") class IGbE(EtherDevice): + # Base class for two IGbE adapters listed above type = 'IGbE' hardware_address = Param.EthernetAddr(NextEthernetAddr, "Ethernet Hardware Address") @@ -80,7 +81,6 @@ class IGbE(EtherDevice): "Number of enteries in the rx descriptor cache") clock = Param.Clock('500MHz', "Clock speed of the device") VendorID = 0x8086 - DeviceID = 0x1075 SubsystemID = 0x1008 SubsystemVendorID = 0x8086 Status = 0x0000 @@ -98,6 +98,28 @@ class IGbE(EtherDevice): InterruptLine = 0x1e InterruptPin = 0x01 BAR0Size = '128kB' + wb_delay = Param.Latency('10ns', "delay before desc writeback occurs") + fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs") + fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs") + wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs") + tx_read_delay = Param.Latency('0ns', "delay after tx dma read") + rx_write_delay = Param.Latency('0ns', "delay after rx dma read") + phy_pid = Param.UInt16("Phy PID that corresponds to device ID") + phy_epid = Param.UInt16("Phy EPID that corresponds to device ID") + +class IGbE_e1000(IGbE): + # Older Intel 8254x based gigabit ethernet adapter + # Uses Intel e1000 driver + DeviceID = 0x1075 + phy_pid = 0x02A8 + phy_epid = 0x0380 + +class IGbE_igb(IGbE): + # Newer Intel 8257x based gigabit ethernet adapter + # Uses Intel igb driver and in theory supports packet splitting and LRO + DeviceID = 0x10C9 + phy_pid = 0x0141 + phy_epid = 0x0CC0 class EtherDevBase(EtherDevice): type = 'EtherDevBase' @@ -153,8 +175,7 @@ class NSGigE(EtherDevBase): class Sinic(EtherDevBase): type = 'Sinic' - cxx_namespace = 'Sinic' - cxx_class = 'Device' + cxx_class = 'Sinic::Device' rx_max_copy = Param.MemorySize('1514B', "rx max copy") tx_max_copy = Param.MemorySize('16kB', "tx max copy") @@ -164,6 +185,9 @@ class Sinic(EtherDevBase): tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold") tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold") virtual_count = Param.UInt32(1, "Virtualized SINIC") + zero_copy_size = Param.UInt32(64, "Bytes to copy if below threshold") + zero_copy_threshold = Param.UInt32(256, + "Only zero copy above this threshold") zero_copy = Param.Bool(False, "Zero copy receive") delay_copy = Param.Bool(False, "Delayed copy transmit") virtual_addr = Param.Bool(False, "Virtual addressing") diff --git a/src/dev/Pci.py b/src/dev/Pci.py index b50e1b15c..bd67d82fb 100644 --- a/src/dev/Pci.py +++ b/src/dev/Pci.py @@ -73,6 +73,12 @@ class PciDevice(DmaDevice): BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size") BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size") BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size") + BAR0LegacyIO = Param.Bool(False, "Whether BAR0 is hardwired legacy IO") + BAR1LegacyIO = Param.Bool(False, "Whether BAR1 is hardwired legacy IO") + BAR2LegacyIO = Param.Bool(False, "Whether BAR2 is hardwired legacy IO") + BAR3LegacyIO = Param.Bool(False, "Whether BAR3 is hardwired legacy IO") + BAR4LegacyIO = Param.Bool(False, "Whether BAR4 is hardwired legacy IO") + BAR5LegacyIO = Param.Bool(False, "Whether BAR5 is hardwired legacy IO") CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure") SubsystemID = Param.UInt16(0x00, "Subsystem ID") diff --git a/src/dev/SConscript b/src/dev/SConscript index 0aba8ac35..c09ec3dcd 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -33,19 +33,22 @@ Import('*') if env['FULL_SYSTEM']: SimObject('BadDevice.py') + SimObject('CopyEngine.py') SimObject('Device.py') SimObject('DiskImage.py') SimObject('Ethernet.py') SimObject('Ide.py') SimObject('Pci.py') SimObject('Platform.py') - SimObject('SimConsole.py') SimObject('SimpleDisk.py') + SimObject('Terminal.py') SimObject('Uart.py') Source('baddev.cc') + Source('copy_engine.cc') Source('disk_image.cc') Source('etherbus.cc') + Source('etherdevice.cc') Source('etherdump.cc') Source('etherint.cc') Source('etherlink.cc') @@ -54,24 +57,25 @@ if env['FULL_SYSTEM']: Source('i8254xGBe.cc') Source('ide_ctrl.cc') Source('ide_disk.cc') + Source('intel_8254_timer.cc') Source('io_device.cc') Source('isa_fake.cc') + Source('mc146818.cc') Source('ns_gige.cc') Source('pciconfigall.cc') Source('pcidev.cc') Source('pktfifo.cc') Source('platform.cc') - Source('simconsole.cc') Source('simple_disk.cc') Source('sinic.cc') + Source('terminal.cc') Source('uart.cc') Source('uart8250.cc') - TraceFlag('Console') - TraceFlag('ConsoleVerbose') TraceFlag('DiskImageRead') TraceFlag('DiskImageWrite') TraceFlag('DMA') + TraceFlag('DMACopyEngine') TraceFlag('Ethernet') TraceFlag('EthernetCksum') TraceFlag('EthernetDMA') @@ -83,17 +87,21 @@ if env['FULL_SYSTEM']: TraceFlag('EthernetSM') TraceFlag('IdeCtrl') TraceFlag('IdeDisk') + TraceFlag('Intel8254Timer') TraceFlag('IsaFake') + TraceFlag('MC146818') TraceFlag('PCIDEV') TraceFlag('PciConfigAll') TraceFlag('SimpleDisk') TraceFlag('SimpleDiskData') + TraceFlag('Terminal') + TraceFlag('TerminalVerbose') TraceFlag('Uart') CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ]) CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', - 'EthernetCksum' ]) + 'EthernetCksum', 'EthernetEEPROM' ]) CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ]) CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ]) diff --git a/src/dev/SimConsole.py b/src/dev/Terminal.py index bb8420527..d67019198 100644 --- a/src/dev/SimConsole.py +++ b/src/dev/Terminal.py @@ -30,10 +30,9 @@ from m5.SimObject import SimObject from m5.params import * from m5.proxy import * -class SimConsole(SimObject): - type = 'SimConsole' - append_name = Param.Bool(True, "append name() to filename") +class Terminal(SimObject): + type = 'Terminal' intr_control = Param.IntrControl(Parent.any, "interrupt controller") port = Param.TcpPort(3456, "listen port") - number = Param.Int(0, "console number") - output = Param.String('console', "file to dump output to") + number = Param.Int(0, "terminal number") + output = Param.Bool(True, "Enable output dump to file") diff --git a/src/dev/Uart.py b/src/dev/Uart.py index e32517a4c..c5db3c42f 100644 --- a/src/dev/Uart.py +++ b/src/dev/Uart.py @@ -34,7 +34,7 @@ from Device import BasicPioDevice class Uart(BasicPioDevice): type = 'Uart' abstract = True - sim_console = Param.SimConsole(Parent.any, "The console") + terminal = Param.Terminal(Parent.any, "The terminal") class Uart8250(Uart): type = 'Uart8250' diff --git a/src/dev/alpha/AlphaConsole.py b/src/dev/alpha/AlphaBackdoor.py index 43c7ef954..fa9627164 100644 --- a/src/dev/alpha/AlphaConsole.py +++ b/src/dev/alpha/AlphaBackdoor.py @@ -30,9 +30,9 @@ from m5.params import * from m5.proxy import * from Device import BasicPioDevice -class AlphaConsole(BasicPioDevice): - type = 'AlphaConsole' +class AlphaBackdoor(BasicPioDevice): + type = 'AlphaBackdoor' cpu = Param.BaseCPU(Parent.cpu[0], "Processor") disk = Param.SimpleDisk("Simple Disk") - sim_console = Param.SimConsole(Parent.any, "The Simulator Console") + terminal = Param.Terminal(Parent.any, "The console terminal") system = Param.AlphaSystem(Parent.any, "system object") diff --git a/src/dev/alpha/SConscript b/src/dev/alpha/SConscript index 2292c3c57..4dbb73903 100644 --- a/src/dev/alpha/SConscript +++ b/src/dev/alpha/SConscript @@ -32,15 +32,14 @@ Import('*') if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'alpha': - SimObject('AlphaConsole.py') + SimObject('AlphaBackdoor.py') SimObject('Tsunami.py') - Source('console.cc') + Source('backdoor.cc') Source('tsunami.cc') Source('tsunami_cchip.cc') Source('tsunami_io.cc') Source('tsunami_pchip.cc') - TraceFlag('AlphaConsole') - TraceFlag('MC146818') + TraceFlag('AlphaBackdoor') TraceFlag('Tsunami') diff --git a/src/dev/alpha/Tsunami.py b/src/dev/alpha/Tsunami.py index 484976c09..5440486b6 100644 --- a/src/dev/alpha/Tsunami.py +++ b/src/dev/alpha/Tsunami.py @@ -28,12 +28,12 @@ from m5.params import * from m5.proxy import * +from BadDevice import BadDevice +from AlphaBackdoor import AlphaBackdoor from Device import BasicPioDevice, IsaFake, BadAddr +from Pci import PciConfigAll from Platform import Platform -from AlphaConsole import AlphaConsole from Uart import Uart8250 -from Pci import PciConfigAll -from BadDevice import BadDevice class TsunamiCChip(BasicPioDevice): type = 'TsunamiCChip' @@ -87,7 +87,7 @@ class Tsunami(Platform): fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer') io = TsunamiIO(pio_addr=0x801fc000000) uart = Uart8250(pio_addr=0x801fc0003f8) - console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk) + backdoor = AlphaBackdoor(pio_addr=0x80200000000, disk=Parent.simple_disk) # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the @@ -120,4 +120,4 @@ class Tsunami(Platform): self.fb.pio = bus.port self.io.pio = bus.port self.uart.pio = bus.port - self.console.pio = bus.port + self.backdoor.pio = bus.port diff --git a/src/dev/alpha/access.h b/src/dev/alpha/access.h index 4adeaf84b..72eb4950a 100644 --- a/src/dev/alpha/access.h +++ b/src/dev/alpha/access.h @@ -45,31 +45,31 @@ typedef unsigned long uint64_t; // This structure hacked up from simos struct AlphaAccess { - uint32_t last_offset; // 00: must be first field - uint32_t version; // 04: - uint32_t numCPUs; // 08: - uint32_t intrClockFrequency; // 0C: Hz - uint64_t cpuClock; // 10: MHz - uint64_t mem_size; // 18: + uint32_t last_offset; // 00: must be first field + uint32_t version; // 04: + uint32_t numCPUs; // 08: + uint32_t intrClockFrequency; // 0C: Hz + uint64_t cpuClock; // 10: MHz + uint64_t mem_size; // 18: // Loaded kernel - uint64_t kernStart; // 20: - uint64_t kernEnd; // 28: - uint64_t entryPoint; // 30: + uint64_t kernStart; // 20: + uint64_t kernEnd; // 28: + uint64_t entryPoint; // 30: // console disk stuff - uint64_t diskUnit; // 38: - uint64_t diskCount; // 40: - uint64_t diskPAddr; // 48: - uint64_t diskBlock; // 50: - uint64_t diskOperation; // 58: + uint64_t diskUnit; // 38: + uint64_t diskCount; // 40: + uint64_t diskPAddr; // 48: + uint64_t diskBlock; // 50: + uint64_t diskOperation; // 58: // console simple output stuff - uint64_t outputChar; // 60: Placeholder for output - uint64_t inputChar; // 68: Placeholder for input + uint64_t outputChar; // 60: Placeholder for output + uint64_t inputChar; // 68: Placeholder for input // MP boot - uint64_t cpuStack[64]; // 70: + uint64_t cpuStack[64]; // 70: }; #endif // __ALPHA_ACCESS_H__ diff --git a/src/dev/alpha/console.cc b/src/dev/alpha/backdoor.cc index 493a21f99..66f682e66 100644 --- a/src/dev/alpha/console.cc +++ b/src/dev/alpha/backdoor.cc @@ -32,7 +32,7 @@ */ /** @file - * Alpha Console Definition + * Alpha Console Backdoor Definition */ #include <cstddef> @@ -44,21 +44,21 @@ #include "base/trace.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" -#include "dev/alpha/console.hh" +#include "dev/alpha/backdoor.hh" #include "dev/platform.hh" -#include "dev/simconsole.hh" #include "dev/simple_disk.hh" +#include "dev/terminal.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" #include "mem/physical.hh" -#include "params/AlphaConsole.hh" +#include "params/AlphaBackdoor.hh" #include "sim/sim_object.hh" using namespace std; using namespace AlphaISA; -AlphaConsole::AlphaConsole(const Params *p) - : BasicPioDevice(p), disk(p->disk), console(p->sim_console), +AlphaBackdoor::AlphaBackdoor(const Params *p) + : BasicPioDevice(p), disk(p->disk), terminal(p->terminal), system(p->system), cpu(p->cpu) { @@ -81,10 +81,10 @@ AlphaConsole::AlphaConsole(const Params *p) } void -AlphaConsole::startup() +AlphaBackdoor::startup() { system->setAlphaAccess(pioAddr); - alphaAccess->numCPUs = system->getNumCPUs(); + alphaAccess->numCPUs = system->numContexts(); alphaAccess->kernStart = system->getKernelStart(); alphaAccess->kernEnd = system->getKernelEnd(); alphaAccess->entryPoint = system->getKernelEntry(); @@ -94,7 +94,7 @@ AlphaConsole::startup() } Tick -AlphaConsole::read(PacketPtr pkt) +AlphaBackdoor::read(PacketPtr pkt) { /** XXX Do we want to push the addr munging to a bus brige or something? So @@ -132,14 +132,14 @@ AlphaConsole::read(PacketPtr pkt) */ pkt->setBadAddress(); } - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr, pkt->get<uint32_t>()); break; case sizeof(uint64_t): switch (daddr) { case offsetof(AlphaAccess, inputChar): - pkt->set(console->console_in()); + pkt->set(terminal->console_in()); break; case offsetof(AlphaAccess, cpuClock): pkt->set(alphaAccess->cpuClock); @@ -183,7 +183,7 @@ AlphaConsole::read(PacketPtr pkt) else panic("Unknown 64bit access, %#x\n", daddr); } - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr, pkt->get<uint64_t>()); break; default: @@ -193,7 +193,7 @@ AlphaConsole::read(PacketPtr pkt) } Tick -AlphaConsole::write(PacketPtr pkt) +AlphaBackdoor::write(PacketPtr pkt) { assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); Addr daddr = pkt->getAddr() - pioAddr; @@ -228,7 +228,7 @@ AlphaConsole::write(PacketPtr pkt) break; case offsetof(AlphaAccess, outputChar): - console->out((char)(val & 0xff)); + terminal->out((char)(val & 0xff)); break; default: @@ -248,7 +248,7 @@ AlphaConsole::write(PacketPtr pkt) } void -AlphaConsole::Access::serialize(ostream &os) +AlphaBackdoor::Access::serialize(ostream &os) { SERIALIZE_SCALAR(last_offset); SERIALIZE_SCALAR(version); @@ -270,7 +270,7 @@ AlphaConsole::Access::serialize(ostream &os) } void -AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) +AlphaBackdoor::Access::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(last_offset); UNSERIALIZE_SCALAR(version); @@ -292,19 +292,19 @@ AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) } void -AlphaConsole::serialize(ostream &os) +AlphaBackdoor::serialize(ostream &os) { alphaAccess->serialize(os); } void -AlphaConsole::unserialize(Checkpoint *cp, const std::string §ion) +AlphaBackdoor::unserialize(Checkpoint *cp, const std::string §ion) { alphaAccess->unserialize(cp, section); } -AlphaConsole * -AlphaConsoleParams::create() +AlphaBackdoor * +AlphaBackdoorParams::create() { - return new AlphaConsole(this); + return new AlphaBackdoor(this); } diff --git a/src/dev/alpha/console.hh b/src/dev/alpha/backdoor.hh index e77a7fad6..ad3c79823 100644 --- a/src/dev/alpha/console.hh +++ b/src/dev/alpha/backdoor.hh @@ -29,28 +29,28 @@ */ /** @file - * System Console Interface + * System Console Backdoor Interface */ -#ifndef __ALPHA_CONSOLE_HH__ -#define __ALPHA_CONSOLE_HH__ +#ifndef __DEV_ALPHA_BACKDOOR_HH__ +#define __DEV_ALPHA_BACKDOOR_HH__ #include "base/range.hh" #include "dev/alpha/access.h" #include "dev/io_device.hh" -#include "params/AlphaConsole.hh" +#include "params/AlphaBackdoor.hh" #include "sim/host.hh" #include "sim/sim_object.hh" class BaseCPU; -class SimConsole; +class Terminal; class AlphaSystem; class SimpleDisk; /** * Memory mapped interface to the system console. This device * represents a shared data region between the OS Kernel and the - * System Console. + * System Console Backdoor. * * The system console is a small standalone program that is initially * run when the system boots. It contains the necessary code to @@ -72,7 +72,7 @@ class SimpleDisk; * primarily used doing boot before the kernel has loaded its device * drivers. */ -class AlphaConsole : public BasicPioDevice +class AlphaBackdoor : public BasicPioDevice { protected: struct Access : public AlphaAccess @@ -90,7 +90,7 @@ class AlphaConsole : public BasicPioDevice SimpleDisk *disk; /** the system console (the terminal) is accessable from the console */ - SimConsole *console; + Terminal *terminal; /** a pointer to the system we are running in */ AlphaSystem *system; @@ -99,8 +99,8 @@ class AlphaConsole : public BasicPioDevice BaseCPU *cpu; public: - typedef AlphaConsoleParams Params; - AlphaConsole(const Params *p); + typedef AlphaBackdoorParams Params; + AlphaBackdoor(const Params *p); const Params * params() const @@ -123,4 +123,4 @@ class AlphaConsole : public BasicPioDevice virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -#endif // __ALPHA_CONSOLE_HH__ +#endif // __DEV_ALPHA_BACKDOOR_HH__ diff --git a/src/dev/alpha/tsunami.cc b/src/dev/alpha/tsunami.cc index 5bc0de5da..b6478fe22 100644 --- a/src/dev/alpha/tsunami.cc +++ b/src/dev/alpha/tsunami.cc @@ -37,11 +37,11 @@ #include <vector> #include "cpu/intr_control.hh" -#include "dev/simconsole.hh" #include "dev/alpha/tsunami_cchip.hh" #include "dev/alpha/tsunami_pchip.hh" #include "dev/alpha/tsunami_io.hh" #include "dev/alpha/tsunami.hh" +#include "dev/terminal.hh" #include "sim/system.hh" using namespace std; @@ -96,11 +96,23 @@ Tsunami::pciToDma(Addr pciAddr) const Addr -Tsunami::calcConfigAddr(int bus, int dev, int func) +Tsunami::calcPciConfigAddr(int bus, int dev, int func) { return pchip->calcConfigAddr(bus, dev, func); } +Addr +Tsunami::calcPciIOAddr(Addr addr) +{ + return pchip->calcIOAddr(addr); +} + +Addr +Tsunami::calcPciMemAddr(Addr addr) +{ + return pchip->calcMemAddr(addr); +} + void Tsunami::serialize(std::ostream &os) { diff --git a/src/dev/alpha/tsunami.hh b/src/dev/alpha/tsunami.hh index 44c5d41a4..64aafe533 100644 --- a/src/dev/alpha/tsunami.hh +++ b/src/dev/alpha/tsunami.hh @@ -116,7 +116,17 @@ class Tsunami : public Platform /** * Calculate the configuration address given a bus/dev/func. */ - virtual Addr calcConfigAddr(int bus, int dev, int func); + virtual Addr calcPciConfigAddr(int bus, int dev, int func); + + /** + * Calculate the address for an IO location on the PCI bus. + */ + virtual Addr calcPciIOAddr(Addr addr); + + /** + * Calculate the address for a memory location on the PCI bus. + */ + virtual Addr calcPciMemAddr(Addr addr); /** * Serialize this object to the given output stream. diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc index 891fe17da..52a2aea14 100644 --- a/src/dev/alpha/tsunami_cchip.cc +++ b/src/dev/alpha/tsunami_cchip.cc @@ -109,8 +109,14 @@ TsunamiCChip::read(PacketPtr pkt) panic("TSDEV_CC_MTR not implemeted\n"); break; case TSDEV_CC_MISC: - pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF | - (pkt->req->getCpuNum() & 0x3)); + pkt->set(((ipint << 8) & 0xF) | ((itint << 4) & 0xF) | + (pkt->req->contextId() & 0x3)); + // currently, FS cannot handle MT so contextId and + // cpuId are effectively the same, don't know if it will + // matter if FS becomes MT enabled. I suspect no because + // we are currently able to boot up to 64 procs anyway + // which would render the CPUID of this register useless + // anyway break; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc index 710aca48d..9c88904e3 100644 --- a/src/dev/alpha/tsunami_io.cc +++ b/src/dev/alpha/tsunami_io.cc @@ -42,7 +42,6 @@ #include "base/time.hh" #include "base/trace.hh" -#include "dev/pitreg.h" #include "dev/rtcreg.h" #include "dev/alpha/tsunami_cchip.hh" #include "dev/alpha/tsunami.hh" @@ -57,386 +56,15 @@ using namespace std; //Should this be AlphaISA? using namespace TheISA; -TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, - const TsunamiIO::Params *p) - : _name(n), event(tsunami, p->frequency), addr(0) +TsunamiIO::RTC::RTC(const string &n, const TsunamiIOParams *p) + : MC146818(p->tsunami, n, p->time, p->year_is_bcd, p->frequency), + tsunami(p->tsunami) { - memset(clock_data, 0, sizeof(clock_data)); - stat_regA = RTCA_32768HZ | RTCA_1024HZ; - stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; - - year = p->time.tm_year; - - if (p->year_is_bcd) { - // The datasheet says that the year field can be either BCD or - // years since 1900. Linux seems to be happy with years since - // 1900. - year = year % 100; - int tens = year / 10; - int ones = year % 10; - year = (tens << 4) + ones; - } - - // Unix is 0-11 for month, data seet says start at 1 - mon = p->time.tm_mon + 1; - mday = p->time.tm_mday; - hour = p->time.tm_hour; - min = p->time.tm_min; - sec = p->time.tm_sec; - - // Datasheet says 1 is sunday - wday = p->time.tm_wday + 1; - - DPRINTFN("Real-time clock set to %s", asctime(&p->time)); -} - -void -TsunamiIO::RTC::writeAddr(const uint8_t data) -{ - if (data <= RTC_STAT_REGD) - addr = data; - else - panic("RTC addresses over 0xD are not implemented.\n"); -} - -void -TsunamiIO::RTC::writeData(const uint8_t data) -{ - if (addr < RTC_STAT_REGA) - clock_data[addr] = data; - else { - switch (addr) { - case RTC_STAT_REGA: - if (data != (RTCA_32768HZ | RTCA_1024HZ)) - panic("Unimplemented RTC register A value write!\n"); - stat_regA = data; - break; - case RTC_STAT_REGB: - if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) - panic("Write to RTC reg B bits that are not implemented!\n"); - - if (data & RTCB_PRDC_IE) { - if (!event.scheduled()) - event.scheduleIntr(); - } else { - if (event.scheduled()) - event.deschedule(); - } - stat_regB = data; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - panic("RTC status registers C and D are not implemented.\n"); - break; - } - } -} - -uint8_t -TsunamiIO::RTC::readData() -{ - if (addr < RTC_STAT_REGA) - return clock_data[addr]; - else { - switch (addr) { - case RTC_STAT_REGA: - // toggle UIP bit for linux - stat_regA ^= RTCA_UIP; - return stat_regA; - break; - case RTC_STAT_REGB: - return stat_regB; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - return 0x00; - break; - default: - panic("Shouldn't be here"); - } - } -} - -void -TsunamiIO::RTC::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".addr", addr); - arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); - paramOut(os, base + ".stat_regA", stat_regA); - paramOut(os, base + ".stat_regB", stat_regB); -} - -void -TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".addr", addr); - arrayParamIn(cp, section, base + ".clock_data", clock_data, - sizeof(clock_data)); - paramIn(cp, section, base + ".stat_regA", stat_regA); - paramIn(cp, section, base + ".stat_regB", stat_regB); - - // We're not unserializing the event here, but we need to - // rescehedule the event since curTick was moved forward by the - // checkpoint - event.reschedule(curTick + event.interval); -} - -TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) - : Event(&mainEventQueue), tsunami(t), interval(i) -{ - DPRINTF(MC146818, "RTC Event Initilizing\n"); - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::scheduleIntr() -{ - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::process() -{ - DPRINTF(MC146818, "RTC Timer Interrupt\n"); - schedule(curTick + interval); - //Actually interrupt the processor here - tsunami->cchip->postRTC(); -} - -const char * -TsunamiIO::RTC::RTCEvent::description() const -{ - return "tsunami RTC interrupt"; -} - -TsunamiIO::PITimer::PITimer(const string &name) - : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), - counter2(name + ".counter2") -{ - counter[0] = &counter0; - counter[1] = &counter0; - counter[2] = &counter0; -} - -void -TsunamiIO::PITimer::writeControl(const uint8_t data) -{ - int rw; - int sel; - - sel = GET_CTRL_SEL(data); - - if (sel == PIT_READ_BACK) - panic("PITimer Read-Back Command is not implemented.\n"); - - rw = GET_CTRL_RW(data); - - if (rw == PIT_RW_LATCH_COMMAND) - counter[sel]->latchCount(); - else { - counter[sel]->setRW(rw); - counter[sel]->setMode(GET_CTRL_MODE(data)); - counter[sel]->setBCD(GET_CTRL_BCD(data)); - } -} - -void -TsunamiIO::PITimer::serialize(const string &base, ostream &os) -{ - // serialize the counters - counter0.serialize(base + ".counter0", os); - counter1.serialize(base + ".counter1", os); - counter2.serialize(base + ".counter2", os); -} - -void -TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - // unserialze the counters - counter0.unserialize(base + ".counter0", cp, section); - counter1.unserialize(base + ".counter1", cp, section); - counter2.unserialize(base + ".counter2", cp, section); -} - -TsunamiIO::PITimer::Counter::Counter(const string &name) - : _name(name), event(this), count(0), latched_count(0), period(0), - mode(0), output_high(false), latch_on(false), read_byte(LSB), - write_byte(LSB) -{ - -} - -void -TsunamiIO::PITimer::Counter::latchCount() -{ - // behave like a real latch - if(!latch_on) { - latch_on = true; - read_byte = LSB; - latched_count = count; - } -} - -uint8_t -TsunamiIO::PITimer::Counter::read() -{ - if (latch_on) { - switch (read_byte) { - case LSB: - read_byte = MSB; - return (uint8_t)latched_count; - break; - case MSB: - read_byte = LSB; - latch_on = false; - return latched_count >> 8; - break; - default: - panic("Shouldn't be here"); - } - } else { - switch (read_byte) { - case LSB: - read_byte = MSB; - return (uint8_t)count; - break; - case MSB: - read_byte = LSB; - return count >> 8; - break; - default: - panic("Shouldn't be here"); - } - } -} - -void -TsunamiIO::PITimer::Counter::write(const uint8_t data) -{ - switch (write_byte) { - case LSB: - count = (count & 0xFF00) | data; - - if (event.scheduled()) - event.deschedule(); - output_high = false; - write_byte = MSB; - break; - - case MSB: - count = (count & 0x00FF) | (data << 8); - period = count; - - if (period > 0) { - DPRINTF(Tsunami, "Timer set to curTick + %d\n", - count * event.interval); - event.schedule(curTick + count * event.interval); - } - write_byte = LSB; - break; - } -} - -void -TsunamiIO::PITimer::Counter::setRW(int rw_val) -{ - if (rw_val != PIT_RW_16BIT) - panic("Only LSB/MSB read/write is implemented.\n"); -} - -void -TsunamiIO::PITimer::Counter::setMode(int mode_val) -{ - if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && - mode_val != PIT_MODE_SQWAVE) - panic("PIT mode %#x is not implemented: \n", mode_val); - - mode = mode_val; -} - -void -TsunamiIO::PITimer::Counter::setBCD(int bcd_val) -{ - if (bcd_val != PIT_BCD_FALSE) - panic("PITimer does not implement BCD counts.\n"); -} - -bool -TsunamiIO::PITimer::Counter::outputHigh() -{ - return output_high; -} - -void -TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".count", count); - paramOut(os, base + ".latched_count", latched_count); - paramOut(os, base + ".period", period); - paramOut(os, base + ".mode", mode); - paramOut(os, base + ".output_high", output_high); - paramOut(os, base + ".latch_on", latch_on); - paramOut(os, base + ".read_byte", read_byte); - paramOut(os, base + ".write_byte", write_byte); - - Tick event_tick = 0; - if (event.scheduled()) - event_tick = event.when(); - paramOut(os, base + ".event_tick", event_tick); -} - -void -TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".count", count); - paramIn(cp, section, base + ".latched_count", latched_count); - paramIn(cp, section, base + ".period", period); - paramIn(cp, section, base + ".mode", mode); - paramIn(cp, section, base + ".output_high", output_high); - paramIn(cp, section, base + ".latch_on", latch_on); - paramIn(cp, section, base + ".read_byte", read_byte); - paramIn(cp, section, base + ".write_byte", write_byte); - - Tick event_tick; - paramIn(cp, section, base + ".event_tick", event_tick); - if (event_tick) - event.schedule(event_tick); -} - -TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) - : Event(&mainEventQueue) -{ - interval = (Tick)(Clock::Float::s / 1193180.0); - counter = c_ptr; -} - -void -TsunamiIO::PITimer::Counter::CounterEvent::process() -{ - DPRINTF(Tsunami, "Timer Interrupt\n"); - switch (counter->mode) { - case PIT_MODE_INTTC: - counter->output_high = true; - case PIT_MODE_RATEGEN: - case PIT_MODE_SQWAVE: - break; - default: - panic("Unimplemented PITimer mode.\n"); - } -} - -const char * -TsunamiIO::PITimer::Counter::CounterEvent::description() const -{ - return "tsunami 8254 Interval timer"; } TsunamiIO::TsunamiIO(const Params *p) - : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), - rtc(p->name + ".rtc", p->tsunami, p) + : BasicPioDevice(p), tsunami(p->tsunami), + pitimer(this, p->name + "pitimer"), rtc(p->name + ".rtc", p) { pioSize = 0x100; @@ -486,19 +114,19 @@ TsunamiIO::read(PacketPtr pkt) pkt->set(0x00); break; case TSDEV_TMR0_DATA: - pkt->set(pitimer.counter0.read()); + pkt->set(pitimer.readCounter(0)); break; case TSDEV_TMR1_DATA: - pkt->set(pitimer.counter1.read()); + pkt->set(pitimer.readCounter(1)); break; case TSDEV_TMR2_DATA: - pkt->set(pitimer.counter2.read()); + pkt->set(pitimer.readCounter(2)); break; case TSDEV_RTC_DATA: - pkt->set(rtc.readData()); + pkt->set(rtc.readData(rtcAddr)); break; case TSDEV_CTRL_PORTB: - if (pitimer.counter2.outputHigh()) + if (pitimer.outputHigh(2)) pkt->set(PORTB_SPKR_HIGH); else pkt->set(0x00); @@ -561,22 +189,22 @@ TsunamiIO::write(PacketPtr pkt) mode2 = pkt->get<uint8_t>(); break; case TSDEV_TMR0_DATA: - pitimer.counter0.write(pkt->get<uint8_t>()); + pitimer.writeCounter(0, pkt->get<uint8_t>()); break; case TSDEV_TMR1_DATA: - pitimer.counter1.write(pkt->get<uint8_t>()); + pitimer.writeCounter(1, pkt->get<uint8_t>()); break; case TSDEV_TMR2_DATA: - pitimer.counter2.write(pkt->get<uint8_t>()); + pitimer.writeCounter(2, pkt->get<uint8_t>()); break; case TSDEV_TMR_CTRL: pitimer.writeControl(pkt->get<uint8_t>()); break; case TSDEV_RTC_ADDR: - rtc.writeAddr(pkt->get<uint8_t>()); + rtcAddr = pkt->get<uint8_t>(); break; case TSDEV_RTC_DATA: - rtc.writeData(pkt->get<uint8_t>()); + rtc.writeData(rtcAddr, pkt->get<uint8_t>()); break; case TSDEV_KBD: case TSDEV_DMA1_CMND: @@ -623,6 +251,7 @@ TsunamiIO::clearPIC(uint8_t bitvector) void TsunamiIO::serialize(ostream &os) { + SERIALIZE_SCALAR(rtcAddr); SERIALIZE_SCALAR(timerData); SERIALIZE_SCALAR(mask1); SERIALIZE_SCALAR(mask2); @@ -639,6 +268,7 @@ TsunamiIO::serialize(ostream &os) void TsunamiIO::unserialize(Checkpoint *cp, const string §ion) { + UNSERIALIZE_SCALAR(rtcAddr); UNSERIALIZE_SCALAR(timerData); UNSERIALIZE_SCALAR(mask1); UNSERIALIZE_SCALAR(mask2); diff --git a/src/dev/alpha/tsunami_io.hh b/src/dev/alpha/tsunami_io.hh index 05c4ee910..b6d63322b 100644 --- a/src/dev/alpha/tsunami_io.hh +++ b/src/dev/alpha/tsunami_io.hh @@ -39,6 +39,8 @@ #include "base/range.hh" #include "dev/alpha/tsunami.hh" +#include "dev/intel_8254_timer.hh" +#include "dev/mc146818.hh" #include "dev/io_device.hh" #include "params/TsunamiIO.hh" #include "sim/eventq.hh" @@ -53,223 +55,19 @@ class TsunamiIO : public BasicPioDevice struct tm tm; protected: - /** Real-Time Clock (MC146818) */ - class RTC - { - private: - /** Event for RTC periodic interrupt */ - struct RTCEvent : public Event - { - /** A pointer back to tsunami to create interrupt the processor. */ - Tsunami* tsunami; - Tick interval; - - RTCEvent(Tsunami* t, Tick i); - - /** Schedule the RTC periodic interrupt */ - void scheduleIntr(); - - /** Event process to occur at interrupt*/ - virtual void process(); - - /** Event description */ - virtual const char *description() const; - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - /** RTC periodic interrupt event */ - RTCEvent event; - - /** Current RTC register address/index */ - int addr; - - /** Data for real-time clock function */ - union { - uint8_t clock_data[10]; - - struct { - uint8_t sec; - uint8_t sec_alrm; - uint8_t min; - uint8_t min_alrm; - uint8_t hour; - uint8_t hour_alrm; - uint8_t wday; - uint8_t mday; - uint8_t mon; - uint8_t year; - }; - }; - - /** RTC status register A */ - uint8_t stat_regA; - - /** RTC status register B */ - uint8_t stat_regB; - - public: - RTC(const std::string &name, Tsunami* tsunami, - const TsunamiIOParams *params); - - /** RTC address port: write address of RTC RAM data to access */ - void writeAddr(const uint8_t data); - - /** RTC write data */ - void writeData(const uint8_t data); - - /** RTC read data */ - uint8_t readData(); - - /** - * Serialize this object to the given output stream. - * @param base The base name of the counter object. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param base The base name of the counter object. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /** Programmable Interval Timer (Intel 8254) */ - class PITimer + class RTC : public MC146818 { - /** Counter element for PIT */ - class Counter - { - /** Event for counter interrupt */ - class CounterEvent : public Event - { - private: - /** Pointer back to Counter */ - Counter* counter; - Tick interval; - - public: - CounterEvent(Counter*); - - /** Event process */ - virtual void process(); - - /** Event description */ - virtual const char *description() const; - - friend class Counter; - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - CounterEvent event; - - /** Current count value */ - uint16_t count; - - /** Latched count */ - uint16_t latched_count; - - /** Interrupt period */ - uint16_t period; - - /** Current mode of operation */ - uint8_t mode; - - /** Output goes high when the counter reaches zero */ - bool output_high; - - /** State of the count latch */ - bool latch_on; - - /** Set of values for read_byte and write_byte */ - enum {LSB, MSB}; - - /** Determine which byte of a 16-bit count value to read/write */ - uint8_t read_byte, write_byte; - - public: - Counter(const std::string &name); - - /** Latch the current count (if one is not already latched) */ - void latchCount(); - - /** Set the read/write mode */ - void setRW(int rw_val); - - /** Set operational mode */ - void setMode(int mode_val); - - /** Set count encoding */ - void setBCD(int bcd_val); - - /** Read a count byte */ - uint8_t read(); - - /** Write a count byte */ - void write(const uint8_t data); - - /** Is the output high? */ - bool outputHigh(); - - /** - * Serialize this object to the given output stream. - * @param base The base name of the counter object. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param base The base name of the counter object. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - /** PIT has three seperate counters */ - Counter *counter[3]; - public: - /** Public way to access individual counters (avoid array accesses) */ - Counter counter0; - Counter counter1; - Counter counter2; - - PITimer(const std::string &name); - - /** Write control word */ - void writeControl(const uint8_t data); + Tsunami *tsunami; + RTC(const std::string &n, const TsunamiIOParams *p); - /** - * Serialize this object to the given output stream. - * @param base The base name of the counter object. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param base The base name of the counter object. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); + protected: + void handleEvent() + { + //Actually interrupt the processor here + tsunami->cchip->postRTC(); + } }; /** Mask of the PIC1 */ @@ -294,10 +92,12 @@ class TsunamiIO : public BasicPioDevice Tsunami *tsunami; /** Intel 8253 Periodic Interval Timer */ - PITimer pitimer; + Intel8254Timer pitimer; RTC rtc; + uint8_t rtcAddr; + /** The interval is set via two writes to the PIT. * This variable contains a flag as to how many writes have happened, and * the time so far. diff --git a/src/dev/alpha/tsunami_pchip.cc b/src/dev/alpha/tsunami_pchip.cc index 83bcf8e65..4df7d1150 100644 --- a/src/dev/alpha/tsunami_pchip.cc +++ b/src/dev/alpha/tsunami_pchip.cc @@ -300,6 +300,7 @@ TsunamiPChip::translatePciToDma(Addr busAddr) // if no match was found, then return the original address return busAddr; } + Addr TsunamiPChip::calcConfigAddr(int bus, int dev, int func) { @@ -310,7 +311,17 @@ TsunamiPChip::calcConfigAddr(int bus, int dev, int func) return TsunamiPciBus0Config | (func << 8) | (dev << 11); } +Addr +TsunamiPChip::calcIOAddr(Addr addr) +{ + return TSUNAMI_PCI0_IO + addr; +} +Addr +TsunamiPChip::calcMemAddr(Addr addr) +{ + return TSUNAMI_PCI0_MEMORY + addr; +} void TsunamiPChip::serialize(std::ostream &os) diff --git a/src/dev/alpha/tsunami_pchip.hh b/src/dev/alpha/tsunami_pchip.hh index 53050565f..d31a28dbe 100644 --- a/src/dev/alpha/tsunami_pchip.hh +++ b/src/dev/alpha/tsunami_pchip.hh @@ -84,6 +84,8 @@ class TsunamiPChip : public BasicPioDevice Addr translatePciToDma(Addr busAddr); Addr calcConfigAddr(int bus, int dev, int func); + Addr calcIOAddr(Addr addr); + Addr calcMemAddr(Addr addr); virtual Tick read(PacketPtr pkt); virtual Tick write(PacketPtr pkt); diff --git a/src/dev/copy_engine.cc b/src/dev/copy_engine.cc new file mode 100644 index 000000000..3c759ac1d --- /dev/null +++ b/src/dev/copy_engine.cc @@ -0,0 +1,764 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/* @file + * Device model for Intel's I/O AT DMA copy engine. + */ + +#include <algorithm> + +#include "base/cp_annotate.hh" +#include "base/trace.hh" +#include "dev/copy_engine.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" +#include "params/CopyEngine.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +using namespace CopyEngineReg; +using namespace std; + +CopyEngine::CopyEngine(const Params *p) + : PciDev(p) +{ + // All Reg regs are initialized to 0 by default + regs.chanCount = p->ChanCnt; + regs.xferCap = findMsbSet(p->XferCap); + regs.attnStatus = 0; + + if (regs.chanCount > 64) + fatal("CopyEngine interface doesn't support more than 64 DMA engines\n"); + + for (int x = 0; x < regs.chanCount; x++) { + CopyEngineChannel *ch = new CopyEngineChannel(this, x); + chan.push_back(ch); + } +} + + +CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid) + : ce(_ce), channelId(cid), busy(false), underReset(false), + refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin), + latAfterCompletion(ce->params()->latAfterCompletion), + completionDataReg(0), nextState(Idle), drainEvent(NULL), + fetchCompleteEvent(this), addrCompleteEvent(this), + readCompleteEvent(this), writeCompleteEvent(this), + statusCompleteEvent(this) + +{ + cr.status.dma_transfer_status(3); + cr.descChainAddr = 0; + cr.completionAddr = 0; + + curDmaDesc = new DmaDesc; + memset(curDmaDesc, 0, sizeof(DmaDesc)); + copyBuffer = new uint8_t[ce->params()->XferCap]; +} + +CopyEngine::~CopyEngine() +{ + for (int x = 0; x < chan.size(); x++) { + delete chan[x]; + } +} + +CopyEngine::CopyEngineChannel::~CopyEngineChannel() +{ + delete curDmaDesc; + delete [] copyBuffer; + delete cePort; +} + +void +CopyEngine::init() +{ + PciDev::init(); + for (int x = 0; x < chan.size(); x++) + chan[x]->init(); +} + +void +CopyEngine::CopyEngineChannel::init() +{ + Port *peer; + + cePort = new DmaPort(ce, ce->sys); + peer = ce->dmaPort->getPeer()->getOwner()->getPort(""); + peer->setPeer(cePort); + cePort->setPeer(peer); +} + +void +CopyEngine::CopyEngineChannel::recvCommand() +{ + if (cr.command.start_dma()) { + assert(!busy); + cr.status.dma_transfer_status(0); + nextState = DescriptorFetch; + fetchAddress = cr.descChainAddr; + if (ce->getState() == SimObject::Running) + fetchDescriptor(cr.descChainAddr); + } else if (cr.command.append_dma()) { + if (!busy) { + nextState = AddressFetch; + if (ce->getState() == SimObject::Running) + fetchNextAddr(lastDescriptorAddr); + } else + refreshNext = true; + } else if (cr.command.reset_dma()) { + if (busy) + underReset = true; + else { + cr.status.dma_transfer_status(3); + nextState = Idle; + } + } else if (cr.command.resume_dma() || cr.command.abort_dma() || + cr.command.suspend_dma()) + panic("Resume, Abort, and Suspend are not supported\n"); + cr.command(0); +} + +Tick +CopyEngine::read(PacketPtr pkt) +{ + int bar; + Addr daddr; + + if (!getBAR(pkt->getAddr(), bar, daddr)) + panic("Invalid PCI memory access to unmapped memory.\n"); + + // Only Memory register BAR is allowed + assert(bar == 0); + + int size = pkt->getSize(); + if (size != sizeof(uint64_t) && size != sizeof(uint32_t) && + size != sizeof(uint16_t) && size != sizeof(uint8_t)) { + panic("Unknown size for MMIO access: %d\n", pkt->getSize()); + } + + DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size); + + pkt->allocate(); + + /// + /// Handle read of register here + /// + + if (daddr < 0x80) { + switch (daddr) { + case GEN_CHANCOUNT: + assert(size == sizeof(regs.chanCount)); + pkt->set<uint8_t>(regs.chanCount); + break; + case GEN_XFERCAP: + assert(size == sizeof(regs.xferCap)); + pkt->set<uint8_t>(regs.xferCap); + break; + case GEN_INTRCTRL: + assert(size == sizeof(uint8_t)); + pkt->set<uint8_t>(regs.intrctrl()); + regs.intrctrl.master_int_enable(0); + break; + case GEN_ATTNSTATUS: + assert(size == sizeof(regs.attnStatus)); + pkt->set<uint32_t>(regs.attnStatus); + regs.attnStatus = 0; + break; + default: + panic("Read request to unknown register number: %#x\n", daddr); + } + pkt->makeAtomicResponse(); + return pioDelay; + } + + + // Find which channel we're accessing + int chanid = 0; + daddr -= 0x80; + while (daddr >= 0x80) { + chanid++; + daddr -= 0x80; + } + + if (chanid >= regs.chanCount) + panic("Access to channel %d (device only configured for %d channels)", + chanid, regs.chanCount); + + /// + /// Channel registers are handled here + /// + chan[chanid]->channelRead(pkt, daddr, size); + + pkt->makeAtomicResponse(); + return pioDelay; +} + +void +CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size) +{ + switch (daddr) { + case CHAN_CONTROL: + assert(size == sizeof(uint16_t)); + pkt->set<uint16_t>(cr.ctrl()); + cr.ctrl.in_use(1); + break; + case CHAN_STATUS: + assert(size == sizeof(uint64_t)); + pkt->set<uint64_t>(cr.status() | ~busy); + break; + case CHAN_CHAINADDR: + assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); + if (size == sizeof(uint64_t)) + pkt->set<uint64_t>(cr.descChainAddr); + else + pkt->set<uint32_t>(bits(cr.descChainAddr,0,31)); + break; + case CHAN_CHAINADDR_HIGH: + assert(size == sizeof(uint32_t)); + pkt->set<uint32_t>(bits(cr.descChainAddr,32,63)); + break; + case CHAN_COMMAND: + assert(size == sizeof(uint8_t)); + pkt->set<uint32_t>(cr.command()); + break; + case CHAN_CMPLNADDR: + assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); + if (size == sizeof(uint64_t)) + pkt->set<uint64_t>(cr.completionAddr); + else + pkt->set<uint32_t>(bits(cr.completionAddr,0,31)); + break; + case CHAN_CMPLNADDR_HIGH: + assert(size == sizeof(uint32_t)); + pkt->set<uint32_t>(bits(cr.completionAddr,32,63)); + break; + case CHAN_ERROR: + assert(size == sizeof(uint32_t)); + pkt->set<uint32_t>(cr.error()); + break; + default: + panic("Read request to unknown channel register number: (%d)%#x\n", + channelId, daddr); + } +} + + +Tick +CopyEngine::write(PacketPtr pkt) +{ + int bar; + Addr daddr; + + + if (!getBAR(pkt->getAddr(), bar, daddr)) + panic("Invalid PCI memory access to unmapped memory.\n"); + + // Only Memory register BAR is allowed + assert(bar == 0); + + int size = pkt->getSize(); + + /// + /// Handle write of register here + /// + + if (size == sizeof(uint64_t)) { + uint64_t val M5_VAR_USED = pkt->get<uint64_t>(); + DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); + } else if (size == sizeof(uint32_t)) { + uint32_t val M5_VAR_USED = pkt->get<uint32_t>(); + DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); + } else if (size == sizeof(uint16_t)) { + uint16_t val M5_VAR_USED = pkt->get<uint16_t>(); + DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); + } else if (size == sizeof(uint8_t)) { + uint8_t val M5_VAR_USED = pkt->get<uint8_t>(); + DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val); + } else { + panic("Unknown size for MMIO access: %d\n", size); + } + + if (daddr < 0x80) { + switch (daddr) { + case GEN_CHANCOUNT: + case GEN_XFERCAP: + case GEN_ATTNSTATUS: + DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", + daddr); + break; + case GEN_INTRCTRL: + regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1)); + break; + default: + panic("Read request to unknown register number: %#x\n", daddr); + } + pkt->makeAtomicResponse(); + return pioDelay; + } + + // Find which channel we're accessing + int chanid = 0; + daddr -= 0x80; + while (daddr >= 0x80) { + chanid++; + daddr -= 0x80; + } + + if (chanid >= regs.chanCount) + panic("Access to channel %d (device only configured for %d channels)", + chanid, regs.chanCount); + + /// + /// Channel registers are handled here + /// + chan[chanid]->channelWrite(pkt, daddr, size); + + pkt->makeAtomicResponse(); + return pioDelay; +} + +void +CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size) +{ + switch (daddr) { + case CHAN_CONTROL: + assert(size == sizeof(uint16_t)); + int old_int_disable; + old_int_disable = cr.ctrl.interrupt_disable(); + cr.ctrl(pkt->get<uint16_t>()); + if (cr.ctrl.interrupt_disable()) + cr.ctrl.interrupt_disable(0); + else + cr.ctrl.interrupt_disable(old_int_disable); + break; + case CHAN_STATUS: + assert(size == sizeof(uint64_t)); + DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n", + daddr); + break; + case CHAN_CHAINADDR: + assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); + if (size == sizeof(uint64_t)) + cr.descChainAddr = pkt->get<uint64_t>(); + else + cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() | + (cr.descChainAddr & ~mask(32)); + DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); + break; + case CHAN_CHAINADDR_HIGH: + assert(size == sizeof(uint32_t)); + cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | + (cr.descChainAddr & mask(32)); + DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr); + break; + case CHAN_COMMAND: + assert(size == sizeof(uint8_t)); + cr.command(pkt->get<uint8_t>()); + recvCommand(); + break; + case CHAN_CMPLNADDR: + assert(size == sizeof(uint64_t) || size == sizeof(uint32_t)); + if (size == sizeof(uint64_t)) + cr.completionAddr = pkt->get<uint64_t>(); + else + cr.completionAddr = pkt->get<uint32_t>() | + (cr.completionAddr & ~mask(32)); + break; + case CHAN_CMPLNADDR_HIGH: + assert(size == sizeof(uint32_t)); + cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) | + (cr.completionAddr & mask(32)); + break; + case CHAN_ERROR: + assert(size == sizeof(uint32_t)); + cr.error(~pkt->get<uint32_t>() & cr.error()); + break; + default: + panic("Read request to unknown channel register number: (%d)%#x\n", + channelId, daddr); + } +} + +void +CopyEngine::regStats() +{ + using namespace Stats; + bytesCopied + .init(regs.chanCount) + .name(name() + ".bytes_copied") + .desc("Number of bytes copied by each engine") + .flags(total) + ; + copiesProcessed + .init(regs.chanCount) + .name(name() + ".copies_processed") + .desc("Number of copies processed by each engine") + .flags(total) + ; +} + +void +CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address) +{ + anDq(); + anBegin("FetchDescriptor"); + DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n", + address, ce->platform->pciToDma(address)); + assert(address); + busy = true; + + DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n", + ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc); + + cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address), + sizeof(DmaDesc), &fetchCompleteEvent, (uint8_t*)curDmaDesc, + latBeforeBegin); + lastDescriptorAddr = address; +} + +void +CopyEngine::CopyEngineChannel::fetchDescComplete() +{ + DPRINTF(DMACopyEngine, "Read of descriptor complete\n"); + + if ((curDmaDesc->command & DESC_CTRL_NULL)) { + DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n"); + assert(!(curDmaDesc->command & DESC_CTRL_CP_STS)); + if (curDmaDesc->command & DESC_CTRL_CP_STS) { + panic("Shouldn't be able to get here\n"); + nextState = CompletionWrite; + if (inDrain()) return; + writeCompletionStatus(); + } else { + anBegin("Idle"); + anWait(); + busy = false; + nextState = Idle; + inDrain(); + } + return; + } + + if (curDmaDesc->command & ~DESC_CTRL_CP_STS) + panic("Descriptor has flag other that completion status set\n"); + + nextState = DMARead; + if (inDrain()) return; + readCopyBytes(); +} + +void +CopyEngine::CopyEngineChannel::readCopyBytes() +{ + anBegin("ReadCopyBytes"); + DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n", + curDmaDesc->len, curDmaDesc->dest, + ce->platform->pciToDma(curDmaDesc->src)); + cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src), + curDmaDesc->len, &readCompleteEvent, copyBuffer, 0); +} + +void +CopyEngine::CopyEngineChannel::readCopyBytesComplete() +{ + DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n"); + + nextState = DMAWrite; + if (inDrain()) return; + writeCopyBytes(); +} + +void +CopyEngine::CopyEngineChannel::writeCopyBytes() +{ + anBegin("WriteCopyBytes"); + DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n", + curDmaDesc->len, curDmaDesc->dest, + ce->platform->pciToDma(curDmaDesc->dest)); + + cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest), + curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0); + + ce->bytesCopied[channelId] += curDmaDesc->len; + ce->copiesProcessed[channelId]++; +} + +void +CopyEngine::CopyEngineChannel::writeCopyBytesComplete() +{ + DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n", + curDmaDesc->user1); + + cr.status.compl_desc_addr(lastDescriptorAddr >> 6); + completionDataReg = cr.status() | 1; + + anQ("DMAUsedDescQ", channelId, 1); + anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len); + if (curDmaDesc->command & DESC_CTRL_CP_STS) { + nextState = CompletionWrite; + if (inDrain()) return; + writeCompletionStatus(); + return; + } + + continueProcessing(); +} + +void +CopyEngine::CopyEngineChannel::continueProcessing() +{ + busy = false; + + if (underReset) { + anBegin("Reset"); + anWait(); + underReset = false; + refreshNext = false; + busy = false; + nextState = Idle; + return; + } + + if (curDmaDesc->next) { + nextState = DescriptorFetch; + fetchAddress = curDmaDesc->next; + if (inDrain()) return; + fetchDescriptor(curDmaDesc->next); + } else if (refreshNext) { + nextState = AddressFetch; + refreshNext = false; + if (inDrain()) return; + fetchNextAddr(lastDescriptorAddr); + } else { + inDrain(); + nextState = Idle; + anWait(); + anBegin("Idle"); + } +} + +void +CopyEngine::CopyEngineChannel::writeCompletionStatus() +{ + anBegin("WriteCompletionStatus"); + DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n", + completionDataReg, cr.completionAddr, + ce->platform->pciToDma(cr.completionAddr)); + + cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(cr.completionAddr), + sizeof(completionDataReg), &statusCompleteEvent, + (uint8_t*)&completionDataReg, latAfterCompletion); +} + +void +CopyEngine::CopyEngineChannel::writeStatusComplete() +{ + DPRINTF(DMACopyEngine, "Writing completion status complete\n"); + continueProcessing(); +} + +void +CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address) +{ + anBegin("FetchNextAddr"); + DPRINTF(DMACopyEngine, "Fetching next address...\n"); + busy = true; + cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address + + offsetof(DmaDesc, next)), sizeof(Addr), &addrCompleteEvent, + (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0); +} + +void +CopyEngine::CopyEngineChannel::fetchAddrComplete() +{ + DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n", + curDmaDesc->next); + if (!curDmaDesc->next) { + DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n"); + busy = false; + nextState = Idle; + anWait(); + anBegin("Idle"); + inDrain(); + return; + } + nextState = DescriptorFetch; + fetchAddress = curDmaDesc->next; + if (inDrain()) return; + fetchDescriptor(curDmaDesc->next); +} + +bool +CopyEngine::CopyEngineChannel::inDrain() +{ + if (ce->getState() == SimObject::Draining) { + DPRINTF(DMACopyEngine, "processing drain\n"); + assert(drainEvent); + drainEvent->process(); + drainEvent = NULL; + } + + return ce->getState() != SimObject::Running; +} + +unsigned int +CopyEngine::CopyEngineChannel::drain(Event *de) +{ + if (nextState == Idle || ce->getState() != SimObject::Running) + return 0; + unsigned int count = 1; + count += cePort->drain(de); + + DPRINTF(DMACopyEngine, "unable to drain, returning %d\n", count); + drainEvent = de; + return count; +} + +unsigned int +CopyEngine::drain(Event *de) +{ + unsigned int count; + count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); + for (int x = 0;x < chan.size(); x++) + count += chan[x]->drain(de); + + if (count) + changeState(Draining); + else + changeState(Drained); + + DPRINTF(DMACopyEngine, "call to CopyEngine::drain() returning %d\n", count); + return count; +} + +void +CopyEngine::serialize(std::ostream &os) +{ + PciDev::serialize(os); + regs.serialize(os); + for (int x =0; x < chan.size(); x++) { + nameOut(os, csprintf("%s.channel%d", name(), x)); + chan[x]->serialize(os); + } +} + +void +CopyEngine::unserialize(Checkpoint *cp, const std::string §ion) +{ + PciDev::unserialize(cp, section); + regs.unserialize(cp, section); + for (int x = 0; x < chan.size(); x++) + chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x)); +} + +void +CopyEngine::CopyEngineChannel::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(channelId); + SERIALIZE_SCALAR(busy); + SERIALIZE_SCALAR(underReset); + SERIALIZE_SCALAR(refreshNext); + SERIALIZE_SCALAR(lastDescriptorAddr); + SERIALIZE_SCALAR(completionDataReg); + SERIALIZE_SCALAR(fetchAddress); + int nextState = this->nextState; + SERIALIZE_SCALAR(nextState); + arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); + SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); + cr.serialize(os); + +} +void +CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(channelId); + UNSERIALIZE_SCALAR(busy); + UNSERIALIZE_SCALAR(underReset); + UNSERIALIZE_SCALAR(refreshNext); + UNSERIALIZE_SCALAR(lastDescriptorAddr); + UNSERIALIZE_SCALAR(completionDataReg); + UNSERIALIZE_SCALAR(fetchAddress); + int nextState; + UNSERIALIZE_SCALAR(nextState); + this->nextState = (ChannelState)nextState; + arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc)); + UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap); + cr.unserialize(cp, section); + +} + +void +CopyEngine::CopyEngineChannel::restartStateMachine() +{ + switch(nextState) { + case AddressFetch: + fetchNextAddr(lastDescriptorAddr); + break; + case DescriptorFetch: + fetchDescriptor(fetchAddress); + break; + case DMARead: + readCopyBytes(); + break; + case DMAWrite: + writeCopyBytes(); + break; + case CompletionWrite: + writeCompletionStatus(); + break; + case Idle: + break; + default: + panic("Unknown state for CopyEngineChannel\n"); + } +} + +void +CopyEngine::resume() +{ + SimObject::resume(); + for (int x = 0;x < chan.size(); x++) + chan[x]->resume(); +} + + +void +CopyEngine::CopyEngineChannel::resume() +{ + DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState); + restartStateMachine(); +} + +CopyEngine * +CopyEngineParams::create() +{ + return new CopyEngine(this); +} diff --git a/src/dev/copy_engine.hh b/src/dev/copy_engine.hh new file mode 100644 index 000000000..dfe469588 --- /dev/null +++ b/src/dev/copy_engine.hh @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/* @file + * Device model for Intel's I/O Acceleration Technology (I/OAT). + * A DMA asyncronous copy engine + */ + +#ifndef __DEV_COPY_ENGINE_HH__ +#define __DEV_COPY_ENGINE_HH__ + +#include <vector> + +#include "base/statistics.hh" +#include "dev/copy_engine_defs.hh" +#include "dev/pcidev.hh" +#include "params/CopyEngine.hh" +#include "sim/eventq.hh" + +class CopyEngine : public PciDev +{ + class CopyEngineChannel + { + private: + DmaPort *cePort; + CopyEngine *ce; + CopyEngineReg::ChanRegs cr; + int channelId; + CopyEngineReg::DmaDesc *curDmaDesc; + uint8_t *copyBuffer; + + bool busy; + bool underReset; + bool refreshNext; + Addr lastDescriptorAddr; + Addr fetchAddress; + + Tick latBeforeBegin; + Tick latAfterCompletion; + + uint64_t completionDataReg; + + enum ChannelState { + Idle, + AddressFetch, + DescriptorFetch, + DMARead, + DMAWrite, + CompletionWrite + }; + + ChannelState nextState; + + Event *drainEvent; + public: + CopyEngineChannel(CopyEngine *_ce, int cid); + virtual ~CopyEngineChannel(); + void init(); + + std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); } + virtual void addressRanges(AddrRangeList &range_list) { range_list.clear(); } + virtual Tick read(PacketPtr pkt) + { panic("CopyEngineChannel has no I/O access\n");} + virtual Tick write(PacketPtr pkt) + { panic("CopyEngineChannel has no I/O access\n"); } + + void channelRead(PacketPtr pkt, Addr daddr, int size); + void channelWrite(PacketPtr pkt, Addr daddr, int size); + + unsigned int drain(Event *de); + void resume(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + private: + void fetchDescriptor(Addr address); + void fetchDescComplete(); + EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchDescComplete> + fetchCompleteEvent; + + void fetchNextAddr(Addr address); + void fetchAddrComplete(); + EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchAddrComplete> + addrCompleteEvent; + + void readCopyBytes(); + void readCopyBytesComplete(); + EventWrapper<CopyEngineChannel, &CopyEngineChannel::readCopyBytesComplete> + readCompleteEvent; + + void writeCopyBytes(); + void writeCopyBytesComplete(); + EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeCopyBytesComplete> + writeCompleteEvent; + + void writeCompletionStatus(); + void writeStatusComplete(); + EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeStatusComplete> + statusCompleteEvent; + + + void continueProcessing(); + void recvCommand(); + bool inDrain(); + void restartStateMachine(); + inline void anBegin(const char *s) + { + CPA::cpa()->hwBegin(CPA::FL_NONE, ce->sys, + channelId, "CopyEngine", s); + } + + inline void anWait() + { + CPA::cpa()->hwWe(CPA::FL_NONE, ce->sys, + channelId, "CopyEngine", "DMAUnusedDescQ", channelId); + } + + inline void anDq() + { + CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys, + channelId, "CopyEngine", "DMAUnusedDescQ", channelId); + } + + inline void anPq() + { + CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys, + channelId, "CopyEngine", "DMAUnusedDescQ", channelId); + } + + inline void anQ(const char * s, uint64_t id, int size = 1) + { + CPA::cpa()->hwQ(CPA::FL_NONE, ce->sys, channelId, + "CopyEngine", s, id, NULL, size); + } + + }; + + private: + + Stats::Vector bytesCopied; + Stats::Vector copiesProcessed; + + // device registers + CopyEngineReg::Regs regs; + + // Array of channels each one with regs/dma port/etc + std::vector<CopyEngineChannel*> chan; + + public: + typedef CopyEngineParams Params; + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + CopyEngine(const Params *params); + ~CopyEngine(); + + void regStats(); + void init(); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + virtual unsigned int drain(Event *de); + virtual void resume(); +}; + +#endif //__DEV_COPY_ENGINE_HH__ + diff --git a/src/dev/copy_engine_defs.hh b/src/dev/copy_engine_defs.hh new file mode 100644 index 000000000..16bf57d58 --- /dev/null +++ b/src/dev/copy_engine_defs.hh @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/* @file + * Register and structure descriptions for Intel's I/O AT DMA Engine + */ +#include "base/bitfield.hh" +#include "sim/serialize.hh" + +namespace CopyEngineReg { + + +// General Channel independant registers, 128 bytes starting at 0x00 +const uint32_t GEN_CHANCOUNT = 0x00; +const uint32_t GEN_XFERCAP = 0x01; +const uint32_t GEN_INTRCTRL = 0x03; +const uint32_t GEN_ATTNSTATUS = 0x04; + + +// Channel specific registers, each block is 128 bytes, starting at 0x80 +const uint32_t CHAN_CONTROL = 0x00; +const uint32_t CHAN_STATUS = 0x04; +const uint32_t CHAN_CHAINADDR = 0x0C; +const uint32_t CHAN_CHAINADDR_LOW = 0x0C; +const uint32_t CHAN_CHAINADDR_HIGH = 0x10; +const uint32_t CHAN_COMMAND = 0x14; +const uint32_t CHAN_CMPLNADDR = 0x18; +const uint32_t CHAN_CMPLNADDR_LOW = 0x18; +const uint32_t CHAN_CMPLNADDR_HIGH = 0x1C; +const uint32_t CHAN_ERROR = 0x28; + + +const uint32_t DESC_CTRL_INT_GEN = 0x00000001; +const uint32_t DESC_CTRL_SRC_SN = 0x00000002; +const uint32_t DESC_CTRL_DST_SN = 0x00000004; +const uint32_t DESC_CTRL_CP_STS = 0x00000008; +const uint32_t DESC_CTRL_FRAME = 0x00000010; +const uint32_t DESC_CTRL_NULL = 0x00000020; + +struct DmaDesc { + uint32_t len; + uint32_t command; + Addr src; + Addr dest; + Addr next; + uint64_t reserved1; + uint64_t reserved2; + uint64_t user1; + uint64_t user2; +}; + +#define ADD_FIELD8(NAME, OFFSET, BITS) \ + inline uint8_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint8_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +#define ADD_FIELD16(NAME, OFFSET, BITS) \ + inline uint16_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint16_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +#define ADD_FIELD32(NAME, OFFSET, BITS) \ + inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +#define ADD_FIELD64(NAME, OFFSET, BITS) \ + inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +template<class T> +struct Reg { + T _data; + T operator()() { return _data; } + const Reg<T> &operator=(T d) { _data = d; return *this;} + bool operator==(T d) { return d == _data; } + void operator()(T d) { _data = d; } + Reg() { _data = 0; } + void serialize(std::ostream &os) + { + SERIALIZE_SCALAR(_data); + } + void unserialize(Checkpoint *cp, const std::string §ion) + { + UNSERIALIZE_SCALAR(_data); + } +}; + + +struct Regs { + uint8_t chanCount; + uint8_t xferCap; + + struct INTRCTRL : public Reg<uint8_t> { // 0x03 + using Reg<uint8_t>::operator =; + ADD_FIELD8(master_int_enable,0,1); + ADD_FIELD8(interrupt_status,1,1); + ADD_FIELD8(interrupt,2,1); + }; + INTRCTRL intrctrl; + + uint32_t attnStatus; // Read clears + + void serialize(std::ostream &os) + { + SERIALIZE_SCALAR(chanCount); + SERIALIZE_SCALAR(xferCap); + paramOut(os, "intrctrl", intrctrl._data); + SERIALIZE_SCALAR(attnStatus); + } + + void unserialize(Checkpoint *cp, const std::string §ion) + { + UNSERIALIZE_SCALAR(chanCount); + UNSERIALIZE_SCALAR(xferCap); + paramIn(cp, section, "intrctrl", intrctrl._data); + UNSERIALIZE_SCALAR(attnStatus); + } + +}; + +struct ChanRegs { + struct CHANCTRL : public Reg<uint16_t> { // channelX + 0x00 + using Reg<uint16_t>::operator =; + ADD_FIELD16(interrupt_disable,0,1); + ADD_FIELD16(error_completion_enable, 2,1); + ADD_FIELD16(any_error_abort_enable,3,1); + ADD_FIELD16(error_int_enable,4,1); + ADD_FIELD16(desc_addr_snoop_control,5,1); + ADD_FIELD16(in_use, 8,1); + }; + CHANCTRL ctrl; + + struct CHANSTS : public Reg<uint64_t> { // channelX + 0x04 + ADD_FIELD64(dma_transfer_status, 0, 3); + ADD_FIELD64(unaffiliated_error, 3, 1); + ADD_FIELD64(soft_error, 4, 1); + ADD_FIELD64(compl_desc_addr, 6, 58); + }; + CHANSTS status; + + uint64_t descChainAddr; + + struct CHANCMD : public Reg<uint8_t> { // channelX + 0x14 + ADD_FIELD8(start_dma,0,1); + ADD_FIELD8(append_dma,1,1); + ADD_FIELD8(suspend_dma,2,1); + ADD_FIELD8(abort_dma,3,1); + ADD_FIELD8(resume_dma,4,1); + ADD_FIELD8(reset_dma,5,1); + }; + CHANCMD command; + + uint64_t completionAddr; + + struct CHANERR : public Reg<uint32_t> { // channel X + 0x28 + ADD_FIELD32(source_addr_error,0,1); + ADD_FIELD32(dest_addr_error,1,1); + ADD_FIELD32(ndesc_addr_error,2,1); + ADD_FIELD32(desc_error,3,1); + ADD_FIELD32(chain_addr_error,4,1); + ADD_FIELD32(chain_cmd_error,5,1); + ADD_FIELD32(chipset_parity_error,6,1); + ADD_FIELD32(dma_parity_error,7,1); + ADD_FIELD32(read_data_error,8,1); + ADD_FIELD32(write_data_error,9,1); + ADD_FIELD32(desc_control_error,10,1); + ADD_FIELD32(desc_len_error,11,1); + ADD_FIELD32(completion_addr_error,12,1); + ADD_FIELD32(interrupt_config_error,13,1); + ADD_FIELD32(soft_error,14,1); + ADD_FIELD32(unaffiliated_error,15,1); + }; + CHANERR error; + + void serialize(std::ostream &os) + { + paramOut(os, "ctrl", ctrl._data); + paramOut(os, "status", status._data); + SERIALIZE_SCALAR(descChainAddr); + paramOut(os, "command", command._data); + SERIALIZE_SCALAR(completionAddr); + paramOut(os, "error", error._data); + } + + void unserialize(Checkpoint *cp, const std::string §ion) + { + paramIn(cp, section, "ctrl", ctrl._data); + paramIn(cp, section, "status", status._data); + UNSERIALIZE_SCALAR(descChainAddr); + paramIn(cp, section, "command", command._data); + UNSERIALIZE_SCALAR(completionAddr); + paramIn(cp, section, "error", error._data); + } + + +}; + +} //namespace CopyEngineReg + + diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc index 2316bfed9..063a594e7 100644 --- a/src/dev/etherbus.cc +++ b/src/dev/etherbus.cc @@ -49,7 +49,7 @@ using namespace std; EtherBus::EtherBus(const Params *p) : EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback), - event(&mainEventQueue, this), sender(0), dump(p->dump) + event(this), sender(0), dump(p->dump) { } @@ -99,7 +99,7 @@ EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt) int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0); DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", delay, ticksPerByte); - event.schedule(curTick + delay); + schedule(event, curTick + delay); return true; } diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh index 624ceb81a..6408f7f1f 100644 --- a/src/dev/etherbus.hh +++ b/src/dev/etherbus.hh @@ -59,8 +59,7 @@ class EtherBus : public EtherObject EtherBus *bus; public: - DoneEvent(EventQueue *q, EtherBus *b) - : Event(q), bus(b) {} + DoneEvent(EtherBus *b) : bus(b) {} virtual void process() { bus->txDone(); } virtual const char *description() const { return "ethernet bus completion"; } diff --git a/src/dev/etherdevice.cc b/src/dev/etherdevice.cc new file mode 100644 index 000000000..5341c02c4 --- /dev/null +++ b/src/dev/etherdevice.cc @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Lisa Hsu + */ + +#include "dev/etherdevice.hh" +#include "sim/stats.hh" + +void +EtherDevice::regStats() +{ + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + descDmaReads + .name(name() + ".descDMAReads") + .desc("Number of descriptors the device read w/ DMA") + .precision(0) + ; + + descDmaWrites + .name(name() + ".descDMAWrites") + .desc("Number of descriptors the device wrote w/ DMA") + .precision(0) + ; + + descDmaRdBytes + .name(name() + ".descDmaReadBytes") + .desc("number of descriptor bytes read w/ DMA") + .precision(0) + ; + + descDmaWrBytes + .name(name() + ".descDmaWriteBytes") + .desc("number of descriptor bytes write w/ DMA") + .precision(0) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("total number of Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("total number of RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("total number of RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("total number of RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("total number of TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("total number of TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("total number of TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("total number of RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + + totalTxOk + totalTxIdle + totalTxDesc + + totalRxOrn) / postedInterrupts; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh index a0df0d741..5d86275b4 100644 --- a/src/dev/etherdevice.hh +++ b/src/dev/etherdevice.hh @@ -36,6 +36,7 @@ #ifndef __DEV_ETHERDEVICE_HH__ #define __DEV_ETHERDEVICE_HH__ +#include "base/statistics.hh" #include "dev/pcidev.hh" #include "params/EtherDevice.hh" #include "sim/sim_object.hh" @@ -64,6 +65,59 @@ class EtherDevice : public PciDev /** Additional function to return the Port of a memory object. */ virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0; + public: + void regStats(); + + protected: + Stats::Scalar txBytes; + Stats::Scalar rxBytes; + Stats::Scalar txPackets; + Stats::Scalar rxPackets; + Stats::Scalar txIpChecksums; + Stats::Scalar rxIpChecksums; + Stats::Scalar txTcpChecksums; + Stats::Scalar rxTcpChecksums; + Stats::Scalar txUdpChecksums; + Stats::Scalar rxUdpChecksums; + Stats::Scalar descDmaReads; + Stats::Scalar descDmaWrites; + Stats::Scalar descDmaRdBytes; + Stats::Scalar descDmaWrBytes; + Stats::Formula totBandwidth; + Stats::Formula totPackets; + Stats::Formula totBytes; + Stats::Formula totPacketRate; + Stats::Formula txBandwidth; + Stats::Formula rxBandwidth; + Stats::Formula txPacketRate; + Stats::Formula rxPacketRate; + Stats::Scalar postedSwi; + Stats::Formula coalescedSwi; + Stats::Scalar totalSwi; + Stats::Scalar postedRxIdle; + Stats::Formula coalescedRxIdle; + Stats::Scalar totalRxIdle; + Stats::Scalar postedRxOk; + Stats::Formula coalescedRxOk; + Stats::Scalar totalRxOk; + Stats::Scalar postedRxDesc; + Stats::Formula coalescedRxDesc; + Stats::Scalar totalRxDesc; + Stats::Scalar postedTxOk; + Stats::Formula coalescedTxOk; + Stats::Scalar totalTxOk; + Stats::Scalar postedTxIdle; + Stats::Formula coalescedTxIdle; + Stats::Scalar totalTxIdle; + Stats::Scalar postedTxDesc; + Stats::Formula coalescedTxDesc; + Stats::Scalar totalTxDesc; + Stats::Scalar postedRxOrn; + Stats::Formula coalescedRxOrn; + Stats::Scalar totalRxOrn; + Stats::Formula coalescedTotal; + Stats::Scalar postedInterrupts; + Stats::Scalar droppedPackets; }; #endif //__DEV_ETHERDEVICE_HH__ diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc index 471093521..c41ce4e1f 100644 --- a/src/dev/etherdump.cc +++ b/src/dev/etherdump.cc @@ -45,75 +45,62 @@ using std::string; EtherDump::EtherDump(const Params *p) - : SimObject(p), stream(simout.resolve(p->file).c_str()), + : SimObject(p), stream(simout.create(p->file, true)), maxlen(p->maxlen) { } -#define DLT_EN10MB 1 // Ethernet (10Mb) -#define TCPDUMP_MAGIC 0xa1b2c3d4 -#define PCAP_VERSION_MAJOR 2 -#define PCAP_VERSION_MINOR 4 +#define DLT_EN10MB 1 // Ethernet (10Mb) +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 struct pcap_file_header { uint32_t magic; uint16_t version_major; uint16_t version_minor; - int32_t thiszone; // gmt to local correction - uint32_t sigfigs; // accuracy of timestamps - uint32_t snaplen; // max length saved portion of each pkt - uint32_t linktype; // data link type (DLT_*) + int32_t thiszone; // gmt to local correction + uint32_t sigfigs; // accuracy of timestamps + uint32_t snaplen; // max length saved portion of each pkt + uint32_t linktype; // data link type (DLT_*) }; struct pcap_pkthdr { uint32_t seconds; uint32_t microseconds; - uint32_t caplen; // length of portion present - uint32_t len; // length this packet (off wire) + uint32_t caplen; // length of portion present + uint32_t len; // length this packet (off wire) }; void EtherDump::init() { - curtime = time(NULL); struct pcap_file_header hdr; hdr.magic = TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; - hdr.thiszone = -5 * 3600; + hdr.thiszone = 0; hdr.snaplen = 1500; hdr.sigfigs = 0; hdr.linktype = DLT_EN10MB; - stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); - /* - * output an empty packet with the current time so that we know - * when the simulation began. This allows us to correlate packets - * to sim_cycles. - */ - pcap_pkthdr pkthdr; - pkthdr.seconds = curtime; - pkthdr.microseconds = 0; - pkthdr.caplen = 0; - pkthdr.len = 0; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - - stream.flush(); + stream->flush(); } void EtherDump::dumpPacket(EthPacketPtr &packet) { pcap_pkthdr pkthdr; - pkthdr.seconds = curtime + (curTick / Clock::Int::s); + pkthdr.seconds = curTick / Clock::Int::s; pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000); pkthdr.caplen = std::min(packet->length, maxlen); pkthdr.len = packet->length; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); - stream.flush(); + stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); + stream->flush(); } EtherDump * diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh index 1027ce4d0..18a5d2c44 100644 --- a/src/dev/etherdump.hh +++ b/src/dev/etherdump.hh @@ -46,13 +46,11 @@ class EtherDump : public SimObject { private: - std::ofstream stream; + std::ostream *stream; const int maxlen; void dumpPacket(EthPacketPtr &packet); void init(); - Tick curtime; - public: typedef EtherDumpParams Params; EtherDump(const Params *p); diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc index b1266000b..f3f38fc20 100644 --- a/src/dev/etherlink.cc +++ b/src/dev/etherlink.cc @@ -135,7 +135,7 @@ class LinkDelayEvent : public Event public: // non-scheduling version for createForUnserialize() LinkDelayEvent(); - LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when); + LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt); void process(); @@ -153,7 +153,8 @@ EtherLink::Link::txDone() if (linkDelay > 0) { DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); - new LinkDelayEvent(this, packet, curTick + linkDelay); + Event *event = new LinkDelayEvent(this, packet); + parent->schedule(event, curTick + linkDelay); } else { txComplete(packet); } @@ -182,7 +183,7 @@ EtherLink::Link::transmit(EthPacketPtr pkt) DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", delay, ticksPerByte); - doneEvent.schedule(curTick + delay); + parent->schedule(doneEvent, curTick + delay); return true; } @@ -220,23 +221,22 @@ EtherLink::Link::unserialize(const string &base, Checkpoint *cp, if (event_scheduled) { Tick event_time; paramIn(cp, section, base + ".event_time", event_time); - doneEvent.schedule(event_time); + parent->schedule(doneEvent, event_time); } } LinkDelayEvent::LinkDelayEvent() - : Event(&mainEventQueue), link(NULL) + : link(NULL) { setFlags(AutoSerialize); setFlags(AutoDelete); } -LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when) - : Event(&mainEventQueue), link(l), packet(p) +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p) + : link(l), packet(p) { setFlags(AutoSerialize); setFlags(AutoDelete); - schedule(when); } void diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc index 5c552b4bd..2c8343eb0 100644 --- a/src/dev/etherpkt.cc +++ b/src/dev/etherpkt.cc @@ -40,7 +40,6 @@ void EthPacketData::serialize(const string &base, ostream &os) { paramOut(os, base + ".length", length); - paramOut(os, base + ".slack", slack); arrayParamOut(os, base + ".data", data, length); } @@ -49,7 +48,6 @@ EthPacketData::unserialize(const string &base, Checkpoint *cp, const string §ion) { paramIn(cp, section, base + ".length", length); - paramIn(cp, section, base + ".slack", slack); if (length) arrayParamIn(cp, section, base + ".data", data, length); } diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh index db2e0d6b5..623895ba8 100644 --- a/src/dev/etherpkt.hh +++ b/src/dev/etherpkt.hh @@ -60,24 +60,17 @@ class EthPacketData : public RefCounted */ int length; - /* - * Extra space taken up by the packet in whatever data structure - * it is in. - * - * NOTE: This can only be use by *one* data structure at a time! - */ - int slack; - public: - EthPacketData() : data(NULL), length(0), slack(0) + EthPacketData() + : data(NULL), length(0) { } explicit EthPacketData(size_t size) - : data(new uint8_t[size]), length(0), slack(0) + : data(new uint8_t[size]), length(0) { } - EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0) - : data(d.release()), length(l), slack(s) + EthPacketData(std::auto_ptr<uint8_t> d, int l) + : data(d.release()), length(l) { } ~EthPacketData() { if (data) delete [] data; } diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc index 81b84d179..85d6370be 100644 --- a/src/dev/ethertap.cc +++ b/src/dev/ethertap.cc @@ -130,6 +130,9 @@ EtherTap::EtherTap(const Params *p) : EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump), interface(NULL), txEvent(this) { + if (ListenSocket::allDisabled()) + fatal("All listeners are disabled! EtherTap can't work!"); + buffer = new char[buflen]; listener = new TapListener(this, p->port); listener->listen(); @@ -179,8 +182,12 @@ EtherTap::recvPacket(EthPacketPtr packet) DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); DDUMP(EthernetData, packet->data, packet->length); uint32_t len = htonl(packet->length); - write(socket, &len, sizeof(len)); - write(socket, packet->data, packet->length); + ssize_t ret = write(socket, &len, sizeof(len)); + if (ret != sizeof(len)) + return false; + ret = write(socket, packet->data, packet->length); + if (ret != packet->length) + return false; interface->recvDone(); @@ -239,7 +246,7 @@ EtherTap::process(int revent) DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); packetBuffer.push(packet); if (!txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); + schedule(txEvent, curTick + retryTime); } else if (dump) { dump->dump(packet); } @@ -262,7 +269,7 @@ EtherTap::retransmit() } if (!packetBuffer.empty() && !txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); + schedule(txEvent, curTick + retryTime); } EtherInt* diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh index be3d73a24..ac287cecb 100644 --- a/src/dev/ethertap.hh +++ b/src/dev/ethertap.hh @@ -90,8 +90,7 @@ class EtherTap : public EtherObject EtherTap *tap; public: - TxEvent(EtherTap *_tap) - : Event(&mainEventQueue), tap(_tap) {} + TxEvent(EtherTap *_tap) : tap(_tap) {} void process() { tap->retransmit(); } virtual const char *description() const { return "EtherTap retransmit"; } diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 3f56ec53a..274f60e39 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -57,10 +57,15 @@ using namespace Net; IGbE::IGbE(const Params *p) : EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), - txTick(false), txFifoTick(false), rxDmaPacket(false), rdtrEvent(this), radvEvent(this), + txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0), + fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), + fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), + rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), + rdtrEvent(this), radvEvent(this), tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), - txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock) + txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), + clock(p->clock), lastInterrupt(0) { etherInt = new IGbEInt(name() + ".int", this); @@ -80,6 +85,9 @@ IGbE::IGbE(const Params *p) regs.rxdctl.gran(1); regs.rxdctl.wthresh(1); regs.fcrth(1); + regs.tdwba = 0; + regs.rlpml = 0; + regs.sw_fw_sync = 0; regs.pba.rxa(0x30); regs.pba.txa(0x10); @@ -105,10 +113,20 @@ IGbE::IGbE(const Params *p) // Magic happy checksum value flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); + // Store the MAC address as queue ID + macAddr = p->hardware_address; + rxFifo.clear(); txFifo.clear(); } +void +IGbE::init() +{ + cpa = CPA::cpa(); + PciDev::init(); +} + EtherInt* IGbE::getEthPort(const std::string &if_name, int idx) { @@ -192,6 +210,11 @@ IGbE::read(PacketPtr pkt) regs.imr &= ~regs.iam; chkInterrupt(); break; + case REG_EICR: + // This is only useful for MSI, but the driver reads it every time + // Just don't do anything + pkt->set<uint32_t>(0); + break; case REG_ITR: pkt->set<uint32_t>(regs.itr()); break; @@ -226,6 +249,9 @@ IGbE::read(PacketPtr pkt) case REG_RDLEN: pkt->set<uint32_t>(regs.rdlen()); break; + case REG_SRRCTL: + pkt->set<uint32_t>(regs.srrctl()); + break; case REG_RDH: pkt->set<uint32_t>(regs.rdh()); break; @@ -241,6 +267,9 @@ IGbE::read(PacketPtr pkt) regs.rdtr.fpd(0); } break; + case REG_RXDCTL: + pkt->set<uint32_t>(regs.rxdctl()); + break; case REG_RADV: pkt->set<uint32_t>(regs.radv()); break; @@ -256,6 +285,9 @@ IGbE::read(PacketPtr pkt) case REG_TDH: pkt->set<uint32_t>(regs.tdh()); break; + case REG_TXDCA_CTL: + pkt->set<uint32_t>(regs.txdca_ctl()); + break; case REG_TDT: pkt->set<uint32_t>(regs.tdt()); break; @@ -268,12 +300,34 @@ IGbE::read(PacketPtr pkt) case REG_TADV: pkt->set<uint32_t>(regs.tadv()); break; + case REG_TDWBAL: + pkt->set<uint32_t>(regs.tdwba & mask(32)); + break; + case REG_TDWBAH: + pkt->set<uint32_t>(regs.tdwba >> 32); + break; case REG_RXCSUM: pkt->set<uint32_t>(regs.rxcsum()); break; + case REG_RLPML: + pkt->set<uint32_t>(regs.rlpml); + break; + case REG_RFCTL: + pkt->set<uint32_t>(regs.rfctl()); + break; case REG_MANC: pkt->set<uint32_t>(regs.manc()); break; + case REG_SWSM: + pkt->set<uint32_t>(regs.swsm()); + regs.swsm.smbi(1); + break; + case REG_FWSM: + pkt->set<uint32_t>(regs.fwsm()); + break; + case REG_SWFWSYNC: + pkt->set<uint32_t>(regs.sw_fw_sync); + break; default: if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && @@ -380,6 +434,14 @@ IGbE::write(PacketPtr pkt) break; case REG_EERD: regs.eerd = val; + if (regs.eerd.start()) { + regs.eerd.done(1); + assert(regs.eerd.addr() < EEPROM_SIZE); + regs.eerd.data(flash[regs.eerd.addr()]); + regs.eerd.start(0); + DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n", + regs.eerd.addr(), regs.eerd.data()); + } break; case REG_MDIC: regs.mdic = val; @@ -394,10 +456,10 @@ IGbE::write(PacketPtr pkt) regs.mdic.data(0x796D); // link up break; case PHY_PID: - regs.mdic.data(0x02A8); + regs.mdic.data(params()->phy_pid); break; case PHY_EPID: - regs.mdic.data(0x0380); + regs.mdic.data(params()->phy_epid); break; case PHY_GSTATUS: regs.mdic.data(0x7C00); @@ -480,6 +542,9 @@ IGbE::write(PacketPtr pkt) case REG_TIPG: ; // We don't care, so don't store anything break; + case REG_IVAR0: + warn("Writing to IVAR0, ignoring...\n"); + break; case REG_FCRTL: regs.fcrtl = val; break; @@ -498,6 +563,9 @@ IGbE::write(PacketPtr pkt) regs.rdlen = val & ~mask(7); rxDescCache.areaChanged(); break; + case REG_SRRCTL: + regs.srrctl = val; + break; case REG_RDH: regs.rdh = val; rxDescCache.areaChanged(); @@ -518,6 +586,9 @@ IGbE::write(PacketPtr pkt) case REG_RADV: regs.radv = val; break; + case REG_RXDCTL: + regs.rxdctl = val; + break; case REG_TDBAL: regs.tdba.tdbal( val & ~mask(4)); txDescCache.areaChanged(); @@ -534,6 +605,11 @@ IGbE::write(PacketPtr pkt) regs.tdh = val; txDescCache.areaChanged(); break; + case REG_TXDCA_CTL: + regs.txdca_ctl = val; + if (regs.txdca_ctl.enabled()) + panic("No support for DCA\n"); + break; case REG_TDT: regs.tdt = val; DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n"); @@ -553,12 +629,38 @@ IGbE::write(PacketPtr pkt) case REG_TADV: regs.tadv = val; break; + case REG_TDWBAL: + regs.tdwba &= ~mask(32); + regs.tdwba |= val; + txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); + break; + case REG_TDWBAH: + regs.tdwba &= mask(32); + regs.tdwba |= (uint64_t)val << 32; + txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); + break; case REG_RXCSUM: regs.rxcsum = val; break; + case REG_RLPML: + regs.rlpml = val; + break; + case REG_RFCTL: + regs.rfctl = val; + if (regs.rfctl.exsten()) + panic("Extended RX descriptors not implemented\n"); + break; case REG_MANC: regs.manc = val; break; + case REG_SWSM: + regs.swsm = val; + if (regs.fwsm.eep_fw_semaphore()) + regs.swsm.swesmbi(0); + break; + case REG_SWFWSYNC: + regs.sw_fw_sync = val; + break; default: if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && @@ -580,16 +682,23 @@ IGbE::postInterrupt(IntTypes t, bool now) return; regs.icr = regs.icr() | t; - if (regs.itr.interval() == 0 || now) { + + Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval(); + DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n", + curTick, regs.itr.interval(), itr_interval); + + if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) { if (interEvent.scheduled()) { - interEvent.deschedule(); + deschedule(interEvent); } cpuPostInt(); } else { - DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", - Clock::Int::ns * 256 * regs.itr.interval()); + Tick int_time = lastInterrupt + itr_interval; + assert(int_time > 0); + DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n", + int_time); if (!interEvent.scheduled()) { - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + schedule(interEvent, int_time); } } } @@ -605,6 +714,8 @@ void IGbE::cpuPostInt() { + postedInterrupts++; + if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); return; @@ -614,24 +725,24 @@ IGbE::cpuPostInt() if (interEvent.scheduled()) { - interEvent.deschedule(); + deschedule(interEvent); } if (rdtrEvent.scheduled()) { regs.icr.rxt0(1); - rdtrEvent.deschedule(); + deschedule(rdtrEvent); } if (radvEvent.scheduled()) { regs.icr.rxt0(1); - radvEvent.deschedule(); + deschedule(radvEvent); } if (tadvEvent.scheduled()) { regs.icr.txdw(1); - tadvEvent.deschedule(); + deschedule(tadvEvent); } if (tidvEvent.scheduled()) { regs.icr.txdw(1); - tidvEvent.deschedule(); + deschedule(tidvEvent); } regs.icr.int_assert(1); @@ -640,6 +751,7 @@ IGbE::cpuPostInt() intrPost(); + lastInterrupt = curTick; } void @@ -662,7 +774,7 @@ IGbE::chkInterrupt() if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); if (interEvent.scheduled()) - interEvent.deschedule(); + deschedule(interEvent); if (regs.icr.int_assert()) cpuClearInt(); } @@ -676,7 +788,8 @@ IGbE::chkInterrupt() if (!interEvent.scheduled()) { DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns * 256 * regs.itr.interval()); - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + schedule(interEvent, + curTick + Clock::Int::ns * 256 * regs.itr.interval()); } } } @@ -686,27 +799,125 @@ IGbE::chkInterrupt() IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) - : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this) + : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), + pktEvent(this), pktHdrEvent(this), pktDataEvent(this) { + annSmFetch = "RX Desc Fetch"; + annSmWb = "RX Desc Writeback"; + annUnusedDescQ = "RX Unused Descriptors"; + annUnusedCacheQ = "RX Unused Descriptor Cache"; + annUsedCacheQ = "RX Used Descriptor Cache"; + annUsedDescQ = "RX Used Descriptors"; + annDescQ = "RX Descriptors"; } void -IGbE::RxDescCache::writePacket(EthPacketPtr packet) +IGbE::RxDescCache::pktSplitDone() { - // We shouldn't have to deal with any of these yet - DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", - packet->length, igbe->regs.rctl.descSize()); - assert(packet->length < igbe->regs.rctl.descSize()); + splitCount++; + DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount); + assert(splitCount <= 2); + if (splitCount != 2) + return; + splitCount = 0; + DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n"); + pktComplete(); +} - assert(unusedCache.size()); +int +IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset) +{ + assert(unusedCache.size()); //if (!unusedCache.size()) // return false; pktPtr = packet; pktDone = false; - igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf), - packet->length, &pktEvent, packet->data); + int buf_len, hdr_len; + + RxDesc *desc = unusedCache.front(); + switch (igbe->regs.srrctl.desctype()) { + case RXDT_LEGACY: + assert(pkt_offset == 0); + bytesCopied = packet->length; + DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", + packet->length, igbe->regs.rctl.descSize()); + assert(packet->length < igbe->regs.rctl.descSize()); + igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent, + packet->data, igbe->rxWriteDelay); + break; + case RXDT_ADV_ONEBUF: + assert(pkt_offset == 0); + bytesCopied = packet->length; + buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : + igbe->regs.rctl.descSize(); + DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n", + packet->length, igbe->regs.srrctl(), buf_len); + assert(packet->length < buf_len); + igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent, + packet->data, igbe->rxWriteDelay); + desc->adv_wb.header_len = htole(0); + desc->adv_wb.sph = htole(0); + desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length)); + break; + case RXDT_ADV_SPLIT_A: + int split_point; + + buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : + igbe->regs.rctl.descSize(); + hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; + DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n", + igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len); + + split_point = hsplit(pktPtr); + + if (packet->length <= hdr_len) { + bytesCopied = packet->length; + assert(pkt_offset == 0); + DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n"); + igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent, + packet->data, igbe->rxWriteDelay); + desc->adv_wb.header_len = htole((uint16_t)packet->length); + desc->adv_wb.sph = htole(0); + desc->adv_wb.pkt_len = htole(0); + } else if (split_point) { + if (pkt_offset) { + // we are only copying some data, header/data has already been + // copied + int max_to_copy = std::min(packet->length - pkt_offset, buf_len); + bytesCopied += max_to_copy; + DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n"); + igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent, + packet->data + pkt_offset, igbe->rxWriteDelay); + desc->adv_wb.header_len = htole(0); + desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy); + desc->adv_wb.sph = htole(0); + } else { + int max_to_copy = std::min(packet->length - split_point, buf_len); + bytesCopied += max_to_copy + split_point; + + DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n", + split_point); + igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent, + packet->data, igbe->rxWriteDelay); + igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), + max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay); + desc->adv_wb.header_len = htole(split_point); + desc->adv_wb.sph = 1; + desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy)); + } + } else { + panic("Header split not fitting within header buffer or undecodable" + " packet not fitting in header unsupported\n"); + } + break; + default: + panic("Unimplemnted RX receive buffer type: %d\n", + igbe->regs.srrctl.desctype()); + } + return bytesCopied; + } void @@ -716,10 +927,11 @@ IGbE::RxDescCache::pktComplete() RxDesc *desc; desc = unusedCache.front(); + igbe->anBegin("RXS", "Update Desc"); + uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ; - desc->len = htole((uint16_t)(pktPtr->length + crcfixup)); - DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n", - pktPtr->length, crcfixup, + DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n", + pktPtr->length, bytesCopied, crcfixup, htole((uint16_t)(pktPtr->length + crcfixup)), (uint16_t)(pktPtr->length + crcfixup)); @@ -728,20 +940,32 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); - uint8_t status = RXDS_DD | RXDS_EOP; + uint16_t status = RXDS_DD; uint8_t err = 0; + uint16_t ext_err = 0; + uint16_t csum = 0; + uint16_t ptype = 0; + uint16_t ip_id = 0; + + assert(bytesCopied <= pktPtr->length); + if (bytesCopied == pktPtr->length) + status |= RXDS_EOP; IpPtr ip(pktPtr); if (ip) { DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); + ptype |= RXDP_IPV4; + ip_id = ip->id(); if (igbe->regs.rxcsum.ipofld()) { DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; - desc->csum = htole(cksum(ip)); + csum = htole(cksum(ip)); + igbe->rxIpChecksums++; if (cksum(ip) != 0) { err |= RXDE_IPE; + ext_err |= RXDEE_IPE; DPRINTF(EthernetDesc, "Checksum is bad!!\n"); } } @@ -749,10 +973,13 @@ IGbE::RxDescCache::pktComplete() if (tcp && igbe->regs.rxcsum.tuofld()) { DPRINTF(EthernetDesc, "Checking TCP checksum\n"); status |= RXDS_TCPCS; - desc->csum = htole(cksum(tcp)); + ptype |= RXDP_TCP; + csum = htole(cksum(tcp)); + igbe->rxTcpChecksums++; if (cksum(tcp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; + ext_err |= RXDEE_TCPE; } } @@ -760,9 +987,12 @@ IGbE::RxDescCache::pktComplete() if (udp && igbe->regs.rxcsum.tuofld()) { DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; - desc->csum = htole(cksum(udp)); + ptype |= RXDP_UDP; + csum = htole(cksum(udp)); + igbe->rxUdpChecksums++; if (cksum(udp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); + ext_err |= RXDEE_TCPE; err |= RXDE_TCPE; } } @@ -770,53 +1000,83 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); } + switch (igbe->regs.srrctl.desctype()) { + case RXDT_LEGACY: + desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup)); + desc->legacy.status = htole(status); + desc->legacy.errors = htole(err); + // No vlan support at this point... just set it to 0 + desc->legacy.vlan = 0; + break; + case RXDT_ADV_SPLIT_A: + case RXDT_ADV_ONEBUF: + desc->adv_wb.rss_type = htole(0); + desc->adv_wb.pkt_type = htole(ptype); + if (igbe->regs.rxcsum.pcsd()) { + // no rss support right now + desc->adv_wb.rss_hash = htole(0); + } else { + desc->adv_wb.id = htole(ip_id); + desc->adv_wb.csum = htole(csum); + } + desc->adv_wb.status = htole(status); + desc->adv_wb.errors = htole(ext_err); + // no vlan support + desc->adv_wb.vlan_tag = htole(0); + break; + default: + panic("Unimplemnted RX receive buffer type %d\n", + igbe->regs.srrctl.desctype()); + } - desc->status = htole(status); - desc->errors = htole(err); - - // No vlan support at this point... just set it to 0 - desc->vlan = 0; + DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n", + desc->adv_read.pkt, desc->adv_read.hdr); - // Deal with the rx timer interrupts - if (igbe->regs.rdtr.delay()) { - DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", - igbe->regs.rdtr.delay() * igbe->intClock()); - igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() * - igbe->intClock(),true); - } + if (bytesCopied == pktPtr->length) { + DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n"); + // Deal with the rx timer interrupts + if (igbe->regs.rdtr.delay()) { + DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", + igbe->regs.rdtr.delay() * igbe->intClock()); + igbe->reschedule(igbe->rdtrEvent, + curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true); + } - if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) { - DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", - igbe->regs.radv.idv() * igbe->intClock()); - if (!igbe->radvEvent.scheduled()) { - igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() * - igbe->intClock()); + if (igbe->regs.radv.idv()) { + DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", + igbe->regs.radv.idv() * igbe->intClock()); + if (!igbe->radvEvent.scheduled()) { + igbe->schedule(igbe->radvEvent, + curTick + igbe->regs.radv.idv() * igbe->intClock()); + } } - } - // if neither radv or rdtr, maybe itr is set... - if (!igbe->regs.rdtr.delay()) { - DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); - igbe->postInterrupt(IT_RXT); - } + // if neither radv or rdtr, maybe itr is set... + if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) { + DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); + igbe->postInterrupt(IT_RXT); + } - // If the packet is small enough, interrupt appropriately - // I wonder if this is delayed or not?! - if (pktPtr->length <= igbe->regs.rsrpd.idv()) { - DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); - igbe->postInterrupt(IT_SRPD); + // If the packet is small enough, interrupt appropriately + // I wonder if this is delayed or not?! + if (pktPtr->length <= igbe->regs.rsrpd.idv()) { + DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); + igbe->postInterrupt(IT_SRPD); + } + bytesCopied = 0; } - DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); - unusedCache.pop_front(); - usedCache.push_back(desc); - - pktPtr = NULL; + igbe->checkDrain(); enableSm(); pktDone = true; - igbe->checkDrain(); + igbe->anBegin("RXS", "Done Updating Desc"); + DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); + igbe->anDq("RXS", annUnusedCacheQ); + unusedCache.pop_front(); + igbe->anQ("RXS", annUsedCacheQ); + usedCache.push_back(desc); } void @@ -842,7 +1102,9 @@ bool IGbE::RxDescCache::hasOutstandingEvents() { return pktEvent.scheduled() || wbEvent.scheduled() || - fetchEvent.scheduled(); + fetchEvent.scheduled() || pktHdrEvent.scheduled() || + pktDataEvent.scheduled(); + } void @@ -850,6 +1112,8 @@ IGbE::RxDescCache::serialize(std::ostream &os) { DescCache<RxDesc>::serialize(os); SERIALIZE_SCALAR(pktDone); + SERIALIZE_SCALAR(splitCount); + SERIALIZE_SCALAR(bytesCopied); } void @@ -857,6 +1121,8 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) { DescCache<RxDesc>::unserialize(cp, section); UNSERIALIZE_SCALAR(pktDone); + UNSERIALIZE_SCALAR(splitCount); + UNSERIALIZE_SCALAR(bytesCopied); } @@ -864,45 +1130,154 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), - pktEvent(this) + completionAddress(0), completionEnabled(false), + useTso(false), pktEvent(this), headerEvent(this), nullEvent(this) { + annSmFetch = "TX Desc Fetch"; + annSmWb = "TX Desc Writeback"; + annUnusedDescQ = "TX Unused Descriptors"; + annUnusedCacheQ = "TX Unused Descriptor Cache"; + annUsedCacheQ = "TX Used Descriptor Cache"; + annUsedDescQ = "TX Used Descriptors"; + annDescQ = "TX Descriptors"; } -int -IGbE::TxDescCache::getPacketSize() +void +IGbE::TxDescCache::processContextDesc() { assert(unusedCache.size()); - TxDesc *desc; + + DPRINTF(EthernetDesc, "Checking and processing context descriptors\n"); - DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); - - while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) { - DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n"); + while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) { + DPRINTF(EthernetDesc, "Got context descriptor type...\n"); - // I think we can just ignore these for now? desc = unusedCache.front(); - DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1, - desc->d2); + DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", + desc->d1, desc->d2); + + // is this going to be a tcp or udp packet? isTcp = TxdOp::tcp(desc) ? true : false; - // make sure it's ipv4 - //assert(TxdOp::ip(desc)); + // setup all the TSO variables, they'll be ignored if we don't use + // tso for this connection + tsoHeaderLen = TxdOp::hdrlen(desc); + tsoMss = TxdOp::mss(desc); + + if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) { + DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n", + TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc)); + useTso = true; + tsoTotalLen = TxdOp::getLen(desc); + tsoLoadedHeader = false; + tsoDescBytesUsed = 0; + tsoUsedLen = 0; + tsoPrevSeq = 0; + tsoPktHasHeader = false; + tsoPkts = 0; + + } TxdOp::setDd(desc); unusedCache.pop_front(); + igbe->anDq("TXS", annUnusedCacheQ); usedCache.push_back(desc); + igbe->anQ("TXS", annUsedCacheQ); } if (!unusedCache.size()) + return; + + desc = unusedCache.front(); + if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) { + DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n", + tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc)); + useTso = true; + tsoTotalLen = TxdOp::getTsoLen(desc); + tsoLoadedHeader = false; + tsoDescBytesUsed = 0; + tsoUsedLen = 0; + tsoPrevSeq = 0; + tsoPktHasHeader = false; + tsoPkts = 0; + } + + if (useTso && !tsoLoadedHeader) { + // we need to fetch a header + DPRINTF(EthernetDesc, "Starting DMA of TSO header\n"); + assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen); + pktWaiting = true; + assert(tsoHeaderLen <= 256); + igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), + tsoHeaderLen, &headerEvent, tsoHeader, 0); + } +} + +void +IGbE::TxDescCache::headerComplete() +{ + DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n"); + pktWaiting = false; + + assert(unusedCache.size()); + TxDesc *desc = unusedCache.front(); + DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n", + TxdOp::getLen(desc), tsoHeaderLen); + + if (TxdOp::getLen(desc) == tsoHeaderLen) { + tsoDescBytesUsed = 0; + tsoLoadedHeader = true; + unusedCache.pop_front(); + usedCache.push_back(desc); + } else { + // I don't think this case happens, I think the headrer is always + // it's own packet, if it wasn't it might be as simple as just + // incrementing descBytesUsed by the header length, but I'm not + // completely sure + panic("TSO header part of bigger packet, not implemented\n"); + } + enableSm(); + igbe->checkDrain(); +} + +int +IGbE::TxDescCache::getPacketSize(EthPacketPtr p) +{ + TxDesc *desc; + + + if (!unusedCache.size()) return -1; + + DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); - DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", - TxdOp::getLen(unusedCache.front())); + assert(!useTso || tsoLoadedHeader); + desc = unusedCache.front(); + + + if (useTso) { + DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); + DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", + useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); + DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n", + tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc)); + DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader); + + if (tsoPktHasHeader) + tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed); + else + tsoCopyBytes = std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed); + Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); + DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size); + return pkt_size; + } - return TxdOp::getLen(unusedCache.front()); + DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", + TxdOp::getLen(unusedCache.front())); + return TxdOp::getLen(desc); } void @@ -913,17 +1288,37 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p) TxDesc *desc; desc = unusedCache.front(); + DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); pktPtr = p; pktWaiting = true; - DPRINTF(EthernetDesc, "Starting DMA of packet\n"); - igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), - TxdOp::getLen(desc), &pktEvent, p->data + p->length); - - + DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); + + if (useTso) { + assert(tsoLoadedHeader); + if (!tsoPktHasHeader) { + DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n", + tsoHeaderLen); + memcpy(p->data, &tsoHeader,tsoHeaderLen); + p->length +=tsoHeaderLen; + tsoPktHasHeader = true; + } + } + + if (useTso) { + tsoDescBytesUsed += tsoCopyBytes; + assert(tsoDescBytesUsed <= TxdOp::getLen(desc)); + DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n", + p->length, tsoCopyBytes); + igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed, + tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay); + } else { + igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), + TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay); + } } void @@ -934,6 +1329,8 @@ IGbE::TxDescCache::pktComplete() assert(unusedCache.size()); assert(pktPtr); + igbe->anBegin("TXS", "Update Desc"); + DPRINTF(EthernetDesc, "DMA of packet complete\n"); @@ -941,40 +1338,83 @@ IGbE::TxDescCache::pktComplete() assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); + DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", + useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); - if (!TxdOp::eop(desc)) { - // This only supports two descriptors per tx packet - assert(pktPtr->length == 0); - pktPtr->length = TxdOp::getLen(desc); + // Set the length of the data in the EtherPacket + if (useTso) { + pktPtr->length += tsoCopyBytes; + tsoUsedLen += tsoCopyBytes; + } else + pktPtr->length += TxdOp::getLen(desc); + + DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n", + tsoDescBytesUsed, tsoCopyBytes); + + + if ((!TxdOp::eop(desc) && !useTso) || + (pktPtr->length < ( tsoMss + tsoHeaderLen) && + tsoTotalLen != tsoUsedLen && useTso)) { + assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc))); + igbe->anDq("TXS", annUnusedCacheQ); unusedCache.pop_front(); + igbe->anQ("TXS", annUsedCacheQ); usedCache.push_back(desc); + + tsoDescBytesUsed = 0; pktDone = true; pktWaiting = false; + pktMultiDesc = true; + + DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n", + pktPtr->length); pktPtr = NULL; - DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); enableSm(); igbe->checkDrain(); return; } - // Set the length of the data in the EtherPacket - pktPtr->length += TxdOp::getLen(desc); + pktMultiDesc = false; // no support for vlans assert(!TxdOp::vle(desc)); - // we alway report status - assert(TxdOp::rs(desc)); - // we only support single packet descriptors at this point - assert(TxdOp::eop(desc)); + if (!useTso) + assert(TxdOp::eop(desc)); // set that this packet is done - TxdOp::setDd(desc); + if (TxdOp::rs(desc)) + TxdOp::setDd(desc); DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); + if (useTso) { + IpPtr ip(pktPtr); + if (ip) { + DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n", + tsoPkts); + ip->id(ip->id() + tsoPkts++); + ip->len(pktPtr->length - EthPtr(pktPtr)->size()); + + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n", + tcp->seq(), tsoPrevSeq); + tcp->seq(tcp->seq() + tsoPrevSeq); + if (tsoUsedLen != tsoTotalLen) + tcp->flags(tcp->flags() & ~9); // clear fin & psh + } + UdpPtr udp(ip); + if (udp) { + DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n"); + udp->len(pktPtr->length - EthPtr(pktPtr)->size()); + } + } + tsoPrevSeq = tsoUsedLen; + } + if (DTRACE(EthernetDesc)) { IpPtr ip(pktPtr); if (ip) @@ -988,10 +1428,11 @@ IGbE::TxDescCache::pktComplete() if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); - + assert(ip); if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); + igbe->txIpChecksums++; DPRINTF(EthernetDesc, "Calculated IP checksum\n"); } if (TxdOp::txsm(desc)) { @@ -1000,11 +1441,13 @@ IGbE::TxDescCache::pktComplete() if (tcp) { tcp->sum(0); tcp->sum(cksum(tcp)); + igbe->txTcpChecksums++; DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else if (udp) { assert(udp); udp->sum(0); udp->sum(cksum(udp)); + igbe->txUdpChecksums++; DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); } else { panic("Told to checksum, but don't know how\n"); @@ -1017,47 +1460,100 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); if (igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tidv\n"); - igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * - igbe->intClock(), true); + igbe->reschedule(igbe->tidvEvent, + curTick + igbe->regs.tidv.idv() * igbe->intClock(), true); } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tadv\n"); if (!igbe->tadvEvent.scheduled()) { - igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * - igbe->intClock()); + igbe->schedule(igbe->tadvEvent, + curTick + igbe->regs.tadv.idv() * igbe->intClock()); } } } + if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) { + DPRINTF(EthernetDesc, "Descriptor Done\n"); + igbe->anDq("TXS", annUnusedCacheQ); + unusedCache.pop_front(); + igbe->anQ("TXS", annUsedCacheQ); + usedCache.push_back(desc); + tsoDescBytesUsed = 0; + } + + if (useTso && tsoUsedLen == tsoTotalLen) + useTso = false; + - unusedCache.pop_front(); - usedCache.push_back(desc); + DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n", + pktPtr->length); pktDone = true; pktWaiting = false; pktPtr = NULL; - - DPRINTF(EthernetDesc, "Descriptor Done\n"); + tsoPktHasHeader = false; if (igbe->regs.txdctl.wthresh() == 0) { + igbe->anBegin("TXS", "Desc Writeback"); DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); writeback(0); + } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >= + descInBlock(usedCache.size())) { + DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); + igbe->anBegin("TXS", "Desc Writeback"); + writeback((igbe->cacheBlockSize()-1)>>4); } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); + igbe->anBegin("TXS", "Desc Writeback"); writeback((igbe->cacheBlockSize()-1)>>4); } + enableSm(); igbe->checkDrain(); } void +IGbE::TxDescCache::actionAfterWb() +{ + DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n", + completionEnabled); + igbe->postInterrupt(iGbReg::IT_TXDW); + if (completionEnabled) { + descEnd = igbe->regs.tdh(); + DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd, + completionAddress); + igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)), + sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0); + } +} + +void IGbE::TxDescCache::serialize(std::ostream &os) { DescCache<TxDesc>::serialize(os); SERIALIZE_SCALAR(pktDone); SERIALIZE_SCALAR(isTcp); SERIALIZE_SCALAR(pktWaiting); + SERIALIZE_SCALAR(pktMultiDesc); + + SERIALIZE_SCALAR(useTso); + SERIALIZE_SCALAR(tsoHeaderLen); + SERIALIZE_SCALAR(tsoMss); + SERIALIZE_SCALAR(tsoTotalLen); + SERIALIZE_SCALAR(tsoUsedLen); + SERIALIZE_SCALAR(tsoPrevSeq);; + SERIALIZE_SCALAR(tsoPktPayloadBytes); + SERIALIZE_SCALAR(tsoLoadedHeader); + SERIALIZE_SCALAR(tsoPktHasHeader); + SERIALIZE_ARRAY(tsoHeader, 256); + SERIALIZE_SCALAR(tsoDescBytesUsed); + SERIALIZE_SCALAR(tsoCopyBytes); + SERIALIZE_SCALAR(tsoPkts); + + SERIALIZE_SCALAR(completionAddress); + SERIALIZE_SCALAR(completionEnabled); + SERIALIZE_SCALAR(descEnd); } void @@ -1067,6 +1563,25 @@ IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(pktDone); UNSERIALIZE_SCALAR(isTcp); UNSERIALIZE_SCALAR(pktWaiting); + UNSERIALIZE_SCALAR(pktMultiDesc); + + UNSERIALIZE_SCALAR(useTso); + UNSERIALIZE_SCALAR(tsoHeaderLen); + UNSERIALIZE_SCALAR(tsoMss); + UNSERIALIZE_SCALAR(tsoTotalLen); + UNSERIALIZE_SCALAR(tsoUsedLen); + UNSERIALIZE_SCALAR(tsoPrevSeq);; + UNSERIALIZE_SCALAR(tsoPktPayloadBytes); + UNSERIALIZE_SCALAR(tsoLoadedHeader); + UNSERIALIZE_SCALAR(tsoPktHasHeader); + UNSERIALIZE_ARRAY(tsoHeader, 256); + UNSERIALIZE_SCALAR(tsoDescBytesUsed); + UNSERIALIZE_SCALAR(tsoCopyBytes); + UNSERIALIZE_SCALAR(tsoPkts); + + UNSERIALIZE_SCALAR(completionAddress); + UNSERIALIZE_SCALAR(completionEnabled); + UNSERIALIZE_SCALAR(descEnd); } bool @@ -1101,9 +1616,9 @@ IGbE::TxDescCache::hasOutstandingEvents() void IGbE::restartClock() { - if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() == - SimObject::Running) - tickEvent.schedule((curTick/ticks(1)) * ticks(1) + ticks(1)); + if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && + getState() == SimObject::Running) + schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1)); } unsigned int @@ -1122,13 +1637,14 @@ IGbE::drain(Event *de) rxTick = false; if (tickEvent.scheduled()) - tickEvent.deschedule(); + deschedule(tickEvent); if (count) changeState(Draining); else changeState(Drained); + DPRINTF(EthernetSM, "got drain() returning %d", count); return count; } @@ -1142,6 +1658,7 @@ IGbE::resume() rxTick = true; restartClock(); + DPRINTF(EthernetSM, "resuming from drain"); } void @@ -1150,6 +1667,7 @@ IGbE::checkDrain() if (!drainEvent) return; + DPRINTF(EthernetSM, "checkDrain() in drain\n"); txFifoTick = false; txTick = false; rxTick = false; @@ -1172,20 +1690,22 @@ IGbE::txStateMachine() // If we have a packet available and it's length is not 0 (meaning it's not // a multidescriptor packet) put it in the fifo, otherwise an the next // iteration we'll get the rest of the data - if (txPacket && txDescCache.packetAvailable() && txPacket->length) { + if (txPacket && txDescCache.packetAvailable() + && !txDescCache.packetMultiDesc() && txPacket->length) { bool success; + anQ("TXS", "TX FIFO Q"); DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); success = txFifo.push(txPacket); txFifoTick = true && !drainEvent; assert(success); txPacket = NULL; + anBegin("TXS", "Desc Writeback"); txDescCache.writeback((cacheBlockSize()-1)>>4); return; } // Only support descriptor granularity - assert(regs.txdctl.gran()); if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) { DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n"); postInterrupt(IT_TXDLOW); @@ -1198,7 +1718,10 @@ IGbE::txStateMachine() if (!txDescCache.packetWaiting()) { if (txDescCache.descLeft() == 0) { postInterrupt(IT_TXQE); + anBegin("TXS", "Desc Writeback"); txDescCache.writeback(0); + anBegin("TXS", "Desc Fetch"); + anWe("TXS", txDescCache.annUnusedCacheQ); txDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " "writeback stopping ticking and posting TXQE\n"); @@ -1208,16 +1731,28 @@ IGbE::txStateMachine() if (!(txDescCache.descUnused())) { + anBegin("TXS", "Desc Fetch"); txDescCache.fetchDescriptors(); + anWe("TXS", txDescCache.annUnusedCacheQ); DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n"); txTick = false; return; } + anPq("TXS", txDescCache.annUnusedCacheQ); + + txDescCache.processContextDesc(); + if (txDescCache.packetWaiting()) { + DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n"); + txTick = false; + return; + } int size; - size = txDescCache.getPacketSize(); + size = txDescCache.getPacketSize(txPacket); if (size > 0 && txFifo.avail() > size) { + anRq("TXS", "TX FIFO Q"); + anBegin("TXS", "DMA Packet"); DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining " "DMA of next packet\n", size); txFifo.reserve(size); @@ -1225,8 +1760,10 @@ IGbE::txStateMachine() } else if (size <= 0) { DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size); DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); + anBegin("TXS", "Desc Writeback"); txDescCache.writeback(0); } else { + anWf("TXS", "TX FIFO Q"); DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " "available in FIFO\n"); txTick = false; @@ -1242,10 +1779,16 @@ IGbE::txStateMachine() bool IGbE::ethRxPkt(EthPacketPtr pkt) { + rxBytes += pkt->length; + rxPackets++; + DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); + anBegin("RXQ", "Wire Recv"); + if (!regs.rctl.en()) { DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); + anBegin("RXQ", "FIFO Drop", CPA::FL_BAD); return true; } @@ -1259,9 +1802,23 @@ IGbE::ethRxPkt(EthPacketPtr pkt) if (!rxFifo.push(pkt)) { DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); postInterrupt(IT_RXO, true); + anBegin("RXQ", "FIFO Drop", CPA::FL_BAD); return false; } + if (CPA::available() && cpa->enabled()) { + assert(sys->numSystemsRunning <= 2); + System *other_sys; + if (sys->systemList[0] == sys) + other_sys = sys->systemList[1]; + else + other_sys = sys->systemList[0]; + + cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys); + anQ("RXQ", "RX FIFO Q"); + cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys); + } + return true; } @@ -1280,6 +1837,8 @@ IGbE::rxStateMachine() rxDmaPacket = false; DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); int descLeft = rxDescCache.descLeft(); + DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n", + descLeft, regs.rctl.rdmts(), regs.rdlen()); switch (regs.rctl.rdmts()) { case 2: if (descLeft > .125 * regs.rdlen()) break; case 1: if (descLeft > .250 * regs.rdlen()) break; @@ -1289,7 +1848,11 @@ IGbE::rxStateMachine() break; } + if (rxFifo.empty()) + rxDescCache.writeback(0); + if (descLeft == 0) { + anBegin("RXS", "Writeback Descriptors"); rxDescCache.writeback(0); DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" " writeback and stopping ticking\n"); @@ -1301,6 +1864,7 @@ IGbE::rxStateMachine() if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n"); + anBegin("RXS", "Writeback Descriptors"); if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4)) rxDescCache.writeback(regs.rxdctl.wthresh()-1); else @@ -1310,11 +1874,14 @@ IGbE::rxStateMachine() if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) { DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n"); + anBegin("RXS", "Fetch Descriptors"); rxDescCache.fetchDescriptors(); } if (rxDescCache.descUnused() == 0) { + anBegin("RXS", "Fetch Descriptors"); rxDescCache.fetchDescriptors(); + anWe("RXS", rxDescCache.annUnusedCacheQ); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " "fetching descriptors and stopping ticking\n"); rxTick = false; @@ -1329,42 +1896,58 @@ IGbE::rxStateMachine() } if (!rxDescCache.descUnused()) { + anBegin("RXS", "Fetch Descriptors"); rxDescCache.fetchDescriptors(); + anWe("RXS", rxDescCache.annUnusedCacheQ); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); rxTick = false; DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); return; } + anPq("RXS", rxDescCache.annUnusedCacheQ); if (rxFifo.empty()) { + anWe("RXS", "RX FIFO Q"); DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); rxTick = false; return; } + anPq("RXS", "RX FIFO Q"); + anBegin("RXS", "Get Desc"); EthPacketPtr pkt; pkt = rxFifo.front(); - rxDescCache.writePacket(pkt); + pktOffset = rxDescCache.writePacket(pkt, pktOffset); DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); - DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); - rxFifo.pop(); + if (pktOffset == pkt->length) { + anBegin( "RXS", "FIFO Dequeue"); + DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); + pktOffset = 0; + anDq("RXS", "RX FIFO Q"); + rxFifo.pop(); + } + DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); rxTick = false; rxDmaPacket = true; + anBegin("RXS", "DMA Packet"); } void IGbE::txWire() { if (txFifo.empty()) { + anWe("TXQ", "TX FIFO Q"); txFifoTick = false; return; } + anPq("TXQ", "TX FIFO Q"); if (etherInt->sendPacket(txFifo.front())) { + cpa->hwQ(CPA::FL_NONE, sys, macAddr, "TXQ", "WireQ", 0); if (DTRACE(EthernetSM)) { IpPtr ip(txFifo.front()); if (ip) @@ -1373,8 +1956,15 @@ IGbE::txWire() else DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); } + anDq("TXQ", "TX FIFO Q"); + anBegin("TXQ", "Wire Send"); DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n", txFifo.avail()); + + txBytes += txFifo.front()->length; + txPackets++; + txFifoTick = false; + txFifo.pop(); } else { // We'll get woken up when the packet ethTxDone() gets called @@ -1398,12 +1988,13 @@ IGbE::tick() if (rxTick || txTick || txFifoTick) - tickEvent.schedule(curTick + ticks(1)); + schedule(tickEvent, curTick + ticks(1)); } void IGbE::ethTxDone() { + anBegin("TXQ", "Send Done"); // restart the tx state machines if they are stopped // fifo to send another packet // tx sm to put more data into the fifo @@ -1412,6 +2003,7 @@ IGbE::ethTxDone() txTick = true; restartClock(); + txWire(); DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n"); } @@ -1426,6 +2018,7 @@ IGbE::serialize(std::ostream &os) SERIALIZE_SCALAR(eeDataBits); SERIALIZE_SCALAR(eeOpcode); SERIALIZE_SCALAR(eeAddr); + SERIALIZE_SCALAR(lastInterrupt); SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.serialize("rxfifo", os); @@ -1459,6 +2052,8 @@ IGbE::serialize(std::ostream &os) inter_time = interEvent.when(); SERIALIZE_SCALAR(inter_time); + SERIALIZE_SCALAR(pktOffset); + nameOut(os, csprintf("%s.TxDescCache", name())); txDescCache.serialize(os); @@ -1477,6 +2072,7 @@ IGbE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(eeDataBits); UNSERIALIZE_SCALAR(eeOpcode); UNSERIALIZE_SCALAR(eeAddr); + UNSERIALIZE_SCALAR(lastInterrupt); UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.unserialize("rxfifo", cp, section); @@ -1501,19 +2097,21 @@ IGbE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(inter_time); if (rdtr_time) - rdtrEvent.schedule(rdtr_time); + schedule(rdtrEvent, rdtr_time); if (radv_time) - radvEvent.schedule(radv_time); + schedule(radvEvent, radv_time); if (tidv_time) - tidvEvent.schedule(tidv_time); + schedule(tidvEvent, tidv_time); if (tadv_time) - tadvEvent.schedule(tadv_time); + schedule(tadvEvent, tadv_time); if (inter_time) - interEvent.schedule(inter_time); + schedule(interEvent, inter_time); + + UNSERIALIZE_SCALAR(pktOffset); txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section)); diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index 9403c87b6..308cfabde 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -38,8 +38,8 @@ #include <deque> #include <string> +#include "base/cp_annotate.hh" #include "base/inet.hh" -#include "base/statistics.hh" #include "dev/etherdevice.hh" #include "dev/etherint.hh" #include "dev/etherpkt.hh" @@ -55,6 +55,7 @@ class IGbE : public EtherDevice { private: IGbEInt *etherInt; + CPA *cpa; // device registers iGbReg::Regs regs; @@ -84,11 +85,19 @@ class IGbE : public EtherDevice bool rxDmaPacket; + // Number of bytes copied from current RX packet + int pktOffset; + + // Delays in managaging descriptors + Tick fetchDelay, wbDelay; + Tick fetchCompDelay, wbCompDelay; + Tick rxWriteDelay, txReadDelay; + // Event and function to deal with RDTR timer expiring void rdtrProcess() { rxDescCache.writeback(0); DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n"); - postInterrupt(iGbReg::IT_RXT, true); + postInterrupt(iGbReg::IT_RXT); } //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>; @@ -98,7 +107,7 @@ class IGbE : public EtherDevice void radvProcess() { rxDescCache.writeback(0); DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n"); - postInterrupt(iGbReg::IT_RXT, true); + postInterrupt(iGbReg::IT_RXT); } //friend class EventWrapper<IGbE, &IGbE::radvProcess>; @@ -108,7 +117,7 @@ class IGbE : public EtherDevice void tadvProcess() { txDescCache.writeback(0); DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n"); - postInterrupt(iGbReg::IT_TXDW, true); + postInterrupt(iGbReg::IT_TXDW); } //friend class EventWrapper<IGbE, &IGbE::tadvProcess>; @@ -118,7 +127,7 @@ class IGbE : public EtherDevice void tidvProcess() { txDescCache.writeback(0); DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n"); - postInterrupt(iGbReg::IT_TXDW, true); + postInterrupt(iGbReg::IT_TXDW); } //friend class EventWrapper<IGbE, &IGbE::tidvProcess>; EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent; @@ -129,6 +138,8 @@ class IGbE : public EtherDevice EventWrapper<IGbE, &IGbE::tick> tickEvent; + uint64_t macAddr; + void rxStateMachine(); void txStateMachine(); void txWire(); @@ -167,6 +178,35 @@ class IGbE : public EtherDevice */ void checkDrain(); + void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) { + cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st); + } + + void anQ(std::string sm, std::string q) { + cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); + } + + void anDq(std::string sm, std::string q) { + cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); + } + + void anPq(std::string sm, std::string q, int num = 1) { + cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num); + } + + void anRq(std::string sm, std::string q, int num = 1) { + cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num); + } + + void anWe(std::string sm, std::string q) { + cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); + } + + void anWf(std::string sm, std::string q) { + cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr); + } + + template<class T> class DescCache { @@ -177,7 +217,7 @@ class IGbE : public EtherDevice virtual long descLen() const = 0; virtual void updateHead(long h) = 0; virtual void enableSm() = 0; - virtual void intAfterWb() const {} + virtual void actionAfterWb() {} virtual void fetchAfterWb() = 0; std::deque<T*> usedCache; @@ -216,9 +256,14 @@ class IGbE : public EtherDevice EthPacketPtr pktPtr; public: + /** Annotate sm*/ + std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ, + annUsedDescQ, annUnusedCacheQ, annDescQ; + DescCache(IGbE *i, const std::string n, int s) : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0), - pktPtr(NULL), fetchEvent(this), wbEvent(this) + pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this), + fetchEvent(this), wbEvent(this) { fetchBuf = new T[size]; wbBuf = new T[size]; @@ -248,62 +293,92 @@ class IGbE : public EtherDevice int curHead = descHead(); int max_to_wb = usedCache.size(); - DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: " - "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n", - curHead, descTail(), descLen(), cachePnt, max_to_wb, - descLeft()); - // Check if this writeback is less restrictive that the previous // and if so setup another one immediately following it - if (wbOut && (aMask < wbAlignment)) { - moreToWb = true; - wbAlignment = aMask; + if (wbOut) { + if (aMask < wbAlignment) { + moreToWb = true; + wbAlignment = aMask; + } DPRINTF(EthernetDesc, "Writing back already in process, returning\n"); return; } - moreToWb = false; wbAlignment = aMask; + + + DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: " + "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n", + curHead, descTail(), descLen(), cachePnt, max_to_wb, + descLeft()); if (max_to_wb + curHead >= descLen()) { max_to_wb = descLen() - curHead; moreToWb = true; // this is by definition aligned correctly - } else if (aMask != 0) { + } else if (wbAlignment != 0) { // align the wb point to the mask - max_to_wb = max_to_wb & ~aMask; + max_to_wb = max_to_wb & ~wbAlignment; } DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb); - if (max_to_wb <= 0 || wbOut) + if (max_to_wb <= 0) { + if (usedCache.size()) + igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT); + else + igbe->anWe(annSmWb, annUsedCacheQ); return; + } wbOut = max_to_wb; + assert(!wbDelayEvent.scheduled()); + igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay); + igbe->anBegin(annSmWb, "Prepare Writeback Desc"); + } + + void writeback1() + { + // If we're draining delay issuing this DMA + if (igbe->getState() != SimObject::Running) { + igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay); + return; + } + + DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut); + for (int x = 0; x < wbOut; x++) { assert(usedCache.size()); - memcpy(&wbBuf[x], usedCache[0], sizeof(T)); - delete usedCache[0]; - usedCache.pop_front(); + memcpy(&wbBuf[x], usedCache[x], sizeof(T)); + igbe->anPq(annSmWb, annUsedCacheQ); + igbe->anPq(annSmWb, annDescQ); + igbe->anQ(annSmWb, annUsedDescQ); } + + igbe->anBegin(annSmWb, "Writeback Desc DMA"); assert(wbOut); - igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)), - wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf); + igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)), + wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf, + igbe->wbCompDelay); } + EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent; /** Fetch a chunk of descriptors into the descriptor cache. * Calls fetchComplete when the memory system returns the data */ + void fetchDescriptors() { size_t max_to_fetch; - if (curFetching) + if (curFetching) { + DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching); return; + } if (descTail() >= cachePnt) max_to_fetch = descTail() - cachePnt; @@ -312,7 +387,20 @@ class IGbE : public EtherDevice size_t free_cache = size - usedCache.size() - unusedCache.size(); + if (!max_to_fetch) + igbe->anWe(annSmFetch, annUnusedDescQ); + else + igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch); + + if (max_to_fetch) { + if (!free_cache) + igbe->anWf(annSmFetch, annDescQ); + else + igbe->anRq(annSmFetch, annDescQ, free_cache); + } + max_to_fetch = std::min(max_to_fetch, free_cache); + DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: " "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n", @@ -322,31 +410,53 @@ class IGbE : public EtherDevice // Nothing to do if (max_to_fetch == 0) return; - + // So we don't have two descriptor fetches going on at once curFetching = max_to_fetch; + assert(!fetchDelayEvent.scheduled()); + igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay); + igbe->anBegin(annSmFetch, "Prepare Fetch Desc"); + } + + void fetchDescriptors1() + { + // If we're draining delay issuing this DMA + if (igbe->getState() != SimObject::Running) { + igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay); + return; + } + + igbe->anBegin(annSmFetch, "Fetch Desc"); + DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n", descBase() + cachePnt * sizeof(T), igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)), curFetching * sizeof(T)); assert(curFetching); igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)), - curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf); + curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf, + igbe->fetchCompDelay); } + EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent; /** Called by event when dma to read descriptors is completed */ void fetchComplete() { T *newDesc; + igbe->anBegin(annSmFetch, "Fetch Complete"); for (int x = 0; x < curFetching; x++) { newDesc = new T; memcpy(newDesc, &fetchBuf[x], sizeof(T)); unusedCache.push_back(newDesc); + igbe->anDq(annSmFetch, annUnusedDescQ); + igbe->anQ(annSmFetch, annUnusedCacheQ); + igbe->anQ(annSmFetch, annDescQ); } + #ifndef NDEBUG int oldCp = cachePnt; #endif @@ -361,6 +471,16 @@ class IGbE : public EtherDevice DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n", oldCp, cachePnt); + if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() - + cachePnt)) == 0) + { + igbe->anWe(annSmFetch, annUnusedDescQ); + } else if (!(size - usedCache.size() - unusedCache.size())) { + igbe->anWf(annSmFetch, annDescQ); + } else { + igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT); + } + enableSm(); igbe->checkDrain(); } @@ -372,10 +492,21 @@ class IGbE : public EtherDevice void wbComplete() { + igbe->anBegin(annSmWb, "Finish Writeback"); + long curHead = descHead(); #ifndef NDEBUG long oldHead = curHead; #endif + + for (int x = 0; x < wbOut; x++) { + assert(usedCache.size()); + delete usedCache[0]; + usedCache.pop_front(); + + igbe->anDq(annSmWb, annUsedCacheQ); + igbe->anDq(annSmWb, annDescQ); + } curHead += wbOut; wbOut = 0; @@ -390,14 +521,19 @@ class IGbE : public EtherDevice oldHead, curHead); // If we still have more to wb, call wb now - intAfterWb(); + actionAfterWb(); if (moreToWb) { + moreToWb = false; DPRINTF(EthernetDesc, "Writeback has more todo\n"); writeback(wbAlignment); } if (!wbOut) { igbe->checkDrain(); + if (usedCache.size()) + igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT); + else + igbe->anWe(annSmWb, annUsedCacheQ); } fetchAfterWb(); } @@ -411,8 +547,8 @@ class IGbE : public EtherDevice int descLeft() const { int left = unusedCache.size(); - if (cachePnt - descTail() >= 0) - left += (cachePnt - descTail()); + if (cachePnt >= descTail()) + left += (descLen() - cachePnt + descTail()); else left += (descTail() - cachePnt); @@ -464,6 +600,16 @@ class IGbE : public EtherDevice arrayParamOut(os, csprintf("unusedCache_%d", x), (uint8_t*)unusedCache[x],sizeof(T)); } + + Tick fetch_delay = 0, wb_delay = 0; + if (fetchDelayEvent.scheduled()) + fetch_delay = fetchDelayEvent.when(); + SERIALIZE_SCALAR(fetch_delay); + if (wbDelayEvent.scheduled()) + wb_delay = wbDelayEvent.when(); + SERIALIZE_SCALAR(wb_delay); + + } virtual void unserialize(Checkpoint *cp, const std::string §ion) @@ -492,6 +638,15 @@ class IGbE : public EtherDevice (uint8_t*)temp,sizeof(T)); unusedCache.push_back(temp); } + Tick fetch_delay = 0, wb_delay = 0; + UNSERIALIZE_SCALAR(fetch_delay); + UNSERIALIZE_SCALAR(wb_delay); + if (fetch_delay) + igbe->schedule(fetchDelayEvent, fetch_delay); + if (wb_delay) + igbe->schedule(wbDelayEvent, wb_delay); + + } virtual bool hasOutstandingEvents() { return wbEvent.scheduled() || fetchEvent.scheduled(); @@ -516,6 +671,12 @@ class IGbE : public EtherDevice bool pktDone; + /** Variable to head with header/data completion events */ + int splitCount; + + /** Bytes of packet that have been copied, so we know when to set EOP */ + int bytesCopied; + public: RxDescCache(IGbE *i, std::string n, int s); @@ -523,20 +684,28 @@ class IGbE : public EtherDevice * descriptor and update the book keeping. Should only be called when * there are no dma's pending. * @param packet ethernet packet to write - * @return if the packet could be written (there was a free descriptor) + * @param pkt_offset bytes already copied from the packet to memory + * @return pkt_offset + number of bytes copied during this call */ - void writePacket(EthPacketPtr packet); + int writePacket(EthPacketPtr packet, int pkt_offset); + /** Called by event when dma to write packet is completed */ void pktComplete(); - /** Check if the dma on the packet has completed. + /** Check if the dma on the packet has completed and RX state machine + * can continue */ - bool packetDone(); EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent; + // Event to handle issuing header and data write at the same time + // and only callking pktComplete() when both are completed + void pktSplitDone(); + EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent; + EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent; + virtual bool hasOutstandingEvents(); virtual void serialize(std::ostream &os); @@ -555,15 +724,37 @@ class IGbE : public EtherDevice virtual long descLen() const { return igbe->regs.tdlen() >> 4; } virtual void updateHead(long h) { igbe->regs.tdh(h); } virtual void enableSm(); - virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW); } + virtual void actionAfterWb(); virtual void fetchAfterWb() { if (!igbe->txTick && igbe->getState() == SimObject::Running) fetchDescriptors(); } + + bool pktDone; bool isTcp; bool pktWaiting; + bool pktMultiDesc; + Addr completionAddress; + bool completionEnabled; + uint32_t descEnd; + + + // tso variables + bool useTso; + Addr tsoHeaderLen; + Addr tsoMss; + Addr tsoTotalLen; + Addr tsoUsedLen; + Addr tsoPrevSeq;; + Addr tsoPktPayloadBytes; + bool tsoLoadedHeader; + bool tsoPktHasHeader; + uint8_t tsoHeader[256]; + Addr tsoDescBytesUsed; + Addr tsoCopyBytes; + int tsoPkts; public: TxDescCache(IGbE *i, std::string n, int s); @@ -572,9 +763,15 @@ class IGbE : public EtherDevice * return the size the of the packet to reserve space in tx fifo. * @return size of the packet */ - int getPacketSize(); + int getPacketSize(EthPacketPtr p); void getPacketData(EthPacketPtr p); + void processContextDesc(); + /** Return the number of dsecriptors in a cache block for threshold + * operations. + */ + int descInBlock(int num_desc) { return num_desc / + igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); } /** Ask if the packet has been transfered so the state machine can give * it to the fifo. * @return packet available in descriptor cache @@ -586,13 +783,35 @@ class IGbE : public EtherDevice */ bool packetWaiting() { return pktWaiting; } + /** Ask if this packet is composed of multiple descriptors + * so even if we've got data, we need to wait for more before + * we can send it out. + * @return packet can't be sent out because it's a multi-descriptor + * packet + */ + bool packetMultiDesc() { return pktMultiDesc;} + /** Called by event when dma to write packet is completed */ void pktComplete(); EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent; + void headerComplete(); + EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent; + + + void completionWriteback(Addr a, bool enabled) { + DPRINTF(EthernetDesc, "Completion writeback Addr: %#x enabled: %d\n", + a, enabled); + completionAddress = a; + completionEnabled = enabled; + } + virtual bool hasOutstandingEvents(); + void nullCallback() { DPRINTF(EthernetDesc, "Completion writeback complete\n"); } + EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent; + virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); @@ -610,10 +829,12 @@ class IGbE : public EtherDevice } IGbE(const Params *params); ~IGbE() {} + virtual void init(); virtual EtherInt *getEthPort(const std::string &if_name, int idx); Tick clock; + Tick lastInterrupt; inline Tick ticks(int numCycles) const { return numCycles * clock; } virtual Tick read(PacketPtr pkt); diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index 91b3eacc9..4634dd9a3 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -59,11 +59,14 @@ const uint32_t REG_FCTTV = 0x00170; const uint32_t REG_TIPG = 0x00410; const uint32_t REG_AIFS = 0x00458; const uint32_t REG_LEDCTL = 0x00e00; +const uint32_t REG_EICR = 0x01580; +const uint32_t REG_IVAR0 = 0x01700; const uint32_t REG_FCRTL = 0x02160; const uint32_t REG_FCRTH = 0x02168; const uint32_t REG_RDBAL = 0x02800; const uint32_t REG_RDBAH = 0x02804; const uint32_t REG_RDLEN = 0x02808; +const uint32_t REG_SRRCTL = 0x0280C; const uint32_t REG_RDH = 0x02810; const uint32_t REG_RDT = 0x02818; const uint32_t REG_RDTR = 0x02820; @@ -74,12 +77,17 @@ const uint32_t REG_TDBAL = 0x03800; const uint32_t REG_TDBAH = 0x03804; const uint32_t REG_TDLEN = 0x03808; const uint32_t REG_TDH = 0x03810; +const uint32_t REG_TXDCA_CTL = 0x03814; const uint32_t REG_TDT = 0x03818; const uint32_t REG_TIDV = 0x03820; const uint32_t REG_TXDCTL = 0x03828; const uint32_t REG_TADV = 0x0382C; +const uint32_t REG_TDWBAL = 0x03838; +const uint32_t REG_TDWBAH = 0x0383C; const uint32_t REG_CRCERRS = 0x04000; const uint32_t REG_RXCSUM = 0x05000; +const uint32_t REG_RLPML = 0x05004; +const uint32_t REG_RFCTL = 0x05008; const uint32_t REG_MTA = 0x05200; const uint32_t REG_RAL = 0x05400; const uint32_t REG_RAH = 0x05404; @@ -87,6 +95,9 @@ const uint32_t REG_VFTA = 0x05600; const uint32_t REG_WUC = 0x05800; const uint32_t REG_MANC = 0x05820; +const uint32_t REG_SWSM = 0x05B50; +const uint32_t REG_FWSM = 0x05B54; +const uint32_t REG_SWFWSYNC = 0x05B5C; const uint8_t EEPROM_READ_OPCODE_SPI = 0x03; const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05; @@ -94,9 +105,9 @@ const uint8_t EEPROM_SIZE = 64; const uint16_t EEPROM_CSUM = 0xBABA; const uint8_t VLAN_FILTER_TABLE_SIZE = 128; -const uint8_t RCV_ADDRESS_TABLE_SIZE = 16; +const uint8_t RCV_ADDRESS_TABLE_SIZE = 24; const uint8_t MULTICAST_TABLE_SIZE = 128; -const uint32_t STATS_REGS_SIZE = 0x124; +const uint32_t STATS_REGS_SIZE = 0x228; // Registers in that are accessed in the PHY @@ -108,14 +119,17 @@ const uint8_t PHY_EPSTATUS = 15; const uint8_t PHY_AGC = 18; // Receive Descriptor Status Flags -const uint8_t RXDS_PIF = 0x80; -const uint8_t RXDS_IPCS = 0x40; -const uint8_t RXDS_TCPCS = 0x20; -const uint8_t RXDS_UDPCS = 0x10; -const uint8_t RXDS_VP = 0x08; -const uint8_t RXDS_IXSM = 0x04; -const uint8_t RXDS_EOP = 0x02; -const uint8_t RXDS_DD = 0x01; +const uint16_t RXDS_DYNINT = 0x800; +const uint16_t RXDS_UDPV = 0x400; +const uint16_t RXDS_CRCV = 0x100; +const uint16_t RXDS_PIF = 0x080; +const uint16_t RXDS_IPCS = 0x040; +const uint16_t RXDS_TCPCS = 0x020; +const uint16_t RXDS_UDPCS = 0x010; +const uint16_t RXDS_VP = 0x008; +const uint16_t RXDS_IXSM = 0x004; +const uint16_t RXDS_EOP = 0x002; +const uint16_t RXDS_DD = 0x001; // Receive Descriptor Error Flags const uint8_t RXDE_RXE = 0x80; @@ -125,6 +139,32 @@ const uint8_t RXDE_SEQ = 0x04; const uint8_t RXDE_SE = 0x02; const uint8_t RXDE_CE = 0x01; +// Receive Descriptor Extended Error Flags +const uint16_t RXDEE_HBO = 0x008; +const uint16_t RXDEE_CE = 0x010; +const uint16_t RXDEE_LE = 0x020; +const uint16_t RXDEE_PE = 0x080; +const uint16_t RXDEE_OSE = 0x100; +const uint16_t RXDEE_USE = 0x200; +const uint16_t RXDEE_TCPE = 0x400; +const uint16_t RXDEE_IPE = 0x800; + + +// Receive Descriptor Types +const uint8_t RXDT_LEGACY = 0x00; +const uint8_t RXDT_ADV_ONEBUF = 0x01; +const uint8_t RXDT_ADV_SPLIT_A = 0x05; + +// Receive Descriptor Packet Types +const uint16_t RXDP_IPV4 = 0x001; +const uint16_t RXDP_IPV4E = 0x002; +const uint16_t RXDP_IPV6 = 0x004; +const uint16_t RXDP_IPV6E = 0x008; +const uint16_t RXDP_TCP = 0x010; +const uint16_t RXDP_UDP = 0x020; +const uint16_t RXDP_SCTP = 0x040; +const uint16_t RXDP_NFS = 0x080; + // Interrupt types enum IntTypes { @@ -147,12 +187,38 @@ enum IntTypes // Receive Descriptor struct struct RxDesc { - Addr buf; - uint16_t len; - uint16_t csum; - uint8_t status; - uint8_t errors; - uint16_t vlan; + union { + struct { + Addr buf; + uint16_t len; + uint16_t csum; + uint8_t status; + uint8_t errors; + uint16_t vlan; + } legacy; + struct { + Addr pkt; + Addr hdr; + } adv_read; + struct { + uint16_t rss_type:4; + uint16_t pkt_type:12; + uint16_t __reserved1:5; + uint16_t header_len:10; + uint16_t sph:1; + union { + struct { + uint16_t id; + uint16_t csum; + }; + uint32_t rss_hash; + }; + uint32_t status:20; + uint32_t errors:12; + uint16_t pkt_len; + uint16_t vlan_tag; + } adv_wb ; + }; }; struct TxDesc { @@ -163,24 +229,33 @@ struct TxDesc { namespace TxdOp { const uint8_t TXD_CNXT = 0x0; const uint8_t TXD_DATA = 0x1; +const uint8_t TXD_ADVCNXT = 0x2; +const uint8_t TXD_ADVDATA = 0x3; bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); } uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); } -bool isContext(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_CNXT; } -bool isData(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_DATA; } +bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; } +bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); } +bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT); } +bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); } +bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); } Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; } Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); } -void setDd(TxDesc *d) -{ - replaceBits(d->d2, 35, 32, ULL(1)); -} +void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); } -bool ide(TxDesc *d) { return bits(d->d2, 31,31); } +bool ide(TxDesc *d) { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); } bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); } bool rs(TxDesc *d) { return bits(d->d2, 27,27); } bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); } -bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 26,26); } +bool tse(TxDesc *d) { + if (isTypes(d, TXD_CNXT, TXD_DATA)) + return bits(d->d2, 26,26); + if (isType(d, TXD_ADVDATA)) + return bits(d->d2, 31, 31); + return false; +} + bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); } bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); } bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); } @@ -199,7 +274,15 @@ int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); } int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); } int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); } int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); } -int hdrlen(TxDesc *d) { assert(isContext(d)); return bits(d->d2,47,40); } +int hdrlen(TxDesc *d) { + assert(isContext(d)); + if (!isAdvDesc(d)) + return bits(d->d2,47,40); + return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9); +} + +int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); } +int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); } } // namespace TxdOp @@ -303,8 +386,8 @@ struct Regs { struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register using Reg<uint32_t>::operator=; ADD_FIELD32(start,0,1); // start read - ADD_FIELD32(done,4,1); // done read - ADD_FIELD32(addr,8,8); // address + ADD_FIELD32(done,1,1); // done read + ADD_FIELD32(addr,2,14); // address ADD_FIELD32(data,16,16); // data }; EERD eerd; @@ -470,6 +553,17 @@ struct Regs { }; RDLEN rdlen; + struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(pktlen, 0, 8); + ADD_FIELD32(hdrlen, 8, 8); // guess based on header, not documented + ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv, + //101 hdr split + int bufLen() { return pktlen() << 10; } + int hdrLen() { return hdrlen() << 6; } + }; + SRRCTL srrctl; + struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register using Reg<uint32_t>::operator=; ADD_FIELD32(rdh,0,16); // head of the descriptor ring @@ -531,6 +625,14 @@ struct Regs { }; TDH tdh; + struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(cpu_mask, 0, 5); + ADD_FIELD32(enabled, 5,1); + ADD_FIELD32(relax_ordering, 6, 1); + }; + TXDCA_CTL txdca_ctl; + struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register using Reg<uint32_t>::operator=; ADD_FIELD32(tdt,0,16); // tail of the descriptor ring @@ -563,15 +665,42 @@ struct Regs { ADD_FIELD32(idv,0,16); // absolute interrupt delay }; TADV tadv; +/* + struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register + using Reg<uint64_t>::operator=; + ADD_FIELD64(en,0,1); // enable transmit description ring address writeback + ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback + ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring + }; + TDWBA tdwba;*/ + uint64_t tdwba; struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register using Reg<uint32_t>::operator=; ADD_FIELD32(pcss,0,8); ADD_FIELD32(ipofld,8,1); ADD_FIELD32(tuofld,9,1); + ADD_FIELD32(pcsd, 13,1); }; RXCSUM rxcsum; + uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size + + struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(iscsi_dis,0,1); + ADD_FIELD32(iscsi_dwc,1,5); + ADD_FIELD32(nfsw_dis,6,1); + ADD_FIELD32(nfsr_dis,7,1); + ADD_FIELD32(nfs_ver,8,2); + ADD_FIELD32(ipv6_dis,10,1); + ADD_FIELD32(ipv6xsum_dis,11,1); + ADD_FIELD32(ackdis,13,1); + ADD_FIELD32(ipfrsp_dis,14,1); + ADD_FIELD32(exsten,15,1); + }; + RFCTL rfctl; + struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register using Reg<uint32_t>::operator=; ADD_FIELD32(smbus,0,1); // SMBus enabled ##### @@ -604,6 +733,32 @@ struct Regs { }; MANC manc; + struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register + using Reg<uint32_t>::operator=; + ADD_FIELD32(smbi,0,1); // Semaphone bit + ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore + ADD_FIELD32(wmng, 2,1); // Wake MNG clock + ADD_FIELD32(reserved, 3, 29); + }; + SWSM swsm; + + struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register + using Reg<uint32_t>::operator=; + ADD_FIELD32(eep_fw_semaphore,0,1); + ADD_FIELD32(fw_mode, 1,3); + ADD_FIELD32(ide, 4,1); + ADD_FIELD32(sol, 5,1); + ADD_FIELD32(eep_roload, 6,1); + ADD_FIELD32(reserved, 7,8); + ADD_FIELD32(fw_val_bit, 15, 1); + ADD_FIELD32(reset_cnt, 16, 3); + ADD_FIELD32(ext_err_ind, 19, 6); + ADD_FIELD32(reserved2, 25, 7); + }; + FWSM fwsm; + + uint32_t sw_fw_sync; + void serialize(std::ostream &os) { paramOut(os, "ctrl", ctrl._data); @@ -624,6 +779,7 @@ struct Regs { paramOut(os, "fcrth", fcrth._data); paramOut(os, "rdba", rdba._data); paramOut(os, "rdlen", rdlen._data); + paramOut(os, "srrctl", srrctl._data); paramOut(os, "rdh", rdh._data); paramOut(os, "rdt", rdt._data); paramOut(os, "rdtr", rdtr._data); @@ -633,12 +789,20 @@ struct Regs { paramOut(os, "tdba", tdba._data); paramOut(os, "tdlen", tdlen._data); paramOut(os, "tdh", tdh._data); + paramOut(os, "txdca_ctl", txdca_ctl._data); paramOut(os, "tdt", tdt._data); paramOut(os, "tidv", tidv._data); paramOut(os, "txdctl", txdctl._data); paramOut(os, "tadv", tadv._data); + //paramOut(os, "tdwba", tdwba._data); + SERIALIZE_SCALAR(tdwba); paramOut(os, "rxcsum", rxcsum._data); + SERIALIZE_SCALAR(rlpml); + paramOut(os, "rfctl", rfctl._data); paramOut(os, "manc", manc._data); + paramOut(os, "swsm", swsm._data); + paramOut(os, "fwsm", fwsm._data); + SERIALIZE_SCALAR(sw_fw_sync); } void unserialize(Checkpoint *cp, const std::string §ion) @@ -661,6 +825,7 @@ struct Regs { paramIn(cp, section, "fcrth", fcrth._data); paramIn(cp, section, "rdba", rdba._data); paramIn(cp, section, "rdlen", rdlen._data); + paramIn(cp, section, "srrctl", srrctl._data); paramIn(cp, section, "rdh", rdh._data); paramIn(cp, section, "rdt", rdt._data); paramIn(cp, section, "rdtr", rdtr._data); @@ -670,12 +835,20 @@ struct Regs { paramIn(cp, section, "tdba", tdba._data); paramIn(cp, section, "tdlen", tdlen._data); paramIn(cp, section, "tdh", tdh._data); + paramIn(cp, section, "txdca_ctl", txdca_ctl._data); paramIn(cp, section, "tdt", tdt._data); paramIn(cp, section, "tidv", tidv._data); paramIn(cp, section, "txdctl", txdctl._data); paramIn(cp, section, "tadv", tadv._data); + UNSERIALIZE_SCALAR(tdwba); + //paramIn(cp, section, "tdwba", tdwba._data); paramIn(cp, section, "rxcsum", rxcsum._data); + UNSERIALIZE_SCALAR(rlpml); + paramIn(cp, section, "rfctl", rfctl._data); paramIn(cp, section, "manc", manc._data); + paramIn(cp, section, "swsm", swsm._data); + paramIn(cp, section, "fwsm", fwsm._data); + UNSERIALIZE_SCALAR(sw_fw_sync); } }; } // iGbReg namespace diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc index 6d7f1baf1..3d4e71888 100644 --- a/src/dev/ide_ctrl.cc +++ b/src/dev/ide_ctrl.cc @@ -30,203 +30,114 @@ * Miguel Serrano */ -#include <cstddef> -#include <cstdlib> #include <string> -#include <vector> #include "base/trace.hh" #include "cpu/intr_control.hh" #include "dev/ide_ctrl.hh" #include "dev/ide_disk.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" #include "params/IdeController.hh" -#include "sim/sim_object.hh" #include "sim/byteswap.hh" using namespace std; -//// -// Initialization and destruction -//// - -IdeController::IdeController(Params *p) - : PciDev(p) +// Bus master IDE registers +enum BMIRegOffset { + BMICommand = 0x0, + BMIStatus = 0x2, + BMIDescTablePtr = 0x4 +}; + +// PCI config space registers +enum ConfRegOffset { + PrimaryTiming = 0x40, + SecondaryTiming = 0x42, + DeviceTiming = 0x44, + UDMAControl = 0x48, + UDMATiming = 0x4A, + IDEConfig = 0x54 +}; + +static const uint16_t timeRegWithDecodeEn = 0x8000; + +IdeController::Channel::Channel( + string newName, Addr _cmdSize, Addr _ctrlSize) : + _name(newName), + cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize), + master(NULL), slave(NULL), selected(NULL) { - // initialize the PIO interface addresses - pri_cmd_addr = 0; - pri_cmd_size = BARSize[0]; - - pri_ctrl_addr = 0; - pri_ctrl_size = BARSize[1]; - - sec_cmd_addr = 0; - sec_cmd_size = BARSize[2]; - - sec_ctrl_addr = 0; - sec_ctrl_size = BARSize[3]; - - // initialize the bus master interface (BMI) address to be configured - // via PCI - bmi_addr = 0; - bmi_size = BARSize[4]; - - // zero out all of the registers - memset(bmi_regs.data, 0, sizeof(bmi_regs)); - memset(config_regs.data, 0, sizeof(config_regs.data)); - - // setup initial values - // enable both channels - config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); - config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); - bmi_regs.bmis0 = DMA1CAP | DMA0CAP; - bmi_regs.bmis1 = DMA1CAP | DMA0CAP; - - // reset all internal variables - io_enabled = false; - bm_enabled = false; - memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); - - // setup the disks attached to controller - memset(disks, 0, sizeof(disks)); - dev[0] = 0; - dev[1] = 0; - - if (params()->disks.size() > 3) - panic("IDE controllers support a maximum of 4 devices attached!\n"); - - for (int i = 0; i < params()->disks.size(); i++) { - disks[i] = params()->disks[i]; - disks[i]->setController(this); - } + memset(&bmiRegs, 0, sizeof(bmiRegs)); + bmiRegs.status.dmaCap0 = 1; + bmiRegs.status.dmaCap1 = 1; } -IdeController::~IdeController() +IdeController::Channel::~Channel() { - for (int i = 0; i < 4; i++) - if (disks[i]) - delete disks[i]; + delete master; + delete slave; } -//// -// Utility functions -/// - -void -IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type) -{ - offset = addr; - - if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { - offset -= pri_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = PRIMARY; - } else if (addr >= pri_ctrl_addr && - addr < (pri_ctrl_addr + pri_ctrl_size)) { - offset -= pri_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = PRIMARY; - } else if (addr >= sec_cmd_addr && - addr < (sec_cmd_addr + sec_cmd_size)) { - offset -= sec_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = SECONDARY; - } else if (addr >= sec_ctrl_addr && - addr < (sec_ctrl_addr + sec_ctrl_size)) { - offset -= sec_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = SECONDARY; - } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { - offset -= bmi_addr; - reg_type = BMI_BLOCK; - channel = (offset < BMIC1) ? PRIMARY : SECONDARY; - } else { - panic("IDE controller access to invalid address: %#x\n", addr); - } -} - -int -IdeController::getDisk(IdeChannel channel) +IdeController::IdeController(Params *p) + : PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]), + secondary(name() + ".secondary", BARSize[2], BARSize[3]), + bmiAddr(0), bmiSize(BARSize[4]), + primaryTiming(htole(timeRegWithDecodeEn)), + secondaryTiming(htole(timeRegWithDecodeEn)), + deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0), + ioEnabled(false), bmEnabled(false) { - int disk = 0; - uint8_t *devBit = &dev[0]; - - if (channel == SECONDARY) { - disk += 2; - devBit = &dev[1]; - } - - disk += *devBit; + if (params()->disks.size() > 3) + panic("IDE controllers support a maximum of 4 devices attached!\n"); - assert(*devBit == 0 || *devBit == 1); + // Assign the disks to channels + int numDisks = params()->disks.size(); + if (numDisks > 0) + primary.master = params()->disks[0]; + if (numDisks > 1) + primary.slave = params()->disks[1]; + if (numDisks > 2) + secondary.master = params()->disks[2]; + if (numDisks > 3) + secondary.slave = params()->disks[3]; - return disk; -} - -int -IdeController::getDisk(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) - return i; + for (int i = 0; i < params()->disks.size(); i++) { + params()->disks[i]->setController(this); } - return -1; + primary.select(false); + secondary.select(false); } bool IdeController::isDiskSelected(IdeDisk *diskPtr) { - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) { - // is disk is on primary or secondary channel - int channel = i/2; - // is disk the master or slave - int devID = i%2; - - return (dev[channel] == devID); - } - } - panic("Unable to find disk by pointer!!\n"); + return (primary.selected == diskPtr || secondary.selected == diskPtr); } -//// -// Command completion -//// +void +IdeController::intrPost() +{ + primary.bmiRegs.status.intStatus = 1; + PciDev::intrPost(); +} void IdeController::setDmaComplete(IdeDisk *disk) { - int diskNum = getDisk(disk); - - if (diskNum < 0) - panic("Unable to find disk based on pointer %#x\n", disk); - - if (diskNum < 2) { - // clear the start/stop bit in the command register - bmi_regs.bmic0 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis0 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis0 |= IDEINTS; + Channel *channel; + if (disk == primary.master || disk == primary.slave) { + channel = &primary; + } else if (disk == secondary.master || disk == secondary.slave) { + channel = &secondary; } else { - // clear the start/stop bit in the command register - bmi_regs.bmic1 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis1 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis1 |= IDEINTS; + panic("Unable to find disk based on pointer %#x\n", disk); } -} - -//// -// Read and write handling -//// + channel->bmiRegs.command.startStop = 0; + channel->bmiRegs.status.active = 0; + channel->bmiRegs.status.intStatus = 1; +} Tick IdeController::readConfig(PacketPtr pkt) @@ -236,30 +147,28 @@ IdeController::readConfig(PacketPtr pkt) return PciDev::readConfig(pkt); } - assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END); - pkt->allocate(); switch (pkt->getSize()) { case sizeof(uint8_t): switch (offset) { - case IDE_CTRL_CONF_DEV_TIMING: - pkt->set<uint8_t>(config_regs.sidetim); + case DeviceTiming: + pkt->set<uint8_t>(deviceTiming); break; - case IDE_CTRL_CONF_UDMA_CNTRL: - pkt->set<uint8_t>(config_regs.udmactl); + case UDMAControl: + pkt->set<uint8_t>(udmaControl); break; - case IDE_CTRL_CONF_PRIM_TIMING+1: - pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8); + case PrimaryTiming + 1: + pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8)); break; - case IDE_CTRL_CONF_SEC_TIMING+1: - pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8); + case SecondaryTiming + 1: + pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8)); break; - case IDE_CTRL_CONF_IDE_CONFIG: - pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF); + case IDEConfig: + pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0)); break; - case IDE_CTRL_CONF_IDE_CONFIG+1: - pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8); + case IDEConfig + 1: + pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8)); break; default: panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", @@ -270,17 +179,17 @@ IdeController::readConfig(PacketPtr pkt) break; case sizeof(uint16_t): switch (offset) { - case IDE_CTRL_CONF_PRIM_TIMING: - pkt->set<uint16_t>(config_regs.idetim0); + case PrimaryTiming: + pkt->set<uint16_t>(primaryTiming); break; - case IDE_CTRL_CONF_SEC_TIMING: - pkt->set<uint16_t>(config_regs.idetim1); + case SecondaryTiming: + pkt->set<uint16_t>(secondaryTiming); break; - case IDE_CTRL_CONF_UDMA_TIMING: - pkt->set<uint16_t>(config_regs.udmatim); + case UDMATiming: + pkt->set<uint16_t>(udmaTiming); break; - case IDE_CTRL_CONF_IDE_CONFIG: - pkt->set<uint16_t>(config_regs.ideconfig); + case IDEConfig: + pkt->set<uint16_t>(ideConfig); break; default: panic("Invalid PCI configuration read for size 2 offset: %#x!\n", @@ -309,48 +218,45 @@ IdeController::writeConfig(PacketPtr pkt) if (offset < PCI_DEVICE_SPECIFIC) { PciDev::writeConfig(pkt); } else { - assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END); - switch (pkt->getSize()) { case sizeof(uint8_t): switch (offset) { - case IDE_CTRL_CONF_DEV_TIMING: - config_regs.sidetim = pkt->get<uint8_t>(); + case DeviceTiming: + deviceTiming = pkt->get<uint8_t>(); break; - case IDE_CTRL_CONF_UDMA_CNTRL: - config_regs.udmactl = pkt->get<uint8_t>(); + case UDMAControl: + udmaControl = pkt->get<uint8_t>(); break; - case IDE_CTRL_CONF_IDE_CONFIG: - config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | - (pkt->get<uint8_t>()); + case IDEConfig: + replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>()); break; - case IDE_CTRL_CONF_IDE_CONFIG+1: - config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | - pkt->get<uint8_t>() << 8; + case IDEConfig + 1: + replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>()); break; default: - panic("Invalid PCI configuration write for size 1 offset: %#x!\n", - offset); + panic("Invalid PCI configuration write " + "for size 1 offset: %#x!\n", offset); } DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", offset, (uint32_t)pkt->get<uint8_t>()); break; case sizeof(uint16_t): switch (offset) { - case IDE_CTRL_CONF_PRIM_TIMING: - config_regs.idetim0 = pkt->get<uint16_t>(); + case PrimaryTiming: + primaryTiming = pkt->get<uint16_t>(); break; - case IDE_CTRL_CONF_SEC_TIMING: - config_regs.idetim1 = pkt->get<uint16_t>(); + case SecondaryTiming: + secondaryTiming = pkt->get<uint16_t>(); break; - case IDE_CTRL_CONF_UDMA_TIMING: - config_regs.udmatim = pkt->get<uint16_t>(); + case UDMATiming: + udmaTiming = pkt->get<uint16_t>(); break; - case IDE_CTRL_CONF_IDE_CONFIG: - config_regs.ideconfig = pkt->get<uint16_t>(); + case IDEConfig: + ideConfig = pkt->get<uint16_t>(); break; default: - panic("Invalid PCI configuration write for size 2 offset: %#x!\n", + panic("Invalid PCI configuration write " + "for size 2 offset: %#x!\n", offset); } DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", @@ -370,317 +276,223 @@ IdeController::writeConfig(PacketPtr pkt) switch(offset) { case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) - pri_cmd_addr = BARAddrs[0]; + primary.cmdAddr = BARAddrs[0]; break; case PCI0_BASE_ADDR1: if (BARAddrs[1] != 0) - pri_ctrl_addr = BARAddrs[1]; + primary.ctrlAddr = BARAddrs[1]; break; case PCI0_BASE_ADDR2: if (BARAddrs[2] != 0) - sec_cmd_addr = BARAddrs[2]; + secondary.cmdAddr = BARAddrs[2]; break; case PCI0_BASE_ADDR3: if (BARAddrs[3] != 0) - sec_ctrl_addr = BARAddrs[3]; + secondary.ctrlAddr = BARAddrs[3]; break; case PCI0_BASE_ADDR4: if (BARAddrs[4] != 0) - bmi_addr = BARAddrs[4]; + bmiAddr = BARAddrs[4]; break; case PCI_COMMAND: - if (letoh(config.command) & PCI_CMD_IOSE) - io_enabled = true; - else - io_enabled = false; - - if (letoh(config.command) & PCI_CMD_BME) - bm_enabled = true; - else - bm_enabled = false; + ioEnabled = (config.command & htole(PCI_CMD_IOSE)); + bmEnabled = (config.command & htole(PCI_CMD_BME)); break; } return configDelay; } - -Tick -IdeController::read(PacketPtr pkt) +void +IdeController::Channel::accessCommand(Addr offset, + int size, uint8_t *data, bool read) { - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - - pkt->allocate(); - if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) - panic("Bad IDE read size: %d\n", pkt->getSize()); - - parseAddr(pkt->getAddr(), offset, channel, reg_type); - - if (!io_enabled) { - pkt->makeAtomicResponse(); - return pioDelay; - } - - switch (reg_type) { - case BMI_BLOCK: - switch (pkt->getSize()) { - case sizeof(uint8_t): - pkt->set(bmi_regs.data[offset]); - break; - case sizeof(uint16_t): - pkt->set(*(uint16_t*)&bmi_regs.data[offset]); - break; - case sizeof(uint32_t): - pkt->set(*(uint32_t*)&bmi_regs.data[offset]); - break; - default: - panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize()); - } - break; - - case COMMAND_BLOCK: - case CONTROL_BLOCK: - disk = getDisk(channel); + const Addr SelectOffset = 6; + const uint8_t SelectDevBit = 0x10; - if (disks[disk] == NULL) { - pkt->set<uint8_t>(0); - break; - } + if (!read && offset == SelectOffset) + select(*data & SelectDevBit); - switch (offset) { - case DATA_OFFSET: - switch (pkt->getSize()) { - case sizeof(uint16_t): - disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); - break; - - case sizeof(uint32_t): - disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); - disks[disk]->read(offset, reg_type, - pkt->getPtr<uint8_t>() + sizeof(uint16_t)); - break; - - default: - panic("IDE read of data reg invalid size: %#x\n", pkt->getSize()); - } - break; - default: - if (pkt->getSize() == sizeof(uint8_t)) { - disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); - } else - panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize()); - } - break; - default: - panic("IDE controller read of unknown register block type!\n"); + if (selected == NULL) { + assert(size == sizeof(uint8_t)); + *data = 0; + } else if (read) { + selected->readCommand(offset, size, data); + } else { + selected->writeCommand(offset, size, data); } - if (pkt->getSize() == 1) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); - else if (pkt->getSize() == 2) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get<uint16_t>()); - else - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get<uint32_t>()); - - pkt->makeAtomicResponse(); - return pioDelay; } -Tick -IdeController::write(PacketPtr pkt) +void +IdeController::Channel::accessControl(Addr offset, + int size, uint8_t *data, bool read) { - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - uint8_t oldVal, newVal; - - parseAddr(pkt->getAddr(), offset, channel, reg_type); - - if (!io_enabled) { - pkt->makeAtomicResponse(); - DPRINTF(IdeCtrl, "io not enabled\n"); - return pioDelay; + if (selected == NULL) { + assert(size == sizeof(uint8_t)); + *data = 0; + } else if (read) { + selected->readControl(offset, size, data); + } else { + selected->writeControl(offset, size, data); } +} - switch (reg_type) { - case BMI_BLOCK: - if (!bm_enabled) { - pkt->makeAtomicResponse(); - return pioDelay; - } - +void +IdeController::Channel::accessBMI(Addr offset, + int size, uint8_t *data, bool read) +{ + assert(offset + size <= sizeof(BMIRegs)); + if (read) { + memcpy(data, (uint8_t *)&bmiRegs + offset, size); + } else { switch (offset) { - // Bus master IDE command register - case BMIC1: - case BMIC0: - if (pkt->getSize() != sizeof(uint8_t)) - panic("Invalid BMIC write size: %x\n", pkt->getSize()); - - // select the current disk based on DEV bit - disk = getDisk(channel); - - oldVal = bmi_regs.chan[channel].bmic; - newVal = pkt->get<uint8_t>(); - - // if a DMA transfer is in progress, R/W control cannot change - if (oldVal & SSBM) { - if ((oldVal & RWCON) ^ (newVal & RWCON)) { - (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; - } - } - - // see if the start/stop bit is being changed - if ((oldVal & SSBM) ^ (newVal & SSBM)) { - if (oldVal & SSBM) { - // stopping DMA transfer - DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + case BMICommand: + { + if (size != sizeof(uint8_t)) + panic("Invalid BMIC write size: %x\n", size); - // clear the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis & ~BMIDEA; + BMICommandReg oldVal = bmiRegs.command; + BMICommandReg newVal = *data; - if (disks[disk] == NULL) - panic("DMA stop for disk %d which does not exist\n", - disk); + // if a DMA transfer is in progress, R/W control cannot change + if (oldVal.startStop && oldVal.rw != newVal.rw) + oldVal.rw = newVal.rw; - // inform the disk of the DMA transfer abort - disks[disk]->abortDma(); - } else { - // starting DMA transfer - DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + if (oldVal.startStop != newVal.startStop) { + if (selected == NULL) + panic("DMA start for disk which does not exist\n"); - // set the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis | BMIDEA; + if (oldVal.startStop) { + DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + bmiRegs.status.active = 0; - if (disks[disk] == NULL) - panic("DMA start for disk %d which does not exist\n", - disk); + selected->abortDma(); + } else { + DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + bmiRegs.status.active = 1; - // inform the disk of the DMA transfer start - disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); + selected->startDma(letoh(bmiRegs.bmidtp)); + } } - } - - // update the register value - bmi_regs.chan[channel].bmic = newVal; - break; - - // Bus master IDE status register - case BMIS0: - case BMIS1: - if (pkt->getSize() != sizeof(uint8_t)) - panic("Invalid BMIS write size: %x\n", pkt->getSize()); - - oldVal = bmi_regs.chan[channel].bmis; - newVal = pkt->get<uint8_t>(); - - // the BMIDEA bit is RO - newVal |= (oldVal & BMIDEA); - // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each - if ((oldVal & IDEINTS) && (newVal & IDEINTS)) - newVal &= ~IDEINTS; // clear the interrupt? - else - (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; - - if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) - newVal &= ~IDEDMAE; - else - (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; - - bmi_regs.chan[channel].bmis = newVal; + bmiRegs.command = newVal; + } break; - - // Bus master IDE descriptor table pointer register - case BMIDTP0: - case BMIDTP1: + case BMIStatus: { - if (pkt->getSize() != sizeof(uint32_t)) - panic("Invalid BMIDTP write size: %x\n", pkt->getSize()); - - bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3); + if (size != sizeof(uint8_t)) + panic("Invalid BMIS write size: %x\n", size); + + BMIStatusReg oldVal = bmiRegs.status; + BMIStatusReg newVal = *data; + + // the BMIDEA bit is read only + newVal.active = oldVal.active; + + // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each + if (oldVal.intStatus && newVal.intStatus) + newVal.intStatus = 0; // clear the interrupt? + else + newVal.intStatus = oldVal.intStatus; + if (oldVal.dmaError && newVal.dmaError) + newVal.dmaError = 0; + else + newVal.dmaError = oldVal.dmaError; + + bmiRegs.status = newVal; } break; - + case BMIDescTablePtr: + if (size != sizeof(uint32_t)) + panic("Invalid BMIDTP write size: %x\n", size); + bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3); + break; default: - if (pkt->getSize() != sizeof(uint8_t) && - pkt->getSize() != sizeof(uint16_t) && - pkt->getSize() != sizeof(uint32_t)) - panic("IDE controller write of invalid write size: %x\n", - pkt->getSize()); - - // do a default copy of data into the registers - memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize()); + if (size != sizeof(uint8_t) && size != sizeof(uint16_t) && + size != sizeof(uint32_t)) + panic("IDE controller write of invalid write size: %x\n", size); + memcpy((uint8_t *)&bmiRegs + offset, data, size); } - break; - case COMMAND_BLOCK: - if (offset == IDE_SELECT_OFFSET) { - uint8_t *devBit = &dev[channel]; - *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0; - } - // fall-through ok! - case CONTROL_BLOCK: - disk = getDisk(channel); + } +} - if (disks[disk] == NULL) - break; +void +IdeController::dispatchAccess(PacketPtr pkt, bool read) +{ + pkt->allocate(); + if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) + panic("Bad IDE read size: %d\n", pkt->getSize()); - switch (offset) { - case DATA_OFFSET: - switch (pkt->getSize()) { - case sizeof(uint16_t): - disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); - break; + if (!ioEnabled) { + pkt->makeAtomicResponse(); + DPRINTF(IdeCtrl, "io not enabled\n"); + return; + } - case sizeof(uint32_t): - disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); - disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() + - sizeof(uint16_t)); - break; - default: - panic("IDE write of data reg invalid size: %#x\n", pkt->getSize()); - } - break; - default: - if (pkt->getSize() == sizeof(uint8_t)) { - disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); - } else - panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize()); + Addr addr = pkt->getAddr(); + int size = pkt->getSize(); + uint8_t *dataPtr = pkt->getPtr<uint8_t>(); + + if (addr >= primary.cmdAddr && + addr < (primary.cmdAddr + primary.cmdSize)) { + addr -= primary.cmdAddr; + primary.accessCommand(addr, size, dataPtr, read); + } else if (addr >= primary.ctrlAddr && + addr < (primary.ctrlAddr + primary.ctrlSize)) { + addr -= primary.ctrlAddr; + primary.accessControl(addr, size, dataPtr, read); + } else if (addr >= secondary.cmdAddr && + addr < (secondary.cmdAddr + secondary.cmdSize)) { + addr -= secondary.cmdAddr; + secondary.accessCommand(addr, size, dataPtr, read); + } else if (addr >= secondary.ctrlAddr && + addr < (secondary.ctrlAddr + secondary.ctrlSize)) { + addr -= secondary.ctrlAddr; + secondary.accessControl(addr, size, dataPtr, read); + } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) { + if (!read && !bmEnabled) + return; + addr -= bmiAddr; + if (addr < sizeof(Channel::BMIRegs)) { + primary.accessBMI(addr, size, dataPtr, read); + } else { + addr -= sizeof(Channel::BMIRegs); + secondary.accessBMI(addr, size, dataPtr, read); } - break; - default: - panic("IDE controller write of unknown register block type!\n"); + } else { + panic("IDE controller access to invalid address: %#x\n", addr); } + uint32_t data; if (pkt->getSize() == 1) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); + data = pkt->get<uint8_t>(); else if (pkt->getSize() == 2) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get<uint16_t>()); + data = pkt->get<uint16_t>(); else - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get<uint32_t>()); - + data = pkt->get<uint32_t>(); + DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n", + read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data); pkt->makeAtomicResponse(); +} + +Tick +IdeController::read(PacketPtr pkt) +{ + dispatchAccess(pkt, true); return pioDelay; } -//// -// Serialization -//// +Tick +IdeController::write(PacketPtr pkt) +{ + dispatchAccess(pkt, false); + return pioDelay; +} void IdeController::serialize(std::ostream &os) @@ -688,30 +500,40 @@ IdeController::serialize(std::ostream &os) // Serialize the PciDev base class PciDev::serialize(os); - // Serialize register addresses and sizes - SERIALIZE_SCALAR(pri_cmd_addr); - SERIALIZE_SCALAR(pri_cmd_size); - SERIALIZE_SCALAR(pri_ctrl_addr); - SERIALIZE_SCALAR(pri_ctrl_size); - SERIALIZE_SCALAR(sec_cmd_addr); - SERIALIZE_SCALAR(sec_cmd_size); - SERIALIZE_SCALAR(sec_ctrl_addr); - SERIALIZE_SCALAR(sec_ctrl_size); - SERIALIZE_SCALAR(bmi_addr); - SERIALIZE_SCALAR(bmi_size); - - // Serialize registers - SERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - SERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); + // Serialize channels + primary.serialize("primary", os); + secondary.serialize("secondary", os); + + // Serialize config registers + SERIALIZE_SCALAR(primaryTiming); + SERIALIZE_SCALAR(secondaryTiming); + SERIALIZE_SCALAR(deviceTiming); + SERIALIZE_SCALAR(udmaControl); + SERIALIZE_SCALAR(udmaTiming); + SERIALIZE_SCALAR(ideConfig); // Serialize internal state - SERIALIZE_SCALAR(io_enabled); - SERIALIZE_SCALAR(bm_enabled); - SERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + SERIALIZE_SCALAR(ioEnabled); + SERIALIZE_SCALAR(bmEnabled); + SERIALIZE_SCALAR(bmiAddr); + SERIALIZE_SCALAR(bmiSize); +} + +void +IdeController::Channel::serialize(const std::string &base, std::ostream &os) +{ + paramOut(os, base + ".cmdAddr", cmdAddr); + paramOut(os, base + ".cmdSize", cmdSize); + paramOut(os, base + ".ctrlAddr", ctrlAddr); + paramOut(os, base + ".ctrlSize", ctrlSize); + uint8_t command = bmiRegs.command; + paramOut(os, base + ".bmiRegs.command", command); + paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0); + uint8_t status = bmiRegs.status; + paramOut(os, base + ".bmiRegs.status", status); + paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1); + paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); + paramOut(os, base + ".selectBit", selectBit); } void @@ -720,30 +542,44 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) // Unserialize the PciDev base class PciDev::unserialize(cp, section); - // Unserialize register addresses and sizes - UNSERIALIZE_SCALAR(pri_cmd_addr); - UNSERIALIZE_SCALAR(pri_cmd_size); - UNSERIALIZE_SCALAR(pri_ctrl_addr); - UNSERIALIZE_SCALAR(pri_ctrl_size); - UNSERIALIZE_SCALAR(sec_cmd_addr); - UNSERIALIZE_SCALAR(sec_cmd_size); - UNSERIALIZE_SCALAR(sec_ctrl_addr); - UNSERIALIZE_SCALAR(sec_ctrl_size); - UNSERIALIZE_SCALAR(bmi_addr); - UNSERIALIZE_SCALAR(bmi_size); - - // Unserialize registers - UNSERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - UNSERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); + // Unserialize channels + primary.unserialize("primary", cp, section); + secondary.unserialize("secondary", cp, section); + + // Unserialize config registers + UNSERIALIZE_SCALAR(primaryTiming); + UNSERIALIZE_SCALAR(secondaryTiming); + UNSERIALIZE_SCALAR(deviceTiming); + UNSERIALIZE_SCALAR(udmaControl); + UNSERIALIZE_SCALAR(udmaTiming); + UNSERIALIZE_SCALAR(ideConfig); // Unserialize internal state - UNSERIALIZE_SCALAR(io_enabled); - UNSERIALIZE_SCALAR(bm_enabled); - UNSERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + UNSERIALIZE_SCALAR(ioEnabled); + UNSERIALIZE_SCALAR(bmEnabled); + UNSERIALIZE_SCALAR(bmiAddr); + UNSERIALIZE_SCALAR(bmiSize); +} + +void +IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion) +{ + paramIn(cp, section, base + ".cmdAddr", cmdAddr); + paramIn(cp, section, base + ".cmdSize", cmdSize); + paramIn(cp, section, base + ".ctrlAddr", ctrlAddr); + paramIn(cp, section, base + ".ctrlSize", ctrlSize); + uint8_t command; + paramIn(cp, section, base +".bmiRegs.command", command); + bmiRegs.command = command; + paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0); + uint8_t status; + paramIn(cp, section, base + ".bmiRegs.status", status); + bmiRegs.status = status; + paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1); + paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); + paramIn(cp, section, base + ".selectBit", selectBit); + select(selectBit); } IdeController * diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh index f22d83e9c..89dc1ee9d 100644 --- a/src/dev/ide_ctrl.hh +++ b/src/dev/ide_ctrl.hh @@ -37,61 +37,13 @@ #ifndef __IDE_CTRL_HH__ #define __IDE_CTRL_HH__ +#include "base/bitunion.hh" #include "dev/pcidev.hh" #include "dev/pcireg.h" #include "dev/io_device.hh" #include "params/IdeController.hh" -#define BMIC0 0x0 // Bus master IDE command register -#define BMIS0 0x2 // Bus master IDE status register -#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register -#define BMIC1 0x8 // Bus master IDE command register -#define BMIS1 0xa // Bus master IDE status register -#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register - -// Bus master IDE command register bit fields -#define RWCON 0x08 // Bus master read/write control -#define SSBM 0x01 // Start/stop bus master - -// Bus master IDE status register bit fields -#define DMA1CAP 0x40 // Drive 1 DMA capable -#define DMA0CAP 0x20 // Drive 0 DMA capable -#define IDEINTS 0x04 // IDE Interrupt Status -#define IDEDMAE 0x02 // IDE DMA error -#define BMIDEA 0x01 // Bus master IDE active - -// IDE Command byte fields -#define IDE_SELECT_OFFSET (6) -#define IDE_SELECT_DEV_BIT 0x10 - -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -// IDE Timing Register bit fields -#define IDETIM_DECODE_EN 0x8000 - -// PCI device specific register byte offsets -#define IDE_CTRL_CONF_START 0x40 -#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) - -#define IDE_CTRL_CONF_PRIM_TIMING 0x40 -#define IDE_CTRL_CONF_SEC_TIMING 0x42 -#define IDE_CTRL_CONF_DEV_TIMING 0x44 -#define IDE_CTRL_CONF_UDMA_CNTRL 0x48 -#define IDE_CTRL_CONF_UDMA_TIMING 0x4A -#define IDE_CTRL_CONF_IDE_CONFIG 0x54 - - -enum IdeRegType { - COMMAND_BLOCK, - CONTROL_BLOCK, - BMI_BLOCK -}; - class IdeDisk; -class IntrControl; -class PciConfigAll; -class Platform; /** * Device model for an Intel PIIX4 IDE controller @@ -99,137 +51,109 @@ class Platform; class IdeController : public PciDev { - friend class IdeDisk; + private: + // Bus master IDE status register bit fields + BitUnion8(BMIStatusReg) + Bitfield<6> dmaCap0; + Bitfield<5> dmaCap1; + Bitfield<2> intStatus; + Bitfield<1> dmaError; + Bitfield<0> active; + EndBitUnion(BMIStatusReg) + + BitUnion8(BMICommandReg) + Bitfield<3> rw; + Bitfield<0> startStop; + EndBitUnion(BMICommandReg) + + struct Channel + { + std::string _name; + + const std::string + name() + { + return _name; + } + + /** Command and control block registers */ + Addr cmdAddr, cmdSize, ctrlAddr, ctrlSize; + + /** Registers used for bus master interface */ + struct BMIRegs + { + BMICommandReg command; + uint8_t reserved0; + BMIStatusReg status; + uint8_t reserved1; + uint32_t bmidtp; + } bmiRegs; - enum IdeChannel { - PRIMARY = 0, - SECONDARY = 1 - }; + /** IDE disks connected to this controller */ + IdeDisk *master, *slave; - private: - /** Primary command block registers */ - Addr pri_cmd_addr; - Addr pri_cmd_size; - /** Primary control block registers */ - Addr pri_ctrl_addr; - Addr pri_ctrl_size; - /** Secondary command block registers */ - Addr sec_cmd_addr; - Addr sec_cmd_size; - /** Secondary control block registers */ - Addr sec_ctrl_addr; - Addr sec_ctrl_size; - /** Bus master interface (BMI) registers */ - Addr bmi_addr; - Addr bmi_size; + /** Currently selected disk */ + IdeDisk *selected; - private: - /** Registers used for bus master interface */ - union { - uint8_t data[16]; - - struct { - uint8_t bmic0; - uint8_t reserved_0; - uint8_t bmis0; - uint8_t reserved_1; - uint32_t bmidtp0; - uint8_t bmic1; - uint8_t reserved_2; - uint8_t bmis1; - uint8_t reserved_3; - uint32_t bmidtp1; - }; - - struct { - uint8_t bmic; - uint8_t reserved_4; - uint8_t bmis; - uint8_t reserved_5; - uint32_t bmidtp; - } chan[2]; + bool selectBit; - } bmi_regs; - /** Shadows of the device select bit */ - uint8_t dev[2]; - /** Registers used in device specific PCI configuration */ - union { - uint8_t data[22]; - - struct { - uint16_t idetim0; - uint16_t idetim1; - uint8_t sidetim; - uint8_t reserved_0[3]; - uint8_t udmactl; - uint8_t reserved_1; - uint16_t udmatim; - uint8_t reserved_2[8]; - uint16_t ideconfig; - }; - } config_regs; + void + select(bool selSlave) + { + selectBit = selSlave; + selected = selectBit ? slave : master; + } - // Internal management variables - bool io_enabled; - bool bm_enabled; - bool cmd_in_progress[4]; + void accessCommand(Addr offset, int size, uint8_t *data, bool read); + void accessControl(Addr offset, int size, uint8_t *data, bool read); + void accessBMI(Addr offset, int size, uint8_t *data, bool read); - private: - /** IDE disks connected to controller */ - IdeDisk *disks[4]; + Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize); + ~Channel(); - private: - /** Parse the access address to pass on to device */ - void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type); + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; - /** Select the disk based on the channel and device bit */ - int getDisk(IdeChannel channel); + Channel primary; + Channel secondary; - /** Select the disk based on a pointer */ - int getDisk(IdeDisk *diskPtr); + /** Bus master interface (BMI) registers */ + Addr bmiAddr, bmiSize; - public: - /** See if a disk is selected based on its pointer */ - bool isDiskSelected(IdeDisk *diskPtr); + /** Registers used in device specific PCI configuration */ + uint16_t primaryTiming, secondaryTiming; + uint8_t deviceTiming; + uint8_t udmaControl; + uint16_t udmaTiming; + uint16_t ideConfig; + + // Internal management variables + bool ioEnabled; + bool bmEnabled; + + void dispatchAccess(PacketPtr pkt, bool read); public: typedef IdeControllerParams Params; const Params *params() const { return (const Params *)_params; } IdeController(Params *p); - ~IdeController(); - virtual Tick writeConfig(PacketPtr pkt); - virtual Tick readConfig(PacketPtr pkt); + /** See if a disk is selected based on its pointer */ + bool isDiskSelected(IdeDisk *diskPtr); + + void intrPost(); + + Tick writeConfig(PacketPtr pkt); + Tick readConfig(PacketPtr pkt); void setDmaComplete(IdeDisk *disk); - /** - * Read a done field for a given target. - * @param pkt Packet describing what is to be read - * @return The amount of time to complete this request - */ - virtual Tick read(PacketPtr pkt); - - /** - * Write a done field for a given target. - * @param pkt Packet describing what is to be written - * @return The amount of time to complete this request - */ - virtual Tick write(PacketPtr pkt); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); + Tick read(PacketPtr pkt); + Tick write(PacketPtr pkt); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); }; #endif // __IDE_CTRL_HH_ diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc index 8f9999beb..83faf508e 100644 --- a/src/dev/ide_disk.cc +++ b/src/dev/ide_disk.cc @@ -177,7 +177,7 @@ Addr IdeDisk::pciToDma(Addr pciAddr) { if (ctrl) - return ctrl->plat->pciToDma(pciAddr); + return ctrl->pciToDma(pciAddr); else panic("Access to unset controller!\n"); } @@ -187,120 +187,127 @@ IdeDisk::pciToDma(Addr pciAddr) //// void -IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) +IdeDisk::readCommand(const Addr offset, int size, uint8_t *data) { - DevAction_t action = ACT_NONE; - - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - // Data transfers occur two bytes at a time - case DATA_OFFSET: - *(uint16_t*)data = cmdReg.data; - action = ACT_DATA_READ_SHORT; - break; - case ERROR_OFFSET: - *data = cmdReg.error; - break; - case NSECTOR_OFFSET: - *data = cmdReg.sec_count; - break; - case SECTOR_OFFSET: - *data = cmdReg.sec_num; - break; - case LCYL_OFFSET: - *data = cmdReg.cyl_low; - break; - case HCYL_OFFSET: - *data = cmdReg.cyl_high; - break; - case DRIVE_OFFSET: - *data = cmdReg.drive; - break; - case STATUS_OFFSET: - *data = status; - action = ACT_STAT_READ; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); + if (offset == DATA_OFFSET) { + if (size == sizeof(uint16_t)) { + *(uint16_t *)data = cmdReg.data; + } else if (size == sizeof(uint32_t)) { + *(uint16_t *)data = cmdReg.data; + updateState(ACT_DATA_READ_SHORT); + *((uint16_t *)data + 1) = cmdReg.data; + } else { + panic("Data read of unsupported size %d.\n", size); } + updateState(ACT_DATA_READ_SHORT); + return; + } + assert(size == sizeof(uint8_t)); + switch (offset) { + case ERROR_OFFSET: + *data = cmdReg.error; break; - case CONTROL_BLOCK: - if (offset == ALTSTAT_OFFSET) - *data = status; - else - panic("Invalid IDE control register offset: %#x\n", offset); + case NSECTOR_OFFSET: + *data = cmdReg.sec_count; + break; + case SECTOR_OFFSET: + *data = cmdReg.sec_num; + break; + case LCYL_OFFSET: + *data = cmdReg.cyl_low; + break; + case HCYL_OFFSET: + *data = cmdReg.cyl_high; + break; + case DRIVE_OFFSET: + *data = cmdReg.drive; + break; + case STATUS_OFFSET: + *data = status; + updateState(ACT_STAT_READ); break; default: - panic("Unknown register block!\n"); + panic("Invalid IDE command register offset: %#x\n", offset); } - DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, - (uint32_t)*data); - - if (action != ACT_NONE) - updateState(action); + DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); } void -IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) +IdeDisk::readControl(const Addr offset, int size, uint8_t *data) { - DevAction_t action = ACT_NONE; + assert(size == sizeof(uint8_t)); + *data = status; + if (offset != ALTSTAT_OFFSET) + panic("Invalid IDE control register offset: %#x\n", offset); + DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); +} - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - case DATA_OFFSET: - cmdReg.data = *(uint16_t*)data; - action = ACT_DATA_WRITE_SHORT; - break; - case FEATURES_OFFSET: - break; - case NSECTOR_OFFSET: - cmdReg.sec_count = *data; - break; - case SECTOR_OFFSET: - cmdReg.sec_num = *data; - break; - case LCYL_OFFSET: - cmdReg.cyl_low = *data; - break; - case HCYL_OFFSET: - cmdReg.cyl_high = *data; - break; - case DRIVE_OFFSET: - cmdReg.drive = *data; - action = ACT_SELECT_WRITE; - break; - case COMMAND_OFFSET: - cmdReg.command = *data; - action = ACT_CMD_WRITE; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); +void +IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data) +{ + if (offset == DATA_OFFSET) { + if (size == sizeof(uint16_t)) { + cmdReg.data = *(const uint16_t *)data; + } else if (size == sizeof(uint32_t)) { + cmdReg.data = *(const uint16_t *)data; + updateState(ACT_DATA_WRITE_SHORT); + cmdReg.data = *((const uint16_t *)data + 1); + } else { + panic("Data write of unsupported size %d.\n", size); } + updateState(ACT_DATA_WRITE_SHORT); + return; + } + + assert(size == sizeof(uint8_t)); + switch (offset) { + case FEATURES_OFFSET: break; - case CONTROL_BLOCK: - if (offset == CONTROL_OFFSET) { - if (*data & CONTROL_RST_BIT) { - // force the device into the reset state - devState = Device_Srst; - action = ACT_SRST_SET; - } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) - action = ACT_SRST_CLEAR; - - nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; - } - else - panic("Invalid IDE control register offset: %#x\n", offset); + case NSECTOR_OFFSET: + cmdReg.sec_count = *data; + break; + case SECTOR_OFFSET: + cmdReg.sec_num = *data; + break; + case LCYL_OFFSET: + cmdReg.cyl_low = *data; + break; + case HCYL_OFFSET: + cmdReg.cyl_high = *data; + break; + case DRIVE_OFFSET: + cmdReg.drive = *data; + updateState(ACT_SELECT_WRITE); + break; + case COMMAND_OFFSET: + cmdReg.command = *data; + updateState(ACT_CMD_WRITE); break; default: - panic("Unknown register block!\n"); + panic("Invalid IDE command register offset: %#x\n", offset); } + DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, + (uint32_t)*data); +} + +void +IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data) +{ + if (offset != CONTROL_OFFSET) + panic("Invalid IDE control register offset: %#x\n", offset); + + if (*data & CONTROL_RST_BIT) { + // force the device into the reset state + devState = Device_Srst; + updateState(ACT_SRST_SET); + } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { + updateState(ACT_SRST_CLEAR); + } + + nIENBit = *data & CONTROL_IEN_BIT; DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, (uint32_t)*data); - if (action != ACT_NONE) - updateState(action); } //// @@ -315,7 +322,7 @@ IdeDisk::doDmaTransfer() dmaState, devState); if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { - dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + schedule(dmaTransferEvent, curTick + DMA_BACKOFF_PERIOD); return; } else ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, @@ -349,7 +356,7 @@ IdeDisk::doDmaDataRead() DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", diskDelay, totalDiskDelay); - dmaReadWaitEvent.schedule(curTick + totalDiskDelay); + schedule(dmaReadWaitEvent, curTick + totalDiskDelay); } void @@ -395,7 +402,7 @@ IdeDisk::doDmaRead() } if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { - dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + schedule(dmaReadWaitEvent, curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaReadCG->done()) { assert(dmaReadCG->complete() < MAX_DMA_SIZE); @@ -457,7 +464,7 @@ IdeDisk::doDmaDataWrite() cmdBytesLeft -= SectorSize; } - dmaWriteWaitEvent.schedule(curTick + totalDiskDelay); + schedule(dmaWriteWaitEvent, curTick + totalDiskDelay); } void @@ -470,7 +477,7 @@ IdeDisk::doDmaWrite() curPrd.getByteCount(), TheISA::PageBytes); } if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { - dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + schedule(dmaWriteWaitEvent, curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaWriteCG->done()) { assert(dmaWriteCG->complete() < MAX_DMA_SIZE); @@ -545,7 +552,7 @@ IdeDisk::startDma(const uint32_t &prdTableBase) dmaState = Dma_Transfer; // schedule dma transfer (doDmaTransfer) - dmaTransferEvent.schedule(curTick + 1); + schedule(dmaTransferEvent, curTick + 1); } void @@ -683,7 +690,6 @@ IdeDisk::intrPost() // talk to controller to set interrupt if (ctrl) { - ctrl->bmi_regs.bmis0 |= IDEINTS; ctrl->intrPost(); } } @@ -1073,12 +1079,12 @@ IdeDisk::unserialize(Checkpoint *cp, const string §ion) switch (event) { case None : break; - case Transfer : dmaTransferEvent.schedule(reschedule); break; - case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; - case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; - case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; - case DmaRead : dmaReadEvent.schedule(reschedule); break; - case DmaWrite : dmaWriteEvent.schedule(reschedule); break; + case Transfer : schedule(dmaTransferEvent, reschedule); break; + case ReadWait : schedule(dmaReadWaitEvent, reschedule); break; + case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break; + case PrdRead : schedule(dmaPrdReadEvent, reschedule); break; + case DmaRead : schedule(dmaReadEvent, reschedule); break; + case DmaWrite : schedule(dmaWriteEvent, reschedule); break; } // Unserialize device registers diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh index 62c89add4..1b455e8ad 100644 --- a/src/dev/ide_disk.hh +++ b/src/dev/ide_disk.hh @@ -238,12 +238,12 @@ class IdeDisk : public SimObject /** Interrupt pending */ bool intrPending; - Stats::Scalar<> dmaReadFullPages; - Stats::Scalar<> dmaReadBytes; - Stats::Scalar<> dmaReadTxs; - Stats::Scalar<> dmaWriteFullPages; - Stats::Scalar<> dmaWriteBytes; - Stats::Scalar<> dmaWriteTxs; + Stats::Scalar dmaReadFullPages; + Stats::Scalar dmaReadBytes; + Stats::Scalar dmaReadTxs; + Stats::Scalar dmaWriteFullPages; + Stats::Scalar dmaWriteBytes; + Stats::Scalar dmaWriteTxs; Stats::Formula rdBandwidth; Stats::Formula wrBandwidth; Stats::Formula totBandwidth; @@ -278,8 +278,10 @@ class IdeDisk : public SimObject } // Device register read/write - void read(const Addr &offset, IdeRegType regtype, uint8_t *data); - void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); + void readCommand(const Addr offset, int size, uint8_t *data); + void readControl(const Addr offset, int size, uint8_t *data); + void writeCommand(const Addr offset, int size, const uint8_t *data); + void writeControl(const Addr offset, int size, const uint8_t *data); // Start/abort functions void startDma(const uint32_t &prdTableBase); diff --git a/src/dev/intel_8254_timer.cc b/src/dev/intel_8254_timer.cc new file mode 100644 index 000000000..d5dd043e1 --- /dev/null +++ b/src/dev/intel_8254_timer.cc @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2004, 2005 + * The Regents of The University of Michigan + * All Rights Reserved + * + * This code is part of the M5 simulator. + * + * 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. + * + * Authors: Ali G. Saidi + * Andrew L. Schultz + * Miguel J. Serrano + */ + +#include "base/misc.hh" +#include "dev/intel_8254_timer.hh" + +using namespace std; + +Intel8254Timer::Intel8254Timer(EventManager *em, const string &name, + Counter *counter0, Counter *counter1, Counter *counter2) : + EventManager(em), _name(name) +{ + counter[0] = counter0; + counter[1] = counter1; + counter[2] = counter2; +} + +Intel8254Timer::Intel8254Timer(EventManager *em, const string &name) : + EventManager(em), _name(name) +{ + counter[0] = new Counter(this, name + ".counter0", 0); + counter[1] = new Counter(this, name + ".counter1", 1); + counter[2] = new Counter(this, name + ".counter2", 2); +} + +void +Intel8254Timer::writeControl(const CtrlReg data) +{ + int sel = data.sel; + + if (sel == ReadBackCommand) + panic("PITimer Read-Back Command is not implemented.\n"); + + if (data.rw == LatchCommand) + counter[sel]->latchCount(); + else { + counter[sel]->setRW(data.rw); + counter[sel]->setMode(data.mode); + counter[sel]->setBCD(data.bcd); + } +} + +void +Intel8254Timer::serialize(const string &base, ostream &os) +{ + // serialize the counters + counter[0]->serialize(base + ".counter0", os); + counter[1]->serialize(base + ".counter1", os); + counter[2]->serialize(base + ".counter2", os); +} + +void +Intel8254Timer::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + // unserialze the counters + counter[0]->unserialize(base + ".counter0", cp, section); + counter[1]->unserialize(base + ".counter1", cp, section); + counter[2]->unserialize(base + ".counter2", cp, section); +} + +Intel8254Timer::Counter::Counter(Intel8254Timer *p, + const string &name, unsigned int _num) + : _name(name), num(_num), event(this), count(0), + latched_count(0), period(0), mode(0), output_high(false), + latch_on(false), read_byte(LSB), write_byte(LSB), parent(p) +{ + +} + +void +Intel8254Timer::Counter::latchCount() +{ + // behave like a real latch + if(!latch_on) { + latch_on = true; + read_byte = LSB; + latched_count = count; + } +} + +uint8_t +Intel8254Timer::Counter::read() +{ + if (latch_on) { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)latched_count; + break; + case MSB: + read_byte = LSB; + latch_on = false; + return latched_count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } else { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)count; + break; + case MSB: + read_byte = LSB; + return count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +Intel8254Timer::Counter::write(const uint8_t data) +{ + switch (write_byte) { + case LSB: + count = (count & 0xFF00) | data; + + if (event.scheduled()) + parent->deschedule(event); + output_high = false; + write_byte = MSB; + break; + + case MSB: + count = (count & 0x00FF) | (data << 8); + // In the RateGen or SquareWave modes, the timer wraps around and + // triggers on a value of 1, not 0. + if (mode == RateGen || mode == SquareWave) + period = count - 1; + else + period = count; + + if (period > 0) + event.setTo(period); + + write_byte = LSB; + break; + } +} + +void +Intel8254Timer::Counter::setRW(int rw_val) +{ + if (rw_val != TwoPhase) + panic("Only LSB/MSB read/write is implemented.\n"); +} + +void +Intel8254Timer::Counter::setMode(int mode_val) +{ + if(mode_val != InitTc && mode_val != RateGen && + mode_val != SquareWave) + panic("PIT mode %#x is not implemented: \n", mode_val); + + mode = mode_val; +} + +void +Intel8254Timer::Counter::setBCD(int bcd_val) +{ + if (bcd_val) + panic("PITimer does not implement BCD counts.\n"); +} + +bool +Intel8254Timer::Counter::outputHigh() +{ + return output_high; +} + +void +Intel8254Timer::Counter::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".count", count); + paramOut(os, base + ".latched_count", latched_count); + paramOut(os, base + ".period", period); + paramOut(os, base + ".mode", mode); + paramOut(os, base + ".output_high", output_high); + paramOut(os, base + ".latch_on", latch_on); + paramOut(os, base + ".read_byte", read_byte); + paramOut(os, base + ".write_byte", write_byte); + + Tick event_tick = 0; + if (event.scheduled()) + event_tick = event.when(); + paramOut(os, base + ".event_tick", event_tick); +} + +void +Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".count", count); + paramIn(cp, section, base + ".latched_count", latched_count); + paramIn(cp, section, base + ".period", period); + paramIn(cp, section, base + ".mode", mode); + paramIn(cp, section, base + ".output_high", output_high); + paramIn(cp, section, base + ".latch_on", latch_on); + paramIn(cp, section, base + ".read_byte", read_byte); + paramIn(cp, section, base + ".write_byte", write_byte); + + Tick event_tick; + paramIn(cp, section, base + ".event_tick", event_tick); + if (event_tick) + parent->schedule(event, event_tick); +} + +Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) +{ + interval = (Tick)(Clock::Float::s / 1193180.0); + counter = c_ptr; +} + +void +Intel8254Timer::Counter::CounterEvent::process() +{ + switch (counter->mode) { + case InitTc: + counter->output_high = true; + break; + case RateGen: + case SquareWave: + setTo(counter->period); + break; + default: + panic("Unimplemented PITimer mode.\n"); + } + counter->parent->counterInterrupt(counter->num); +} + +void +Intel8254Timer::Counter::CounterEvent::setTo(int clocks) +{ + if (clocks == 0) + panic("Timer can't be set to go off instantly.\n"); + DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n", + clocks * interval); + counter->parent->schedule(this, curTick + clocks * interval); +} + +const char * +Intel8254Timer::Counter::CounterEvent::description() const +{ + return "Intel 8254 Interval timer"; +} diff --git a/src/dev/intel_8254_timer.hh b/src/dev/intel_8254_timer.hh new file mode 100644 index 000000000..bb650d33b --- /dev/null +++ b/src/dev/intel_8254_timer.hh @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2004, 2005 + * The Regents of The University of Michigan + * All Rights Reserved + * + * This code is part of the M5 simulator. + * + * 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. + * + * Authors: Ali G. Saidi + * Andrew L. Schultz + * Miguel J. Serrano + */ + +#ifndef __DEV_8254_HH__ +#define __DEV_8254_HH__ + +#include <string> +#include <iostream> + +#include "base/bitunion.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" + +/** Programmable Interval Timer (Intel 8254) */ +class Intel8254Timer : public EventManager +{ + protected: + BitUnion8(CtrlReg) + Bitfield<7, 6> sel; + Bitfield<5, 4> rw; + Bitfield<3, 1> mode; + Bitfield<0> bcd; + EndBitUnion(CtrlReg) + + enum SelectVal { + SelectCounter0, + SelectCounter1, + SelectCounter2, + ReadBackCommand + }; + + enum ReadWriteVal { + LatchCommand, + LsbOnly, + MsbOnly, + TwoPhase + }; + + enum ModeVal { + InitTc, + OneShot, + RateGen, + SquareWave, + SoftwareStrobe, + HardwareStrobe + }; + + /** Counter element for PIT */ + class Counter + { + /** Event for counter interrupt */ + class CounterEvent : public Event + { + private: + /** Pointer back to Counter */ + Counter* counter; + Tick interval; + + public: + CounterEvent(Counter*); + + /** Event process */ + void process(); + + /** Event description */ + virtual const char *description() const; + + friend class Counter; + + void setTo(int clocks); + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + unsigned int num; + + CounterEvent event; + + /** Current count value */ + uint16_t count; + + /** Latched count */ + uint16_t latched_count; + + /** Interrupt period */ + uint16_t period; + + /** Current mode of operation */ + uint8_t mode; + + /** Output goes high when the counter reaches zero */ + bool output_high; + + /** State of the count latch */ + bool latch_on; + + /** Set of values for read_byte and write_byte */ + enum {LSB, MSB}; + + /** Determine which byte of a 16-bit count value to read/write */ + uint8_t read_byte, write_byte; + + /** Pointer to container */ + Intel8254Timer *parent; + + public: + Counter(Intel8254Timer *p, const std::string &name, unsigned int num); + + /** Latch the current count (if one is not already latched) */ + void latchCount(); + + /** Set the read/write mode */ + void setRW(int rw_val); + + /** Set operational mode */ + void setMode(int mode_val); + + /** Set count encoding */ + void setBCD(int bcd_val); + + /** Read a count byte */ + uint8_t read(); + + /** Write a count byte */ + void write(const uint8_t data); + + /** Is the output high? */ + bool outputHigh(); + + /** + * Serialize this object to the given output stream. + * @param base The base name of the counter object. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param base The base name of the counter object. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + protected: + std::string _name; + const std::string &name() const { return _name; } + + /** PIT has three seperate counters */ + Counter *counter[3]; + + virtual void + counterInterrupt(unsigned int num) + { + DPRINTF(Intel8254Timer, "Timer interrupt from counter %d.\n", num); + } + + public: + + virtual + ~Intel8254Timer() + {} + + Intel8254Timer(EventManager *em, const std::string &name, + Counter *counter0, Counter *counter1, Counter *counter2); + + Intel8254Timer(EventManager *em, const std::string &name); + + /** Write control word */ + void writeControl(const CtrlReg data); + + uint8_t + readCounter(unsigned int num) + { + assert(num < 3); + return counter[num]->read(); + } + + void + writeCounter(unsigned int num, const uint8_t data) + { + assert(num < 3); + counter[num]->write(data); + } + + bool + outputHigh(unsigned int num) + { + assert(num < 3); + return counter[num]->outputHigh(); + } + + /** + * Serialize this object to the given output stream. + * @param base The base name of the counter object. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param base The base name of the counter object. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); +}; + +#endif // __DEV_8254_HH__ diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index 527397ed8..cdba171a6 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -117,7 +117,7 @@ DmaPort::recvTiming(PacketPtr pkt) else if (backoffTime < device->maxBackoffDelay) backoffTime <<= 1; - backoffEvent.reschedule(curTick + backoffTime, true); + reschedule(backoffEvent, curTick + backoffTime, true); DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); @@ -138,7 +138,10 @@ DmaPort::recvTiming(PacketPtr pkt) state->numBytes += pkt->req->getSize(); assert(state->totBytes >= state->numBytes); if (state->totBytes == state->numBytes) { - state->completionEvent->process(); + if (state->delay) + schedule(state->completionEvent, curTick + state->delay); + else + state->completionEvent->process(); delete state; } delete pkt->req; @@ -187,9 +190,9 @@ void DmaPort::recvRetry() { assert(transmitList.size()); - PacketPtr pkt = transmitList.front(); bool result = true; do { + PacketPtr pkt = transmitList.front(); DPRINTF(DMA, "Retry on %s addr %#x\n", pkt->cmdString(), pkt->getAddr()); result = sendTiming(pkt); @@ -206,7 +209,7 @@ DmaPort::recvRetry() if (transmitList.size() && backoffTime && !inRetry) { DPRINTF(DMA, "Scheduling backoff for %d\n", curTick+backoffTime); if (!backoffEvent.scheduled()) - backoffEvent.schedule(backoffTime+curTick); + schedule(backoffEvent, backoffTime + curTick); } DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", transmitList.size(), backoffTime, inRetry, @@ -216,13 +219,13 @@ DmaPort::recvRetry() void DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, - uint8_t *data) + uint8_t *data, Tick delay) { assert(event); assert(device->getState() == SimObject::Running); - DmaReqState *reqState = new DmaReqState(event, this, size); + DmaReqState *reqState = new DmaReqState(event, this, size, delay); DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, @@ -294,7 +297,7 @@ DmaPort::sendDma() !backoffEvent.scheduled()) { DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", backoffTime+curTick); - backoffEvent.schedule(backoffTime+curTick); + schedule(backoffEvent, backoffTime + curTick); } } else if (state == Enums::atomic) { transmitList.pop_front(); @@ -314,7 +317,7 @@ DmaPort::sendDma() if (state->totBytes == state->numBytes) { assert(!state->completionEvent->scheduled()); - state->completionEvent->schedule(curTick + lat); + schedule(state->completionEvent, curTick + lat + state->delay); delete state; delete pkt->req; } diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index 876166adb..70af6093d 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -32,6 +32,7 @@ #ifndef __DEV_IO_DEVICE_HH__ #define __DEV_IO_DEVICE_HH__ +#include "base/fast_alloc.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" #include "mem/tport.hh" @@ -73,7 +74,7 @@ class PioPort : public SimpleTimingPort class DmaPort : public Port { protected: - struct DmaReqState : public Packet::SenderState + struct DmaReqState : public Packet::SenderState, public FastAlloc { /** Event to call on the device when this transaction (all packets) * complete. */ @@ -88,8 +89,12 @@ class DmaPort : public Port /** Number of bytes that have been acked for this transaction. */ Addr numBytes; - DmaReqState(Event *ce, Port *p, Addr tb) - : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0) + /** Amount to delay completion of dma by */ + Tick delay; + + DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay) + : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0), + delay(_delay) {} }; @@ -143,7 +148,7 @@ class DmaPort : public Port DmaPort(DmaDevice *dev, System *s); void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, - uint8_t *data = NULL); + uint8_t *data, Tick delay); bool dmaPending() { return pendingCount > 0; } @@ -207,7 +212,8 @@ class PioDevice : public MemObject { if (if_name == "pio") { if (pioPort != NULL) - panic("pio port already connected to."); + fatal("%s: pio port already connected to %s", + name(), pioPort->getPeer()->name()); pioPort = new PioPort(this, sys); return pioPort; } else @@ -264,14 +270,14 @@ class DmaDevice : public PioDevice return dynamic_cast<const Params *>(_params); } - void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) + void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) { - dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data); + dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); } - void dmaRead(Addr addr, int size, Event *event, uint8_t *data) + void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0) { - dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data); + dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); } bool dmaPending() { return dmaPort->dmaPending(); } @@ -284,12 +290,14 @@ class DmaDevice : public PioDevice { if (if_name == "pio") { if (pioPort != NULL) - panic("pio port already connected to."); + fatal("%s: pio port already connected to %s", + name(), pioPort->getPeer()->name()); pioPort = new PioPort(this, sys); return pioPort; } else if (if_name == "dma") { if (dmaPort != NULL) - panic("dma port already connected to."); + fatal("%s: dma port already connected to %s", + name(), dmaPort->getPeer()->name()); dmaPort = new DmaPort(this, sys); return dmaPort; } else diff --git a/src/dev/mc146818.cc b/src/dev/mc146818.cc new file mode 100644 index 000000000..c01d945b3 --- /dev/null +++ b/src/dev/mc146818.cc @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Andrew Schultz + * Miguel Serrano + */ + +#include <sys/time.h> +#include <time.h> + +#include <string> + +#include "base/bitfield.hh" +#include "base/time.hh" +#include "base/trace.hh" +#include "dev/mc146818.hh" +#include "dev/rtcreg.h" + +using namespace std; + +MC146818::MC146818(EventManager *em, const string &n, const struct tm time, + bool bcd, Tick frequency) + : EventManager(em), _name(n), event(this, frequency) +{ + memset(clock_data, 0, sizeof(clock_data)); + stat_regA = RTCA_32768HZ | RTCA_1024HZ; + stat_regB = RTCB_PRDC_IE | RTCB_24HR; + if (!bcd) + stat_regB |= RTCB_BIN; + + year = time.tm_year; + + if (bcd) { + // The datasheet says that the year field can be either BCD or + // years since 1900. Linux seems to be happy with years since + // 1900. + year = year % 100; + int tens = year / 10; + int ones = year % 10; + year = (tens << 4) + ones; + } + + // Unix is 0-11 for month, data seet says start at 1 + mon = time.tm_mon + 1; + mday = time.tm_mday; + hour = time.tm_hour; + min = time.tm_min; + sec = time.tm_sec; + + // Datasheet says 1 is sunday + wday = time.tm_wday + 1; + + DPRINTFN("Real-time clock set to %s", asctime(&time)); +} + +MC146818::~MC146818() +{ +} + +void +MC146818::writeData(const uint8_t addr, const uint8_t data) +{ + if (addr < RTC_STAT_REGA) + clock_data[addr] = data; + else { + switch (addr) { + case RTC_STAT_REGA: + // The "update in progress" bit is read only. + if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ)) + panic("Unimplemented RTC register A value write!\n"); + replaceBits(stat_regA, data, 6, 0); + break; + case RTC_STAT_REGB: + if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) + panic("Write to RTC reg B bits that are not implemented!\n"); + + if (data & RTCB_PRDC_IE) { + if (!event.scheduled()) + event.scheduleIntr(); + } else { + if (event.scheduled()) + deschedule(event); + } + stat_regB = data; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + panic("RTC status registers C and D are not implemented.\n"); + break; + } + } +} + +uint8_t +MC146818::readData(uint8_t addr) +{ + if (addr < RTC_STAT_REGA) + return clock_data[addr]; + else { + switch (addr) { + case RTC_STAT_REGA: + // toggle UIP bit for linux + stat_regA ^= RTCA_UIP; + return stat_regA; + break; + case RTC_STAT_REGB: + return stat_regB; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + return 0x00; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +MC146818::serialize(const string &base, ostream &os) +{ + arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); + paramOut(os, base + ".stat_regA", stat_regA); + paramOut(os, base + ".stat_regB", stat_regB); +} + +void +MC146818::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + arrayParamIn(cp, section, base + ".clock_data", clock_data, + sizeof(clock_data)); + paramIn(cp, section, base + ".stat_regA", stat_regA); + paramIn(cp, section, base + ".stat_regB", stat_regB); + + // We're not unserializing the event here, but we need to + // rescehedule the event since curTick was moved forward by the + // checkpoint + reschedule(event, curTick + event.interval); +} + +MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i) + : parent(_parent), interval(i) +{ + DPRINTF(MC146818, "RTC Event Initilizing\n"); + parent->schedule(this, curTick + interval); +} + +void +MC146818::RTCEvent::scheduleIntr() +{ + parent->schedule(this, curTick + interval); +} + +void +MC146818::RTCEvent::process() +{ + DPRINTF(MC146818, "RTC Timer Interrupt\n"); + parent->schedule(this, curTick + interval); + parent->handleEvent(); +} + +const char * +MC146818::RTCEvent::description() const +{ + return "RTC interrupt"; +} diff --git a/src/dev/mc146818.hh b/src/dev/mc146818.hh new file mode 100644 index 000000000..e145ad3fd --- /dev/null +++ b/src/dev/mc146818.hh @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Andrew Schultz + * Miguel Serrano + */ + +#ifndef __DEV_MC146818_HH__ +#define __DEV_MC146818_HH__ + +#include "base/range.hh" +#include "sim/eventq.hh" + +/** Real-Time Clock (MC146818) */ +class MC146818 : public EventManager +{ + protected: + virtual void handleEvent() + { + warn("No RTC event handler defined.\n"); + } + + private: + /** Event for RTC periodic interrupt */ + struct RTCEvent : public Event + { + MC146818 * parent; + Tick interval; + + RTCEvent(MC146818 * _parent, Tick i); + + /** Schedule the RTC periodic interrupt */ + void scheduleIntr(); + + /** Event process to occur at interrupt*/ + virtual void process(); + + /** Event description */ + virtual const char *description() const; + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + /** RTC periodic interrupt event */ + RTCEvent event; + + /** Data for real-time clock function */ + union { + uint8_t clock_data[10]; + + struct { + uint8_t sec; + uint8_t sec_alrm; + uint8_t min; + uint8_t min_alrm; + uint8_t hour; + uint8_t hour_alrm; + uint8_t wday; + uint8_t mday; + uint8_t mon; + uint8_t year; + }; + }; + + /** RTC status register A */ + uint8_t stat_regA; + + /** RTC status register B */ + uint8_t stat_regB; + + public: + MC146818(EventManager *em, const std::string &name, const struct tm time, + bool bcd, Tick frequency); + virtual ~MC146818(); + + /** RTC write data */ + void writeData(const uint8_t addr, const uint8_t data); + + /** RTC read data */ + uint8_t readData(const uint8_t addr); + + /** + * Serialize this object to the given output stream. + * @param base The base name of the counter object. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param base The base name of the counter object. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); +}; + +#endif // __DEV_MC146818_HH__ diff --git a/src/dev/mips/Malta.py b/src/dev/mips/Malta.py index d321a6361..d215bf329 100755 --- a/src/dev/mips/Malta.py +++ b/src/dev/mips/Malta.py @@ -28,12 +28,13 @@ from m5.params import * from m5.proxy import * + +from BadDevice import BadDevice from Device import BasicPioDevice +from MipsBackdoor import MipsBackdoor +from Pci import PciConfigAll from Platform import Platform -from MipsConsole import MipsConsole from Uart import Uart8250 -from Pci import PciConfigAll -from BadDevice import BadDevice class MaltaCChip(BasicPioDevice): type = 'MaltaCChip' @@ -56,7 +57,7 @@ class Malta(Platform): cchip = MaltaCChip(pio_addr=0x801a0000000) io = MaltaIO(pio_addr=0x801fc000000) uart = Uart8250(pio_addr=0xBFD003F8) - console = MipsConsole(pio_addr=0xBFD00F00, disk=Parent.simple_disk) + backdoor = MipsBackdoor(pio_addr=0xBFD00F00, disk=Parent.simple_disk) # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the @@ -65,4 +66,4 @@ class Malta(Platform): self.cchip.pio = bus.port self.io.pio = bus.port self.uart.pio = bus.port - self.console.pio = bus.port + self.backdoor.pio = bus.port diff --git a/src/dev/mips/MipsConsole.py b/src/dev/mips/MipsBackdoor.py index 36575677a..f65250238 100644 --- a/src/dev/mips/MipsConsole.py +++ b/src/dev/mips/MipsBackdoor.py @@ -30,9 +30,9 @@ from m5.params import * from m5.proxy import * from Device import BasicPioDevice -class MipsConsole(BasicPioDevice): - type = 'MipsConsole' +class MipsBackdoor(BasicPioDevice): + type = 'MipsBackdoor' cpu = Param.BaseCPU(Parent.cpu[0], "Processor") disk = Param.SimpleDisk("Simple Disk") - sim_console = Param.SimConsole(Parent.any, "The Simulator Console") + terminal = Param.Terminal(Parent.any, "The console terminal") system = Param.MipsSystem(Parent.any, "system object") diff --git a/src/dev/mips/SConscript b/src/dev/mips/SConscript index 22e91ff09..e83e47ebd 100755 --- a/src/dev/mips/SConscript +++ b/src/dev/mips/SConscript @@ -32,13 +32,13 @@ Import('*') if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'mips': - SimObject('MipsConsole.py') + SimObject('MipsBackdoor.py') SimObject('Malta.py') TraceFlag('Malta') TraceFlag('MC146818') - Source('console.cc') + Source('backdoor.cc') Source('malta.cc') Source('malta_cchip.cc') Source('malta_io.cc') diff --git a/src/dev/mips/access.h b/src/dev/mips/access.h index dbf3661b3..416b80590 100755 --- a/src/dev/mips/access.h +++ b/src/dev/mips/access.h @@ -48,37 +48,37 @@ typedef unsigned long uint64_t; // This structure hacked up from simos struct MipsAccess { - uint32_t inputChar; // 00: Placeholder for input - uint32_t last_offset; // 04: must be first field - uint32_t version; // 08: - uint32_t numCPUs; // 0C: - uint32_t intrClockFrequency; // 10: Hz + uint32_t inputChar; // 00: Placeholder for input + uint32_t last_offset; // 04: must be first field + uint32_t version; // 08: + uint32_t numCPUs; // 0C: + uint32_t intrClockFrequency; // 10: Hz // Loaded kernel - uint32_t kernStart; // 14: - uint32_t kernEnd; // 18: - uint32_t entryPoint; // 1c: + uint32_t kernStart; // 14: + uint32_t kernEnd; // 18: + uint32_t entryPoint; // 1c: // console simple output stuff - uint32_t outputChar; // 20: Placeholder for output + uint32_t outputChar; // 20: Placeholder for output // console disk stuff - uint32_t diskUnit; // 24: - uint32_t diskCount; // 28: - uint32_t diskPAddr; // 2c: - uint32_t diskBlock; // 30: - uint32_t diskOperation; // 34: + uint32_t diskUnit; // 24: + uint32_t diskCount; // 28: + uint32_t diskPAddr; // 2c: + uint32_t diskBlock; // 30: + uint32_t diskOperation; // 34: // MP boot - uint32_t cpuStack[64]; // 70: + uint32_t cpuStack[64]; // 70: /* XXX There appears to be a problem in accessing * unit64_t in the console.c file. They are treated * like uint32_int and result in the wrong address for * everything below. This problem should be investigated. */ - uint64_t cpuClock; // 38: MHz - uint64_t mem_size; // 40: + uint64_t cpuClock; // 38: MHz + uint64_t mem_size; // 40: }; #endif // __MIPS_ACCESS_H__ diff --git a/src/dev/mips/console.cc b/src/dev/mips/backdoor.cc index 185e1acbc..313f12567 100755 --- a/src/dev/mips/console.cc +++ b/src/dev/mips/backdoor.cc @@ -32,7 +32,7 @@ */ /** @file - * Mips Console Definition + * Mips Console Backdoor Definition */ #include <cstddef> #include <string> @@ -43,22 +43,22 @@ #include "base/trace.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" -#include "dev/mips/console.hh" +#include "dev/mips/backdoor.hh" #include "dev/platform.hh" -#include "dev/simconsole.hh" #include "dev/simple_disk.hh" +#include "dev/terminal.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" #include "mem/physical.hh" -#include "params/MipsConsole.hh" +#include "params/MipsBackdoor.hh" #include "sim/sim_object.hh" using namespace std; using namespace MipsISA; -MipsConsole::MipsConsole(const Params *p) - : BasicPioDevice(p), disk(p->disk), console(p->sim_console), +MipsBackdoor::MipsBackdoor(const Params *p) + : BasicPioDevice(p), disk(p->disk), terminal(p->terminal), system(p->system), cpu(p->cpu) { @@ -81,7 +81,7 @@ MipsConsole::MipsConsole(const Params *p) } void -MipsConsole::startup() +MipsBackdoor::startup() { system->setMipsAccess(pioAddr); mipsAccess->numCPUs = system->getNumCPUs(); @@ -94,7 +94,7 @@ MipsConsole::startup() } Tick -MipsConsole::read(PacketPtr pkt) +MipsBackdoor::read(PacketPtr pkt) { /** XXX Do we want to push the addr munging to a bus brige or something? So @@ -125,7 +125,7 @@ MipsConsole::read(PacketPtr pkt) pkt->set(mipsAccess->intrClockFrequency); break; case offsetof(MipsAccess, inputChar): - pkt->set(console->console_in()); + pkt->set(terminal->console_in()); break; case offsetof(MipsAccess, cpuClock): pkt->set(mipsAccess->cpuClock); @@ -169,7 +169,7 @@ MipsConsole::read(PacketPtr pkt) else panic("Unknown 32bit access, %#x\n", daddr); } - //DPRINTF(MipsConsole, "read: offset=%#x val=%#x\n", daddr, + //DPRINTF(MipsBackdoor, "read: offset=%#x val=%#x\n", daddr, // pkt->get<uint64_t>()); break; default: @@ -181,7 +181,7 @@ MipsConsole::read(PacketPtr pkt) } Tick -MipsConsole::write(PacketPtr pkt) +MipsBackdoor::write(PacketPtr pkt) { assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); Addr daddr = pkt->getAddr() - pioAddr; @@ -215,7 +215,7 @@ MipsConsole::write(PacketPtr pkt) break; case offsetof(MipsAccess, outputChar): - console->out((char)(val & 0xff)); + terminal->out((char)(val & 0xff)); break; default: @@ -235,7 +235,7 @@ MipsConsole::write(PacketPtr pkt) } void -MipsConsole::Access::serialize(ostream &os) +MipsBackdoor::Access::serialize(ostream &os) { SERIALIZE_SCALAR(last_offset); SERIALIZE_SCALAR(version); @@ -257,7 +257,7 @@ MipsConsole::Access::serialize(ostream &os) } void -MipsConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) +MipsBackdoor::Access::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(last_offset); UNSERIALIZE_SCALAR(version); @@ -279,19 +279,19 @@ MipsConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) } void -MipsConsole::serialize(ostream &os) +MipsBackdoor::serialize(ostream &os) { mipsAccess->serialize(os); } void -MipsConsole::unserialize(Checkpoint *cp, const std::string §ion) +MipsBackdoor::unserialize(Checkpoint *cp, const std::string §ion) { mipsAccess->unserialize(cp, section); } -MipsConsole * -MipsConsoleParams::create() +MipsBackdoor * +MipsBackdoorParams::create() { - return new MipsConsole(this); + return new MipsBackdoor(this); } diff --git a/src/dev/mips/console.hh b/src/dev/mips/backdoor.hh index 34792090d..b8cc0ae46 100755 --- a/src/dev/mips/console.hh +++ b/src/dev/mips/backdoor.hh @@ -29,28 +29,28 @@ */ /** @file - * System Console Interface + * System Console Backdoor Interface */ -#ifndef __MIPS_CONSOLE_HH__ -#define __MIPS_CONSOLE_HH__ +#ifndef __DEV_MIPS_BACKDOOR_HH__ +#define __DEV_MIPS_BACKDOOR_HH__ #include "base/range.hh" #include "dev/mips/access.h" #include "dev/io_device.hh" -#include "params/MipsConsole.hh" +#include "params/MipsBackdoor.hh" #include "sim/host.hh" #include "sim/sim_object.hh" class BaseCPU; -class SimConsole; +class Terminal; class MipsSystem; class SimpleDisk; /** * Memory mapped interface to the system console. This device * represents a shared data region between the OS Kernel and the - * System Console. + * System Console Backdoor. * * The system console is a small standalone program that is initially * run when the system boots. It contains the necessary code to @@ -72,7 +72,7 @@ class SimpleDisk; * primarily used doing boot before the kernel has loaded its device * drivers. */ -class MipsConsole : public BasicPioDevice +class MipsBackdoor : public BasicPioDevice { protected: struct Access : public MipsAccess @@ -89,8 +89,8 @@ class MipsConsole : public BasicPioDevice /** the disk must be accessed from the console */ SimpleDisk *disk; - /** the system console (the terminal) is accessable from the console */ - SimConsole *console; + /** the system terminal is accessable from the console */ + Terminal *terminal; /** a pointer to the system we are running in */ MipsSystem *system; @@ -99,8 +99,8 @@ class MipsConsole : public BasicPioDevice BaseCPU *cpu; public: - typedef MipsConsoleParams Params; - MipsConsole(const Params *p); + typedef MipsBackdoorParams Params; + MipsBackdoor(const Params *p); const Params * params() const @@ -123,4 +123,4 @@ class MipsConsole : public BasicPioDevice virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -#endif // __MIPS_CONSOLE_HH__ +#endif // __DEV_MIPS_BACKDOOR_HH__ diff --git a/src/dev/mips/malta.cc b/src/dev/mips/malta.cc index 0b1fa15ba..21e79d999 100755 --- a/src/dev/mips/malta.cc +++ b/src/dev/mips/malta.cc @@ -38,11 +38,11 @@ #include <vector> #include "cpu/intr_control.hh" -#include "dev/simconsole.hh" #include "dev/mips/malta_cchip.hh" #include "dev/mips/malta_pchip.hh" #include "dev/mips/malta_io.hh" #include "dev/mips/malta.hh" +#include "dev/terminal.hh" #include "params/Malta.hh" #include "sim/system.hh" diff --git a/src/dev/mips/malta_cchip.cc b/src/dev/mips/malta_cchip.cc index 5a4ea4585..265977665 100755 --- a/src/dev/mips/malta_cchip.cc +++ b/src/dev/mips/malta_cchip.cc @@ -103,7 +103,7 @@ MaltaCChip::read(PacketPtr pkt) break; case TSDEV_CC_MISC: pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF | - (pkt->req->getCpuNum() & 0x3)); + (pkt->req->contextId() & 0x3)); break; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc index bd48bdca5..fb3446299 100644 --- a/src/dev/ns_gige.cc +++ b/src/dev/ns_gige.cc @@ -36,6 +36,7 @@ #include <deque> #include <string> +#include "base/debug.hh" #include "base/inet.hh" #include "cpu/thread_context.hh" #include "dev/etherlink.hh" @@ -44,9 +45,7 @@ #include "mem/packet.hh" #include "mem/packet_access.hh" #include "params/NSGigE.hh" -#include "sim/debug.hh" #include "sim/host.hh" -#include "sim/stats.hh" #include "sim/system.hh" const char *NsRxStateStrings[] = @@ -131,341 +130,6 @@ NSGigE::NSGigE(Params *p) NSGigE::~NSGigE() {} -void -NSGigE::regStats() -{ - txBytes - .name(name() + ".txBytes") - .desc("Bytes Transmitted") - .prereq(txBytes) - ; - - rxBytes - .name(name() + ".rxBytes") - .desc("Bytes Received") - .prereq(rxBytes) - ; - - txPackets - .name(name() + ".txPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - rxPackets - .name(name() + ".rxPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - txIpChecksums - .name(name() + ".txIpChecksums") - .desc("Number of tx IP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxIpChecksums - .name(name() + ".rxIpChecksums") - .desc("Number of rx IP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txTcpChecksums - .name(name() + ".txTcpChecksums") - .desc("Number of tx TCP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxTcpChecksums - .name(name() + ".rxTcpChecksums") - .desc("Number of rx TCP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txUdpChecksums - .name(name() + ".txUdpChecksums") - .desc("Number of tx UDP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxUdpChecksums - .name(name() + ".rxUdpChecksums") - .desc("Number of rx UDP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - descDmaReads - .name(name() + ".descDMAReads") - .desc("Number of descriptors the device read w/ DMA") - .precision(0) - ; - - descDmaWrites - .name(name() + ".descDMAWrites") - .desc("Number of descriptors the device wrote w/ DMA") - .precision(0) - ; - - descDmaRdBytes - .name(name() + ".descDmaReadBytes") - .desc("number of descriptor bytes read w/ DMA") - .precision(0) - ; - - descDmaWrBytes - .name(name() + ".descDmaWriteBytes") - .desc("number of descriptor bytes write w/ DMA") - .precision(0) - ; - - txBandwidth - .name(name() + ".txBandwidth") - .desc("Transmit Bandwidth (bits/s)") - .precision(0) - .prereq(txBytes) - ; - - rxBandwidth - .name(name() + ".rxBandwidth") - .desc("Receive Bandwidth (bits/s)") - .precision(0) - .prereq(rxBytes) - ; - - totBandwidth - .name(name() + ".totBandwidth") - .desc("Total Bandwidth (bits/s)") - .precision(0) - .prereq(totBytes) - ; - - totPackets - .name(name() + ".totPackets") - .desc("Total Packets") - .precision(0) - .prereq(totBytes) - ; - - totBytes - .name(name() + ".totBytes") - .desc("Total Bytes") - .precision(0) - .prereq(totBytes) - ; - - totPacketRate - .name(name() + ".totPPS") - .desc("Total Tranmission Rate (packets/s)") - .precision(0) - .prereq(totBytes) - ; - - txPacketRate - .name(name() + ".txPPS") - .desc("Packet Tranmission Rate (packets/s)") - .precision(0) - .prereq(txBytes) - ; - - rxPacketRate - .name(name() + ".rxPPS") - .desc("Packet Reception Rate (packets/s)") - .precision(0) - .prereq(rxBytes) - ; - - postedSwi - .name(name() + ".postedSwi") - .desc("number of software interrupts posted to CPU") - .precision(0) - ; - - totalSwi - .name(name() + ".totalSwi") - .desc("total number of Swi written to ISR") - .precision(0) - ; - - coalescedSwi - .name(name() + ".coalescedSwi") - .desc("average number of Swi's coalesced into each post") - .precision(0) - ; - - postedRxIdle - .name(name() + ".postedRxIdle") - .desc("number of rxIdle interrupts posted to CPU") - .precision(0) - ; - - totalRxIdle - .name(name() + ".totalRxIdle") - .desc("total number of RxIdle written to ISR") - .precision(0) - ; - - coalescedRxIdle - .name(name() + ".coalescedRxIdle") - .desc("average number of RxIdle's coalesced into each post") - .precision(0) - ; - - postedRxOk - .name(name() + ".postedRxOk") - .desc("number of RxOk interrupts posted to CPU") - .precision(0) - ; - - totalRxOk - .name(name() + ".totalRxOk") - .desc("total number of RxOk written to ISR") - .precision(0) - ; - - coalescedRxOk - .name(name() + ".coalescedRxOk") - .desc("average number of RxOk's coalesced into each post") - .precision(0) - ; - - postedRxDesc - .name(name() + ".postedRxDesc") - .desc("number of RxDesc interrupts posted to CPU") - .precision(0) - ; - - totalRxDesc - .name(name() + ".totalRxDesc") - .desc("total number of RxDesc written to ISR") - .precision(0) - ; - - coalescedRxDesc - .name(name() + ".coalescedRxDesc") - .desc("average number of RxDesc's coalesced into each post") - .precision(0) - ; - - postedTxOk - .name(name() + ".postedTxOk") - .desc("number of TxOk interrupts posted to CPU") - .precision(0) - ; - - totalTxOk - .name(name() + ".totalTxOk") - .desc("total number of TxOk written to ISR") - .precision(0) - ; - - coalescedTxOk - .name(name() + ".coalescedTxOk") - .desc("average number of TxOk's coalesced into each post") - .precision(0) - ; - - postedTxIdle - .name(name() + ".postedTxIdle") - .desc("number of TxIdle interrupts posted to CPU") - .precision(0) - ; - - totalTxIdle - .name(name() + ".totalTxIdle") - .desc("total number of TxIdle written to ISR") - .precision(0) - ; - - coalescedTxIdle - .name(name() + ".coalescedTxIdle") - .desc("average number of TxIdle's coalesced into each post") - .precision(0) - ; - - postedTxDesc - .name(name() + ".postedTxDesc") - .desc("number of TxDesc interrupts posted to CPU") - .precision(0) - ; - - totalTxDesc - .name(name() + ".totalTxDesc") - .desc("total number of TxDesc written to ISR") - .precision(0) - ; - - coalescedTxDesc - .name(name() + ".coalescedTxDesc") - .desc("average number of TxDesc's coalesced into each post") - .precision(0) - ; - - postedRxOrn - .name(name() + ".postedRxOrn") - .desc("number of RxOrn posted to CPU") - .precision(0) - ; - - totalRxOrn - .name(name() + ".totalRxOrn") - .desc("total number of RxOrn written to ISR") - .precision(0) - ; - - coalescedRxOrn - .name(name() + ".coalescedRxOrn") - .desc("average number of RxOrn's coalesced into each post") - .precision(0) - ; - - coalescedTotal - .name(name() + ".coalescedTotal") - .desc("average number of interrupts coalesced into each post") - .precision(0) - ; - - postedInterrupts - .name(name() + ".postedInterrupts") - .desc("number of posts to CPU") - .precision(0) - ; - - droppedPackets - .name(name() + ".droppedPackets") - .desc("number of packets dropped") - .precision(0) - ; - - coalescedSwi = totalSwi / postedInterrupts; - coalescedRxIdle = totalRxIdle / postedInterrupts; - coalescedRxOk = totalRxOk / postedInterrupts; - coalescedRxDesc = totalRxDesc / postedInterrupts; - coalescedTxOk = totalTxOk / postedInterrupts; - coalescedTxIdle = totalTxIdle / postedInterrupts; - coalescedTxDesc = totalTxDesc / postedInterrupts; - coalescedRxOrn = totalRxOrn / postedInterrupts; - - coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + - totalTxOk + totalTxIdle + totalTxDesc + - totalRxOrn) / postedInterrupts; - - txBandwidth = txBytes * Stats::constant(8) / simSeconds; - rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; - totBandwidth = txBandwidth + rxBandwidth; - totBytes = txBytes + rxBytes; - totPackets = txPackets + rxPackets; - - txPacketRate = txPackets / simSeconds; - rxPacketRate = rxPackets / simSeconds; -} - - /** * This is to write to the PCI general configuration registers */ @@ -1186,6 +850,7 @@ NSGigE::devIntrPost(uint32_t interrupts) Tick when = curTick; if ((regs.isr & regs.imr & ISR_NODELAY) == 0) when += intrDelay; + postedInterrupts++; cpuIntrPost(when); } } @@ -1226,9 +891,6 @@ NSGigE::devIntrClear(uint32_t interrupts) postedRxOrn++; } - if (regs.isr & regs.imr & ISR_IMPL) - postedInterrupts++; - interrupts &= ~ISR_NOIMPL; regs.isr &= ~interrupts; @@ -1283,7 +945,8 @@ NSGigE::cpuIntrPost(Tick when) if (intrEvent) intrEvent->squash(); - intrEvent = new IntrEvent(this, intrTick, true); + intrEvent = new IntrEvent(this, true); + schedule(intrEvent, intrTick); } void @@ -1780,7 +1443,7 @@ NSGigE::rxKick() NsRxStateStrings[rxState]); if (clock && !rxKickEvent.scheduled()) - rxKickEvent.schedule(rxKickTick); + schedule(rxKickEvent, rxKickTick); } void @@ -1830,7 +1493,7 @@ NSGigE::transmit() if (!txFifo.empty() && !txEvent.scheduled()) { DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); + schedule(txEvent, curTick + retryTime); } } @@ -2036,19 +1699,34 @@ NSGigE::txKick() IpPtr ip(txPacket); if (extsts & EXTSTS_UDPPKT) { UdpPtr udp(ip); - udp->sum(0); - udp->sum(cksum(udp)); - txUdpChecksums++; + if (udp) { + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } else { + debug_break(); + warn_once("UDPPKT set, but not UDP!\n"); + } } else if (extsts & EXTSTS_TCPPKT) { TcpPtr tcp(ip); - tcp->sum(0); - tcp->sum(cksum(tcp)); - txTcpChecksums++; + if (tcp) { + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } else { + debug_break(); + warn_once("TCPPKT set, but not UDP!\n"); + } } if (extsts & EXTSTS_IPPKT) { - ip->sum(0); - ip->sum(cksum(ip)); - txIpChecksums++; + if (ip) { + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } else { + debug_break(); + warn_once("IPPKT set, but not UDP!\n"); + } } } @@ -2208,7 +1886,7 @@ NSGigE::txKick() NsTxStateStrings[txState]); if (clock && !txKickEvent.scheduled()) - txKickEvent.schedule(txKickTick); + schedule(txKickEvent, txKickTick); } /** @@ -2322,7 +2000,7 @@ NSGigE::transferDone() DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - txEvent.reschedule(curTick + ticks(1), true); + reschedule(txEvent, curTick + ticks(1), true); } bool @@ -2723,7 +2401,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) this->txDmaState = (DmaState) txDmaState; UNSERIALIZE_SCALAR(txKickTick); if (txKickTick) - txKickEvent.schedule(txKickTick); + schedule(txKickEvent, txKickTick); /* * unserialize rx state machine @@ -2741,7 +2419,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) this->rxDmaState = (DmaState) rxDmaState; UNSERIALIZE_SCALAR(rxKickTick); if (rxKickTick) - rxKickEvent.schedule(rxKickTick); + schedule(rxKickEvent, rxKickTick); /* * Unserialize EEPROM state machine @@ -2761,7 +2439,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) Tick transmitTick; UNSERIALIZE_SCALAR(transmitTick); if (transmitTick) - txEvent.schedule(curTick + transmitTick); + schedule(txEvent, curTick + transmitTick); /* * unserialize receive address filter settings @@ -2782,7 +2460,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) Tick intrEventTick; UNSERIALIZE_SCALAR(intrEventTick); if (intrEventTick) { - intrEvent = new IntrEvent(this, intrEventTick, true); + intrEvent = new IntrEvent(this, true); + schedule(intrEvent, intrEventTick); } } diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh index dfdd81b66..87cf56962 100644 --- a/src/dev/ns_gige.hh +++ b/src/dev/ns_gige.hh @@ -38,7 +38,6 @@ #define __DEV_NS_GIGE_HH__ #include "base/inet.hh" -#include "base/statistics.hh" #include "dev/etherdevice.hh" #include "dev/etherint.hh" #include "dev/etherpkt.hh" @@ -63,10 +62,10 @@ const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0 * Ethernet device registers */ struct dp_regs { - uint32_t command; - uint32_t config; - uint32_t mear; - uint32_t ptscr; + uint32_t command; + uint32_t config; + uint32_t mear; + uint32_t ptscr; uint32_t isr; uint32_t imr; uint32_t ier; @@ -372,60 +371,6 @@ class NSGigE : public EtherDevice virtual void unserialize(Checkpoint *cp, const std::string §ion); virtual void resume(); - - public: - void regStats(); - - private: - Stats::Scalar<> txBytes; - Stats::Scalar<> rxBytes; - Stats::Scalar<> txPackets; - Stats::Scalar<> rxPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> txUdpChecksums; - Stats::Scalar<> rxUdpChecksums; - Stats::Scalar<> descDmaReads; - Stats::Scalar<> descDmaWrites; - Stats::Scalar<> descDmaRdBytes; - Stats::Scalar<> descDmaWrBytes; - Stats::Formula totBandwidth; - Stats::Formula totPackets; - Stats::Formula totBytes; - Stats::Formula totPacketRate; - Stats::Formula txBandwidth; - Stats::Formula rxBandwidth; - Stats::Formula txPacketRate; - Stats::Formula rxPacketRate; - Stats::Scalar<> postedSwi; - Stats::Formula coalescedSwi; - Stats::Scalar<> totalSwi; - Stats::Scalar<> postedRxIdle; - Stats::Formula coalescedRxIdle; - Stats::Scalar<> totalRxIdle; - Stats::Scalar<> postedRxOk; - Stats::Formula coalescedRxOk; - Stats::Scalar<> totalRxOk; - Stats::Scalar<> postedRxDesc; - Stats::Formula coalescedRxDesc; - Stats::Scalar<> totalRxDesc; - Stats::Scalar<> postedTxOk; - Stats::Formula coalescedTxOk; - Stats::Scalar<> totalTxOk; - Stats::Scalar<> postedTxIdle; - Stats::Formula coalescedTxIdle; - Stats::Scalar<> totalTxIdle; - Stats::Scalar<> postedTxDesc; - Stats::Formula coalescedTxDesc; - Stats::Scalar<> totalTxDesc; - Stats::Scalar<> postedRxOrn; - Stats::Formula coalescedRxOrn; - Stats::Scalar<> totalRxOrn; - Stats::Formula coalescedTotal; - Stats::Scalar<> postedInterrupts; - Stats::Scalar<> droppedPackets; }; /* diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc index faf033705..74396be5d 100644 --- a/src/dev/pciconfigall.cc +++ b/src/dev/pciconfigall.cc @@ -47,7 +47,7 @@ using namespace std; PciConfigAll::PciConfigAll(const Params *p) : PioDevice(p) { - pioAddr = p->platform->calcConfigAddr(params()->bus,0,0); + pioAddr = p->platform->calcPciConfigAddr(params()->bus,0,0); } diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc index aa532414c..b311ed8cf 100644 --- a/src/dev/pcidev.cc +++ b/src/dev/pcidev.cc @@ -41,7 +41,7 @@ #include "base/inifile.hh" #include "base/intmath.hh" // for isPowerOf2( #include "base/misc.hh" -#include "base/str.hh" // for to_number +#include "base/str.hh" // for to_number #include "base/trace.hh" #include "dev/pciconfigall.hh" #include "dev/pcidev.hh" @@ -56,10 +56,10 @@ using namespace std; PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, int funcid, Platform *p) - : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p), - busId(busid), deviceId(devid), functionId(funcid) + : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev), + platform(p), busId(busid), deviceId(devid), functionId(funcid) { - configAddr = platform->calcConfigAddr(busId, deviceId, functionId); + configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId); } @@ -121,15 +121,26 @@ PciDev::PciDev(const Params *p) BARSize[4] = p->BAR4Size; BARSize[5] = p->BAR5Size; + legacyIO[0] = p->BAR0LegacyIO; + legacyIO[1] = p->BAR1LegacyIO; + legacyIO[2] = p->BAR2LegacyIO; + legacyIO[3] = p->BAR3LegacyIO; + legacyIO[4] = p->BAR4LegacyIO; + legacyIO[5] = p->BAR5LegacyIO; + for (int i = 0; i < 6; ++i) { - uint32_t barsize = BARSize[i]; - if (barsize != 0 && !isPowerOf2(barsize)) { - fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); + if (legacyIO[i]) { + BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i])); + config.baseAddr[i] = 0; + } else { + BARAddrs[i] = 0; + uint32_t barsize = BARSize[i]; + if (barsize != 0 && !isPowerOf2(barsize)) { + fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); + } } } - memset(BARAddrs, 0, sizeof(BARAddrs)); - plat->registerPciDevice(0, p->pci_dev, p->pci_func, letoh(config.interruptLine)); } @@ -216,8 +227,10 @@ PciDev::writeConfig(PacketPtr pkt) switch (offset) { case PCI0_INTERRUPT_LINE: config.interruptLine = pkt->get<uint8_t>(); + break; case PCI_CACHE_LINE_SIZE: config.cacheLineSize = pkt->get<uint8_t>(); + break; case PCI_LATENCY_TIMER: config.latencyTimer = pkt->get<uint8_t>(); break; @@ -240,8 +253,10 @@ PciDev::writeConfig(PacketPtr pkt) switch (offset) { case PCI_COMMAND: config.command = pkt->get<uint8_t>(); + break; case PCI_STATUS: config.status = pkt->get<uint8_t>(); + break; case PCI_CACHE_LINE_SIZE: config.cacheLineSize = pkt->get<uint8_t>(); break; @@ -264,30 +279,32 @@ PciDev::writeConfig(PacketPtr pkt) { int barnum = BAR_NUMBER(offset); - // convert BAR values to host endianness - uint32_t he_old_bar = letoh(config.baseAddr[barnum]); - uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); - - uint32_t bar_mask = - BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; - - // Writing 0xffffffff to a BAR tells the card to set the - // value of the bar to a bitmask indicating the size of - // memory it needs - if (he_new_bar == 0xffffffff) { - he_new_bar = ~(BARSize[barnum] - 1); - } else { - // does it mean something special to write 0 to a BAR? - he_new_bar &= ~bar_mask; - if (he_new_bar) { - Addr space_base = BAR_IO_SPACE(he_old_bar) ? - TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY; - BARAddrs[barnum] = he_new_bar + space_base; - pioPort->sendStatusChange(Port::RangeChange); + if (!legacyIO[barnum]) { + // convert BAR values to host endianness + uint32_t he_old_bar = letoh(config.baseAddr[barnum]); + uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); + + uint32_t bar_mask = + BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; + + // Writing 0xffffffff to a BAR tells the card to set the + // value of the bar to a bitmask indicating the size of + // memory it needs + if (he_new_bar == 0xffffffff) { + he_new_bar = ~(BARSize[barnum] - 1); + } else { + // does it mean something special to write 0 to a BAR? + he_new_bar &= ~bar_mask; + if (he_new_bar) { + BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? + platform->calcPciIOAddr(he_new_bar) : + platform->calcPciMemAddr(he_new_bar); + pioPort->sendStatusChange(Port::RangeChange); + } } + config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | + (he_old_bar & bar_mask)); } - config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | - (he_old_bar & bar_mask)); } break; diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh index a584a957d..5da8b2dfc 100644 --- a/src/dev/pcidev.hh +++ b/src/dev/pcidev.hh @@ -99,6 +99,9 @@ class PciDev : public DmaDevice /** The current address mapping of the BARs */ Addr BARAddrs[6]; + /** Whether the BARs are really hardwired legacy IO locations. */ + bool legacyIO[6]; + /** * Does the given address lie within the space mapped by the given * base address register? diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h index df57acdb0..5639d8e29 100644 --- a/src/dev/pcireg.h +++ b/src/dev/pcireg.h @@ -69,18 +69,18 @@ union PCIConfig { }; // Common PCI offsets -#define PCI_VENDOR_ID 0x00 // Vendor ID ro -#define PCI_DEVICE_ID 0x02 // Device ID ro -#define PCI_COMMAND 0x04 // Command rw -#define PCI_STATUS 0x06 // Status rw -#define PCI_REVISION_ID 0x08 // Revision ID ro -#define PCI_CLASS_CODE 0x09 // Class Code ro -#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro -#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro -#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+ -#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+ -#define PCI_HEADER_TYPE 0x0E // Header Type ro -#define PCI_BIST 0x0F // Built in self test rw +#define PCI_VENDOR_ID 0x00 // Vendor ID ro +#define PCI_DEVICE_ID 0x02 // Device ID ro +#define PCI_COMMAND 0x04 // Command rw +#define PCI_STATUS 0x06 // Status rw +#define PCI_REVISION_ID 0x08 // Revision ID ro +#define PCI_CLASS_CODE 0x09 // Class Code ro +#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro +#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro +#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+ +#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+ +#define PCI_HEADER_TYPE 0x0E // Header Type ro +#define PCI_BIST 0x0F // Built in self test rw // some pci command reg bitfields #define PCI_CMD_BME 0x04 // Bus master function enable @@ -88,62 +88,62 @@ union PCIConfig { #define PCI_CMD_IOSE 0x01 // I/O space enable // Type 0 PCI offsets -#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw -#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw -#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw -#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw -#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw -#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw -#define PCI0_CIS 0x28 // CardBus CIS Pointer ro -#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro -#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro -#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw -#define PCI0_RESERVED0 0x34 -#define PCI0_RESERVED1 0x38 -#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw -#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro -#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro -#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro +#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw +#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw +#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw +#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw +#define PCI0_CIS 0x28 // CardBus CIS Pointer ro +#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro +#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro +#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw +#define PCI0_RESERVED0 0x34 +#define PCI0_RESERVED1 0x38 +#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw +#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro +#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro +#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro // Type 1 PCI offsets -#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw -#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw -#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw -#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw -#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw -#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+ -#define PCI1_IO_BASE 0x1C // I/O Base rw -#define PCI1_IO_LIMIT 0x1D // I/O Limit rw -#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw -#define PCI1_MEM_BASE 0x20 // Memory Base rw -#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw -#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw -#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw -#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw -#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw -#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw -#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw -#define PCI1_RESERVED 0x34 // Reserved ro -#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw -#define PCI1_INTR_LINE 0x3C // Interrupt Line rw -#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro -#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw +#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw +#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw +#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw +#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+ +#define PCI1_IO_BASE 0x1C // I/O Base rw +#define PCI1_IO_LIMIT 0x1D // I/O Limit rw +#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw +#define PCI1_MEM_BASE 0x20 // Memory Base rw +#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw +#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw +#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw +#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw +#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw +#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw +#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw +#define PCI1_RESERVED 0x34 // Reserved ro +#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw +#define PCI1_INTR_LINE 0x3C // Interrupt Line rw +#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro +#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw // Device specific offsets -#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes +#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes #define PCI_CONFIG_SIZE 0xFF // Some Vendor IDs -#define PCI_VENDOR_DEC 0x1011 -#define PCI_VENDOR_NCR 0x101A -#define PCI_VENDOR_QLOGIC 0x1077 -#define PCI_VENDOR_SIMOS 0x1291 +#define PCI_VENDOR_DEC 0x1011 +#define PCI_VENDOR_NCR 0x101A +#define PCI_VENDOR_QLOGIC 0x1077 +#define PCI_VENDOR_SIMOS 0x1291 // Some Product IDs -#define PCI_PRODUCT_DEC_PZA 0x0008 -#define PCI_PRODUCT_NCR_810 0x0001 -#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 -#define PCI_PRODUCT_SIMOS_SIMOS 0x1291 -#define PCI_PRODUCT_SIMOS_ETHER 0x1292 +#define PCI_PRODUCT_DEC_PZA 0x0008 +#define PCI_PRODUCT_NCR_810 0x0001 +#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 +#define PCI_PRODUCT_SIMOS_SIMOS 0x1291 +#define PCI_PRODUCT_SIMOS_ETHER 0x1292 #endif // __PCIREG_H__ diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc index 37f7ff680..97d6c04af 100644 --- a/src/dev/pktfifo.cc +++ b/src/dev/pktfifo.cc @@ -40,23 +40,24 @@ PacketFifo::copyout(void *dest, int offset, int len) if (offset + len >= size()) return false; - list<EthPacketPtr>::iterator p = fifo.begin(); - list<EthPacketPtr>::iterator end = fifo.end(); + iterator i = fifo.begin(); + iterator end = fifo.end(); while (len > 0) { - while (offset >= (*p)->length) { - offset -= (*p)->length; - ++p; + EthPacketPtr &pkt = i->packet; + while (offset >= pkt->length) { + offset -= pkt->length; + ++i; } - if (p == end) + if (i == end) panic("invalid fifo"); - int size = min((*p)->length - offset, len); - memcpy(data, (*p)->data, size); + int size = min(pkt->length - offset, len); + memcpy(data, pkt->data, size); offset = 0; len -= size; data += size; - ++p; + ++i; } return true; @@ -64,6 +65,26 @@ PacketFifo::copyout(void *dest, int offset, int len) void +PacketFifoEntry::serialize(const string &base, ostream &os) +{ + packet->serialize(base + ".packet", os); + paramOut(os, base + ".slack", slack); + paramOut(os, base + ".number", number); + paramOut(os, base + ".priv", priv); +} + +void +PacketFifoEntry::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + packet = new EthPacketData(16384); + packet->unserialize(base + ".packet", cp, section); + paramIn(cp, section, base + ".slack", slack); + paramIn(cp, section, base + ".number", number); + paramIn(cp, section, base + ".priv", priv); +} + +void PacketFifo::serialize(const string &base, ostream &os) { paramOut(os, base + ".size", _size); @@ -72,11 +93,11 @@ PacketFifo::serialize(const string &base, ostream &os) paramOut(os, base + ".packets", fifo.size()); int i = 0; - list<EthPacketPtr>::iterator p = fifo.begin(); - list<EthPacketPtr>::iterator end = fifo.end(); - while (p != end) { - (*p)->serialize(csprintf("%s.packet%d", base, i), os); - ++p; + iterator entry = fifo.begin(); + iterator end = fifo.end(); + while (entry != end) { + entry->serialize(csprintf("%s.entry%d", base, i), os); + ++entry; ++i; } } @@ -94,8 +115,8 @@ PacketFifo::unserialize(const string &base, Checkpoint *cp, fifo.clear(); for (int i = 0; i < fifosize; ++i) { - EthPacketPtr p = new EthPacketData(16384); - p->unserialize(csprintf("%s.packet%d", base, i), cp, section); - fifo.push_back(p); + PacketFifoEntry entry; + entry.unserialize(csprintf("%s.entry%d", base, i), cp, section); + fifo.push_back(entry); } } diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh index 45157ba41..6ded248be 100644 --- a/src/dev/pktfifo.hh +++ b/src/dev/pktfifo.hh @@ -39,20 +39,59 @@ #include "sim/serialize.hh" class Checkpoint; + +struct PacketFifoEntry +{ + EthPacketPtr packet; + uint64_t number; + int slack; + int priv; + + PacketFifoEntry() + { + clear(); + } + + PacketFifoEntry(const PacketFifoEntry &s) + : packet(s.packet), number(s.number), slack(s.slack), priv(s.priv) + { + } + + PacketFifoEntry(EthPacketPtr p, uint64_t n) + : packet(p), number(n), slack(0), priv(-1) + { + } + + void clear() + { + packet = NULL; + number = 0; + slack = 0; + priv = -1; + } + + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); +}; + class PacketFifo { public: - typedef std::list<EthPacketPtr> fifo_list; + + typedef std::list<PacketFifoEntry> fifo_list; typedef fifo_list::iterator iterator; protected: - std::list<EthPacketPtr> fifo; + std::list<PacketFifoEntry> fifo; + uint64_t _counter; int _maxsize; int _size; int _reserved; public: - explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} + explicit PacketFifo(int max) + : _counter(0), _maxsize(max), _size(0), _reserved(0) {} virtual ~PacketFifo() {} int packets() const { return fifo.size(); } @@ -73,18 +112,21 @@ class PacketFifo iterator begin() { return fifo.begin(); } iterator end() { return fifo.end(); } - EthPacketPtr front() { return fifo.front(); } + EthPacketPtr front() { return fifo.begin()->packet; } bool push(EthPacketPtr ptr) { assert(ptr->length); assert(_reserved <= ptr->length); - assert(ptr->slack == 0); if (avail() < ptr->length - _reserved) return false; _size += ptr->length; - fifo.push_back(ptr); + + PacketFifoEntry entry; + entry.packet = ptr; + entry.number = _counter++; + fifo.push_back(entry); _reserved = 0; return true; } @@ -94,18 +136,17 @@ class PacketFifo if (empty()) return; - EthPacketPtr &packet = fifo.front(); - _size -= packet->length; - _size -= packet->slack; - packet->slack = 0; - packet = NULL; + iterator entry = fifo.begin(); + _size -= entry->packet->length; + _size -= entry->slack; + entry->packet = NULL; fifo.pop_front(); } void clear() { for (iterator i = begin(); i != end(); ++i) - (*i)->slack = 0; + i->clear(); fifo.clear(); _size = 0; _reserved = 0; @@ -113,51 +154,48 @@ class PacketFifo void remove(iterator i) { - EthPacketPtr &packet = *i; if (i != fifo.begin()) { iterator prev = i; --prev; assert(prev != fifo.end()); - (*prev)->slack += packet->length; + prev->slack += i->packet->length; + prev->slack += i->slack; } else { - _size -= packet->length; - _size -= packet->slack; + _size -= i->packet->length; + _size -= i->slack; } - packet->slack = 0; - packet = NULL; + i->clear(); fifo.erase(i); } bool copyout(void *dest, int offset, int len); - int countPacketsBefore(iterator end) + int countPacketsBefore(iterator i) { - iterator i = fifo.begin(); - int count = 0; - - while (i != end) { - ++count; - ++i; - } - - return count; + if (i == fifo.end()) + return 0; + return i->number - fifo.begin()->number; } int countPacketsAfter(iterator i) { iterator end = fifo.end(); - int count = 0; + if (i == end) + return 0; + return (--end)->number - i->number; + } - while (i != end) { - ++count; - ++i; - } + void check() + { + int total = 0; + for (iterator i = begin(); i != end(); ++i) + total += i->packet->length + i->slack; - return count; + if (total != _size) + panic("total (%d) is not == to size (%d)\n", total, _size); } - /** * Serialization stuff */ diff --git a/src/dev/platform.hh b/src/dev/platform.hh index 699b168ce..5f6f1df81 100644 --- a/src/dev/platform.hh +++ b/src/dev/platform.hh @@ -46,7 +46,7 @@ class PciConfigAll; class IntrControl; -class SimConsole; +class Terminal; class Uart; class System; @@ -69,7 +69,9 @@ class Platform : public SimObject virtual void postPciInt(int line); virtual void clearPciInt(int line); virtual Addr pciToDma(Addr pciAddr) const; - virtual Addr calcConfigAddr(int bus, int dev, int func) = 0; + virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0; + virtual Addr calcPciIOAddr(Addr addr) = 0; + virtual Addr calcPciMemAddr(Addr addr) = 0; virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func, uint8_t intr); diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h index 37255777b..b1406c464 100644 --- a/src/dev/rtcreg.h +++ b/src/dev/rtcreg.h @@ -30,32 +30,32 @@ * Nathan Binkert */ -#define RTC_SEC 0x00 -#define RTC_SEC_ALRM 0x01 -#define RTC_MIN 0x02 -#define RTC_MIN_ALRM 0x03 -#define RTC_HR 0x04 -#define RTC_HR_ALRM 0x05 -#define RTC_DOW 0x06 -#define RTC_DOM 0x07 -#define RTC_MON 0x08 -#define RTC_YEAR 0x09 +static const int RTC_SEC = 0x00; +static const int RTC_SEC_ALRM = 0x01; +static const int RTC_MIN = 0x02; +static const int RTC_MIN_ALRM = 0x03; +static const int RTC_HR = 0x04; +static const int RTC_HR_ALRM = 0x05; +static const int RTC_DOW = 0x06; +static const int RTC_DOM = 0x07; +static const int RTC_MON = 0x08; +static const int RTC_YEAR = 0x09; -#define RTC_STAT_REGA 0x0A -#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */ -#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */ -#define RTCA_UIP 0x80 /* 1 = date and time update in progress */ +static const int RTC_STAT_REGA = 0x0A; +static const int RTCA_1024HZ = 0x06; /* 1024Hz periodic interrupt frequency */ +static const int RTCA_32768HZ = 0x20; /* 22-stage divider, 32.768KHz timebase */ +static const int RTCA_UIP = 0x80; /* 1 = date and time update in progress */ -#define RTC_STAT_REGB 0x0B -#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */ -#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ -#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */ -#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ -#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */ -#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */ -#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */ -#define RTCB_NO_UPDT 0x80 /* stop clock updates */ +static const int RTC_STAT_REGB = 0x0B; +static const int RTCB_DST = 0x01; /* USA Daylight Savings Time enable */ +static const int RTCB_24HR = 0x02; /* 0 = 12 hours, 1 = 24 hours */ +static const int RTCB_BIN = 0x04; /* 0 = BCD, 1 = Binary coded time */ +static const int RTCB_SQWE = 0x08; /* 1 = output sqare wave at SQW pin */ +static const int RTCB_UPDT_IE = 0x10; /* 1 = enable update-ended interrupt */ +static const int RTCB_ALRM_IE = 0x20; /* 1 = enable alarm interrupt */ +static const int RTCB_PRDC_IE = 0x40; /* 1 = enable periodic clock interrupt */ +static const int RTCB_NO_UPDT = 0x80; /* stop clock updates */ -#define RTC_STAT_REGC 0x0C -#define RTC_STAT_REGD 0x0D +static const int RTC_STAT_REGC = 0x0C; +static const int RTC_STAT_REGD = 0x0D; diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc index c63966528..37c6a8259 100644 --- a/src/dev/sinic.cc +++ b/src/dev/sinic.cc @@ -33,6 +33,7 @@ #include <string> #include "arch/vtophys.hh" +#include "base/debug.hh" #include "base/inet.hh" #include "cpu/thread_context.hh" #include "cpu/intr_control.hh" @@ -40,11 +41,11 @@ #include "dev/sinic.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" -#include "sim/debug.hh" #include "sim/eventq.hh" #include "sim/host.hh" #include "sim/stats.hh" +using namespace std; using namespace Net; using namespace TheISA; @@ -265,6 +266,35 @@ Device::regStats() totPackets = txPackets + rxPackets; txPacketRate = txPackets / simSeconds; rxPacketRate = rxPackets / simSeconds; + + _maxVnicDistance = 0; + + maxVnicDistance + .name(name() + ".maxVnicDistance") + .desc("maximum vnic distance") + ; + + totalVnicDistance + .name(name() + ".totalVnicDistance") + .desc("total vnic distance") + ; + numVnicDistance + .name(name() + ".numVnicDistance") + .desc("number of vnic distance measurements") + ; + + avgVnicDistance + .name(name() + ".avgVnicDistance") + .desc("average vnic distance") + ; + + avgVnicDistance = totalVnicDistance / numVnicDistance; +} + +void +Device::resetStats() +{ + _maxVnicDistance = 0; } EtherInt* @@ -289,6 +319,10 @@ Device::prepareIO(int cpu, int index) index, size); } +//add stats for head of line blocking +//add stats for average fifo length +//add stats for average number of vnics busy + void Device::prepareRead(int cpu, int index) { @@ -301,7 +335,7 @@ Device::prepareRead(int cpu, int index) uint64_t rxdone = vnic.RxDone; rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); - rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); + rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); rxdone = set_RxDone_NotHigh(rxdone, rxLow); regs.RxData = vnic.RxData; regs.RxDone = rxdone; @@ -311,10 +345,23 @@ Device::prepareRead(int cpu, int index) uint64_t txdone = vnic.TxDone; txdone = set_TxDone_Packets(txdone, txFifo.packets()); txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); - txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); + txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); regs.TxData = vnic.TxData; regs.TxDone = txdone; regs.TxWait = txdone; + + int head = 0xffff; + + if (!rxFifo.empty()) { + int vnic = rxFifo.begin()->priv; + if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) + head = vnic; + } + + regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); + regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); + regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); + regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); } void @@ -332,7 +379,7 @@ Device::read(PacketPtr pkt) assert(config.command & PCI_CMD_MSE); assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); - int cpu = pkt->req->getCpuNum(); + int cpu = pkt->req->contextId(); Addr daddr = pkt->getAddr() - BARAddrs[0]; Addr index = daddr >> Regs::VirtualShift; Addr raddr = daddr & Regs::VirtualMask; @@ -419,7 +466,7 @@ Device::write(PacketPtr pkt) assert(config.command & PCI_CMD_MSE); assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); - int cpu = pkt->req->getCpuNum(); + int cpu = pkt->req->contextId(); Addr daddr = pkt->getAddr() - BARAddrs[0]; Addr index = daddr >> Regs::VirtualShift; Addr raddr = daddr & Regs::VirtualMask; @@ -473,22 +520,25 @@ Device::write(PacketPtr pkt) vnic.rxUnique = rxUnique++; vnic.RxDone = Regs::RxDone_Busy; vnic.RxData = pkt->get<uint64_t>(); + rxBusyCount++; if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) { panic("vtophys not implemented in newmem"); -/* Addr vaddr = Regs::get_RxData_Addr(reg64); +#ifdef SINIC_VTOPHYS + Addr vaddr = Regs::get_RxData_Addr(reg64); Addr paddr = vtophys(req->xc, vaddr); DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " "vaddr=%#x, paddr=%#x\n", index, vnic.rxUnique, vaddr, paddr); - vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/ + vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); +#endif } else { DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", index, vnic.rxUnique); } - if (vnic.rxPacket == rxFifo.end()) { + if (vnic.rxIndex == rxFifo.end()) { DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); rxList.push_back(index); } else { @@ -512,15 +562,17 @@ Device::write(PacketPtr pkt) if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) { panic("vtophys won't work here in newmem.\n"); - /*Addr vaddr = Regs::get_TxData_Addr(reg64); +#ifdef SINIC_VTOPHYS + Addr vaddr = Regs::get_TxData_Addr(reg64); Addr paddr = vtophys(req->xc, vaddr); - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " + DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): " "vaddr=%#x, paddr=%#x\n", index, vnic.txUnique, vaddr, paddr); - vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/ + vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); +#endif } else { - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", + DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n", index, vnic.txUnique); } @@ -643,7 +695,8 @@ Base::cpuIntrPost(Tick when) if (intrEvent) intrEvent->squash(); - intrEvent = new IntrEvent(this, intrTick, true); + intrEvent = new IntrEvent(this, true); + schedule(intrEvent, intrTick); } void @@ -761,18 +814,31 @@ Device::reset() regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; regs.RxMaxCopy = params()->rx_max_copy; regs.TxMaxCopy = params()->tx_max_copy; - regs.RxMaxIntr = params()->rx_max_intr; + regs.ZeroCopySize = params()->zero_copy_size; + regs.ZeroCopyMark = params()->zero_copy_threshold; regs.VirtualCount = params()->virtual_count; + regs.RxMaxIntr = params()->rx_max_intr; regs.RxFifoSize = params()->rx_fifo_size; regs.TxFifoSize = params()->tx_fifo_size; - regs.RxFifoMark = params()->rx_fifo_threshold; - regs.TxFifoMark = params()->tx_fifo_threshold; + regs.RxFifoLow = params()->rx_fifo_low_mark; + regs.TxFifoLow = params()->tx_fifo_threshold; + regs.RxFifoHigh = params()->rx_fifo_threshold; + regs.TxFifoHigh = params()->tx_fifo_high_mark; regs.HwAddr = params()->hardware_address; + if (regs.RxMaxCopy < regs.ZeroCopyMark) + panic("Must be able to copy at least as many bytes as the threshold"); + + if (regs.ZeroCopySize >= regs.ZeroCopyMark) + panic("The number of bytes to copy must be less than the threshold"); + rxList.clear(); rxBusy.clear(); rxActive = -1; txList.clear(); + rxBusyCount = 0; + rxDirtyCount = 0; + rxMappedCount = 0; rxState = rxIdle; txState = txIdle; @@ -788,7 +854,7 @@ Device::reset() virtualRegs.clear(); virtualRegs.resize(size); for (int i = 0; i < size; ++i) - virtualRegs[i].rxPacket = rxFifo.end(); + virtualRegs[i].rxIndex = rxFifo.end(); } void @@ -822,6 +888,7 @@ Device::rxKick() } next: + rxFifo.check(); if (rxState == rxIdle) goto exit; @@ -845,12 +912,28 @@ Device::rxKick() int size = virtualRegs.size(); for (int i = 0; i < size; ++i) { VirtualReg *vn = &virtualRegs[i]; - if (vn->rxPacket != end && - !Regs::get_RxDone_Busy(vn->RxDone)) { + bool busy = Regs::get_RxDone_Busy(vn->RxDone); + if (vn->rxIndex != end) { + bool dirty = vn->rxPacketOffset > 0; + const char *status; + + if (busy && dirty) + status = "busy,dirty"; + else if (busy) + status = "busy"; + else if (dirty) + status = "dirty"; + else + status = "mapped"; + DPRINTF(EthernetSM, - "vnic %d (rxunique %d), has outstanding packet %d\n", - i, vn->rxUnique, - rxFifo.countPacketsBefore(vn->rxPacket)); + "vnic %d %s (rxunique %d), packet %d, slack %d\n", + i, status, vn->rxUnique, + rxFifo.countPacketsBefore(vn->rxIndex), + vn->rxIndex->slack); + } else if (busy) { + DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", + i, vn->rxUnique); } } } @@ -860,7 +943,7 @@ Device::rxKick() rxBusy.pop_front(); vnic = &virtualRegs[rxActive]; - if (vnic->rxPacket == rxFifo.end()) + if (vnic->rxIndex == rxFifo.end()) panic("continuing vnic without packet\n"); DPRINTF(EthernetSM, @@ -869,6 +952,14 @@ Device::rxKick() rxState = rxBeginCopy; + int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); + totalVnicDistance += vnic_distance; + numVnicDistance += 1; + if (vnic_distance > _maxVnicDistance) { + maxVnicDistance = vnic_distance; + _maxVnicDistance = vnic_distance; + } + break; } @@ -891,14 +982,16 @@ Device::rxKick() rxActive, vnic->rxUnique); // Grab a new packet from the fifo. - vnic->rxPacket = rxFifoPtr++; + vnic->rxIndex = rxFifoPtr++; + vnic->rxIndex->priv = rxActive; vnic->rxPacketOffset = 0; - vnic->rxPacketBytes = (*vnic->rxPacket)->length; + vnic->rxPacketBytes = vnic->rxIndex->packet->length; assert(vnic->rxPacketBytes); + rxMappedCount++; vnic->rxDoneData = 0; /* scope for variables */ { - IpPtr ip(*vnic->rxPacket); + IpPtr ip(vnic->rxIndex->packet); if (ip) { DPRINTF(Ethernet, "ID is %d\n", ip->id()); vnic->rxDoneData |= Regs::RxDone_IpPacket; @@ -939,16 +1032,26 @@ Device::rxKick() rxDmaAddr = params()->platform->pciToDma( Regs::get_RxData_Addr(vnic->RxData)); - rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData), + rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData), vnic->rxPacketBytes); - rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; + + /* + * if we're doing zero/delay copy and we're below the fifo + * threshold, see if we should try to do the zero/defer copy + */ + if ((Regs::get_Config_ZeroCopy(regs.Config) || + Regs::get_Config_DelayCopy(regs.Config)) && + !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { + if (rxDmaLen > regs.ZeroCopyMark) + rxDmaLen = regs.ZeroCopySize; + } + rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; rxState = rxCopy; if (rxDmaAddr == 1LL) { rxState = rxCopyDone; break; } - dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); break; @@ -959,17 +1062,25 @@ Device::rxKick() case rxCopyDone: vnic->RxDone = vnic->rxDoneData; vnic->RxDone |= Regs::RxDone_Complete; + rxBusyCount--; if (vnic->rxPacketBytes == rxDmaLen) { + if (vnic->rxPacketOffset) + rxDirtyCount--; + // Packet is complete. Indicate how many bytes were copied vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d (rxunique %d)\n", rxActive, vnic->rxUnique); - rxFifo.remove(vnic->rxPacket); - vnic->rxPacket = rxFifo.end(); + rxFifo.remove(vnic->rxIndex); + vnic->rxIndex = rxFifo.end(); + rxMappedCount--; } else { + if (!vnic->rxPacketOffset) + rxDirtyCount++; + vnic->rxPacketBytes -= rxDmaLen; vnic->rxPacketOffset += rxDmaLen; vnic->RxDone |= Regs::RxDone_More; @@ -989,10 +1100,10 @@ Device::rxKick() rxEmpty = true; } - if (rxFifo.size() < params()->rx_fifo_low_mark) + if (rxFifo.size() < regs.RxFifoLow) rxLow = true; - if (rxFifo.size() > params()->rx_fifo_threshold) + if (rxFifo.size() > regs.RxFifoHigh) rxLow = false; devIntrPost(Regs::Intr_RxDMA); @@ -1044,7 +1155,7 @@ Device::transmit() if (!interface->sendPacket(packet)) { DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", txFifo.avail()); - goto reschedule; + return; } txFifo.pop(); @@ -1072,15 +1183,9 @@ Device::transmit() txFifo.avail()); interrupts = Regs::Intr_TxPacket; - if (txFifo.size() < regs.TxFifoMark) + if (txFifo.size() < regs.TxFifoLow) interrupts |= Regs::Intr_TxLow; devIntrPost(interrupts); - - reschedule: - if (!txFifo.empty() && !txEvent.scheduled()) { - DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); - } } void @@ -1211,7 +1316,7 @@ Device::transferDone() DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - txEvent.reschedule(curTick + ticks(1), true); + reschedule(txEvent, curTick + ticks(1), true); } bool @@ -1278,7 +1383,7 @@ Device::recvPacket(EthPacketPtr packet) return true; } - if (rxFifo.size() >= regs.RxFifoMark) + if (rxFifo.size() >= regs.RxFifoHigh) devIntrPost(Regs::Intr_RxHigh); if (!rxFifo.push(packet)) { @@ -1351,7 +1456,8 @@ Base::unserialize(Checkpoint *cp, const std::string §ion) Tick intrEventTick; UNSERIALIZE_SCALAR(intrEventTick); if (intrEventTick) { - intrEvent = new IntrEvent(this, intrEventTick, true); + intrEvent = new IntrEvent(this, true); + schedule(intrEvent, intrEventTick); } } @@ -1372,19 +1478,13 @@ Device::serialize(std::ostream &os) TxStateStrings[txState]); /* - * Serialize the device registers + * Serialize the device registers that could be modified by the OS. */ SERIALIZE_SCALAR(regs.Config); SERIALIZE_SCALAR(regs.IntrStatus); SERIALIZE_SCALAR(regs.IntrMask); - SERIALIZE_SCALAR(regs.RxMaxCopy); - SERIALIZE_SCALAR(regs.TxMaxCopy); - SERIALIZE_SCALAR(regs.RxMaxIntr); - SERIALIZE_SCALAR(regs.VirtualCount); SERIALIZE_SCALAR(regs.RxData); - SERIALIZE_SCALAR(regs.RxDone); SERIALIZE_SCALAR(regs.TxData); - SERIALIZE_SCALAR(regs.TxDone); /* * Serialize the virtual nic state @@ -1400,12 +1500,12 @@ Device::serialize(std::ostream &os) paramOut(os, reg + ".TxData", vnic->TxData); paramOut(os, reg + ".TxDone", vnic->TxDone); - bool rxPacketExists = vnic->rxPacket != rxFifo.end(); + bool rxPacketExists = vnic->rxIndex != rxFifo.end(); paramOut(os, reg + ".rxPacketExists", rxPacketExists); if (rxPacketExists) { int rxPacket = 0; PacketFifo::iterator i = rxFifo.begin(); - while (i != vnic->rxPacket) { + while (i != vnic->rxIndex) { assert(i != rxFifo.end()); ++i; ++rxPacket; @@ -1418,10 +1518,15 @@ Device::serialize(std::ostream &os) paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); } - int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); + int rxFifoPtr = -1; + if (this->rxFifoPtr != rxFifo.end()) + rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); SERIALIZE_SCALAR(rxFifoPtr); SERIALIZE_SCALAR(rxActive); + SERIALIZE_SCALAR(rxBusyCount); + SERIALIZE_SCALAR(rxDirtyCount); + SERIALIZE_SCALAR(rxMappedCount); VirtualList::iterator i, end; for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) @@ -1478,21 +1583,18 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) Base::unserialize(cp, section); /* - * Unserialize the device registers + * Unserialize the device registers that may have been written by the OS. */ UNSERIALIZE_SCALAR(regs.Config); UNSERIALIZE_SCALAR(regs.IntrStatus); UNSERIALIZE_SCALAR(regs.IntrMask); - UNSERIALIZE_SCALAR(regs.RxMaxCopy); - UNSERIALIZE_SCALAR(regs.TxMaxCopy); - UNSERIALIZE_SCALAR(regs.RxMaxIntr); - UNSERIALIZE_SCALAR(regs.VirtualCount); UNSERIALIZE_SCALAR(regs.RxData); - UNSERIALIZE_SCALAR(regs.RxDone); UNSERIALIZE_SCALAR(regs.TxData); - UNSERIALIZE_SCALAR(regs.TxDone); UNSERIALIZE_SCALAR(rxActive); + UNSERIALIZE_SCALAR(rxBusyCount); + UNSERIALIZE_SCALAR(rxDirtyCount); + UNSERIALIZE_SCALAR(rxMappedCount); int rxListSize; UNSERIALIZE_SCALAR(rxListSize); @@ -1533,9 +1635,13 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) int rxFifoPtr; UNSERIALIZE_SCALAR(rxFifoPtr); - this->rxFifoPtr = rxFifo.begin(); - for (int i = 0; i < rxFifoPtr; ++i) - ++this->rxFifoPtr; + if (rxFifoPtr >= 0) { + this->rxFifoPtr = rxFifo.begin(); + for (int i = 0; i < rxFifoPtr; ++i) + ++this->rxFifoPtr; + } else { + this->rxFifoPtr = rxFifo.end(); + } /* * Unserialize tx state machine @@ -1582,15 +1688,15 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) if (rxPacketExists) { int rxPacket; paramIn(cp, section, reg + ".rxPacket", rxPacket); - vnic->rxPacket = rxFifo.begin(); + vnic->rxIndex = rxFifo.begin(); while (rxPacket--) - ++vnic->rxPacket; + ++vnic->rxIndex; paramIn(cp, section, reg + ".rxPacketOffset", vnic->rxPacketOffset); paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); } else { - vnic->rxPacket = rxFifo.end(); + vnic->rxIndex = rxFifo.end(); } paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); } @@ -1601,7 +1707,7 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) Tick transmitTick; UNSERIALIZE_SCALAR(transmitTick); if (transmitTick) - txEvent.schedule(curTick + transmitTick); + schedule(txEvent, curTick + transmitTick); pioPort->sendStatusChange(Port::RangeChange); diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh index e85d93fe4..cd8412ef4 100644 --- a/src/dev/sinic.hh +++ b/src/dev/sinic.hh @@ -115,19 +115,24 @@ class Device : public Base uint32_t IntrMask; // 0x0c uint32_t RxMaxCopy; // 0x10 uint32_t TxMaxCopy; // 0x14 - uint32_t RxMaxIntr; // 0x18 - uint32_t VirtualCount; // 0x1c - uint32_t RxFifoSize; // 0x20 - uint32_t TxFifoSize; // 0x24 - uint32_t RxFifoMark; // 0x28 - uint32_t TxFifoMark; // 0x2c - uint64_t RxData; // 0x30 - uint64_t RxDone; // 0x38 - uint64_t RxWait; // 0x40 - uint64_t TxData; // 0x48 - uint64_t TxDone; // 0x50 - uint64_t TxWait; // 0x58 - uint64_t HwAddr; // 0x60 + uint32_t ZeroCopySize; // 0x18 + uint32_t ZeroCopyMark; // 0x1c + uint32_t VirtualCount; // 0x20 + uint32_t RxMaxIntr; // 0x24 + uint32_t RxFifoSize; // 0x28 + uint32_t TxFifoSize; // 0x2c + uint32_t RxFifoLow; // 0x30 + uint32_t TxFifoLow; // 0x34 + uint32_t RxFifoHigh; // 0x38 + uint32_t TxFifoHigh; // 0x3c + uint64_t RxData; // 0x40 + uint64_t RxDone; // 0x48 + uint64_t RxWait; // 0x50 + uint64_t TxData; // 0x58 + uint64_t TxDone; // 0x60 + uint64_t TxWait; // 0x68 + uint64_t HwAddr; // 0x70 + uint64_t RxStatus; // 0x78 } regs; struct VirtualReg { @@ -136,7 +141,7 @@ class Device : public Base uint64_t TxData; uint64_t TxDone; - PacketFifo::iterator rxPacket; + PacketFifo::iterator rxIndex; int rxPacketOffset; int rxPacketBytes; uint64_t rxDoneData; @@ -159,6 +164,10 @@ class Device : public Base int rxActive; VirtualList txList; + int rxBusyCount; + int rxMappedCount; + int rxDirtyCount; + uint8_t ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(daddr); } @@ -274,34 +283,42 @@ class Device : public Base * Statistics */ private: - Stats::Scalar<> rxBytes; + Stats::Scalar rxBytes; Stats::Formula rxBandwidth; - Stats::Scalar<> rxPackets; + Stats::Scalar rxPackets; Stats::Formula rxPacketRate; - Stats::Scalar<> rxIpPackets; - Stats::Scalar<> rxTcpPackets; - Stats::Scalar<> rxUdpPackets; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> rxUdpChecksums; - - Stats::Scalar<> txBytes; + Stats::Scalar rxIpPackets; + Stats::Scalar rxTcpPackets; + Stats::Scalar rxUdpPackets; + Stats::Scalar rxIpChecksums; + Stats::Scalar rxTcpChecksums; + Stats::Scalar rxUdpChecksums; + + Stats::Scalar txBytes; Stats::Formula txBandwidth; Stats::Formula totBandwidth; Stats::Formula totPackets; Stats::Formula totBytes; Stats::Formula totPacketRate; - Stats::Scalar<> txPackets; + Stats::Scalar txPackets; Stats::Formula txPacketRate; - Stats::Scalar<> txIpPackets; - Stats::Scalar<> txTcpPackets; - Stats::Scalar<> txUdpPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> txUdpChecksums; + Stats::Scalar txIpPackets; + Stats::Scalar txTcpPackets; + Stats::Scalar txUdpPackets; + Stats::Scalar txIpChecksums; + Stats::Scalar txTcpChecksums; + Stats::Scalar txUdpChecksums; + + Stats::Scalar totalVnicDistance; + Stats::Scalar numVnicDistance; + Stats::Scalar maxVnicDistance; + Stats::Formula avgVnicDistance; + + int _maxVnicDistance; public: virtual void regStats(); + virtual void resetStats(); /** * Serialization stuff diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh index de4188145..7ac7abad0 100644 --- a/src/dev/sinicreg.hh +++ b/src/dev/sinicreg.hh @@ -48,7 +48,7 @@ static const uint64_t NAME##_width = WIDTH; \ static const uint64_t NAME##_offset = OFFSET; \ static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \ - static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ + static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ static inline uint64_t get_##NAME(uint64_t reg) \ { return (reg & NAME) >> OFFSET; } \ static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \ @@ -67,20 +67,25 @@ __SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status __SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask __SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy __SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy -__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt -__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs -__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes -__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes -__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark -__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark -__SINIC_REG32(RxData, 0x30); // 64: receive data -__SINIC_REG32(RxDone, 0x38); // 64: receive done -__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait) -__SINIC_REG32(TxData, 0x48); // 64: transmit data -__SINIC_REG32(TxDone, 0x50); // 64: transmit done -__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait) -__SINIC_REG32(HwAddr, 0x60); // 64: mac address -__SINIC_REG32(Size, 0x68); // register addres space size +__SINIC_REG32(ZeroCopySize, 0x18); // 32: bytes to copy if below threshold +__SINIC_REG32(ZeroCopyMark, 0x1c); // 32: only zero-copy above this threshold +__SINIC_REG32(VirtualCount, 0x20); // 32: number of virutal NICs +__SINIC_REG32(RxMaxIntr, 0x24); // 32: max receives per interrupt +__SINIC_REG32(RxFifoSize, 0x28); // 32: rx fifo capacity in bytes +__SINIC_REG32(TxFifoSize, 0x2c); // 32: tx fifo capacity in bytes +__SINIC_REG32(RxFifoLow, 0x30); // 32: rx fifo low watermark +__SINIC_REG32(TxFifoLow, 0x34); // 32: tx fifo low watermark +__SINIC_REG32(RxFifoHigh, 0x38); // 32: rx fifo high watermark +__SINIC_REG32(TxFifoHigh, 0x3c); // 32: tx fifo high watermark +__SINIC_REG32(RxData, 0x40); // 64: receive data +__SINIC_REG32(RxDone, 0x48); // 64: receive done +__SINIC_REG32(RxWait, 0x50); // 64: receive done (busy wait) +__SINIC_REG32(TxData, 0x58); // 64: transmit data +__SINIC_REG32(TxDone, 0x60); // 64: transmit done +__SINIC_REG32(TxWait, 0x68); // 64: transmit done (busy wait) +__SINIC_REG32(HwAddr, 0x70); // 64: mac address +__SINIC_REG32(RxStatus, 0x78); +__SINIC_REG32(Size, 0x80); // register addres space size // Config register bits __SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy @@ -116,9 +121,10 @@ __SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced __SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits // RX Data Description -__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual -__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k -__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB +__SINIC_VAL64(RxData_NoDelay, 61, 1); // Don't Delay this copy +__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual +__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k +__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB // TX Data Description __SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more) @@ -159,6 +165,11 @@ __SINIC_VAL64(TxDone_Res6, 21, 1); // reserved __SINIC_VAL64(TxDone_Res7, 20, 1); // reserved __SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k +__SINIC_VAL64(RxStatus_Dirty, 48, 16); +__SINIC_VAL64(RxStatus_Mapped, 32, 16); +__SINIC_VAL64(RxStatus_Busy, 16, 16); +__SINIC_VAL64(RxStatus_Head, 0, 16); + struct Info { uint8_t size; @@ -174,31 +185,37 @@ regInfo(Addr daddr) { static Regs::Info invalid = { 0, false, false, "invalid" }; static Regs::Info info [] = { - { 4, true, true, "Config" }, - { 4, false, true, "Command" }, - { 4, true, true, "IntrStatus" }, - { 4, true, true, "IntrMask" }, - { 4, true, false, "RxMaxCopy" }, - { 4, true, false, "TxMaxCopy" }, - { 4, true, false, "RxMaxIntr" }, - { 4, true, false, "VirtualCount" }, - { 4, true, false, "RxFifoSize" }, - { 4, true, false, "TxFifoSize" }, - { 4, true, false, "RxFifoMark" }, - { 4, true, false, "TxFifoMark" }, - { 8, true, true, "RxData" }, + { 4, true, true, "Config" }, + { 4, false, true, "Command" }, + { 4, true, true, "IntrStatus" }, + { 4, true, true, "IntrMask" }, + { 4, true, false, "RxMaxCopy" }, + { 4, true, false, "TxMaxCopy" }, + { 4, true, false, "ZeroCopySize" }, + { 4, true, false, "ZeroCopyMark" }, + { 4, true, false, "VirtualCount" }, + { 4, true, false, "RxMaxIntr" }, + { 4, true, false, "RxFifoSize" }, + { 4, true, false, "TxFifoSize" }, + { 4, true, false, "RxFifoLow" }, + { 4, true, false, "TxFifoLow" }, + { 4, true, false, "RxFifoHigh" }, + { 4, true, false, "TxFifoHigh" }, + { 8, true, true, "RxData" }, + invalid, + { 8, true, false, "RxDone" }, invalid, - { 8, true, false, "RxDone" }, + { 8, true, false, "RxWait" }, invalid, - { 8, true, false, "RxWait" }, + { 8, true, true, "TxData" }, invalid, - { 8, true, true, "TxData" }, + { 8, true, false, "TxDone" }, invalid, - { 8, true, false, "TxDone" }, + { 8, true, false, "TxWait" }, invalid, - { 8, true, false, "TxWait" }, + { 8, true, false, "HwAddr" }, invalid, - { 8, true, false, "HwAddr" }, + { 8, true, false, "RxStatus" }, invalid, }; diff --git a/src/dev/sparc/T1000.py b/src/dev/sparc/T1000.py index a033e27e2..cbf390737 100644 --- a/src/dev/sparc/T1000.py +++ b/src/dev/sparc/T1000.py @@ -29,9 +29,9 @@ from m5.params import * from m5.proxy import * from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr -from Uart import Uart8250 from Platform import Platform -from SimConsole import SimConsole +from Terminal import Terminal +from Uart import Uart8250 class MmDisk(BasicPioDevice): @@ -98,11 +98,11 @@ class T1000(Platform): fake_ssi = IsaFake(pio_addr=0xff00000000, pio_size=0x10000000) #warn_access="Accessing SSI -- Unimplemented!") - hconsole = SimConsole() + hterm = Terminal() hvuart = Uart8250(pio_addr=0xfff0c2c000) htod = DumbTOD() - pconsole = SimConsole() + pterm = Terminal() puart0 = Uart8250(pio_addr=0x1f10000000) iob = Iob() @@ -116,8 +116,8 @@ class T1000(Platform): # earlier, since the bus object itself is typically defined at the # System level. def attachIO(self, bus): - self.hvuart.sim_console = self.hconsole - self.puart0.sim_console = self.pconsole + self.hvuart.terminal = self.hterm + self.puart0.terminal = self.pterm self.fake_clk.pio = bus.port self.fake_membnks.pio = bus.port self.fake_l2_1.pio = bus.port diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc index 6608fc64a..4543dd07b 100644 --- a/src/dev/sparc/iob.cc +++ b/src/dev/sparc/iob.cc @@ -120,7 +120,7 @@ void Iob::readJBus(PacketPtr pkt) { Addr accessAddr = pkt->getAddr() - iobJBusAddr; - int cpuid = pkt->req->getCpuNum(); + int cpuid = pkt->req->contextId(); int index; uint64_t data; @@ -235,7 +235,7 @@ void Iob::writeJBus(PacketPtr pkt) { Addr accessAddr = pkt->getAddr() - iobJBusAddr; - int cpuid = pkt->req->getCpuNum(); + int cpuid = pkt->req->contextId(); int index; uint64_t data; @@ -276,7 +276,7 @@ void Iob::generateIpi(Type type, int cpu_id, int vector) { SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset(); - if (cpu_id >= sys->getNumCPUs()) + if (cpu_id >= sys->numContexts()) return; switch (type) { diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc index 49e44af55..88fb358ef 100644 --- a/src/dev/sparc/t1000.cc +++ b/src/dev/sparc/t1000.cc @@ -37,8 +37,8 @@ #include <vector> #include "cpu/intr_control.hh" -#include "dev/simconsole.hh" #include "dev/sparc/t1000.hh" +#include "dev/terminal.hh" #include "sim/system.hh" using namespace std; @@ -94,7 +94,21 @@ T1000::pciToDma(Addr pciAddr) const Addr -T1000::calcConfigAddr(int bus, int dev, int func) +T1000::calcPciConfigAddr(int bus, int dev, int func) +{ + panic("Need implementation\n"); + M5_DUMMY_RETURN +} + +Addr +T1000::calcPciIOAddr(Addr addr) +{ + panic("Need implementation\n"); + M5_DUMMY_RETURN +} + +Addr +T1000::calcPciMemAddr(Addr addr) { panic("Need implementation\n"); M5_DUMMY_RETURN diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh index 76de0a550..01ff3d319 100644 --- a/src/dev/sparc/t1000.hh +++ b/src/dev/sparc/t1000.hh @@ -91,7 +91,17 @@ class T1000 : public Platform /** * Calculate the configuration address given a bus/dev/func. */ - virtual Addr calcConfigAddr(int bus, int dev, int func); + virtual Addr calcPciConfigAddr(int bus, int dev, int func); + + /** + * Calculate the address for an IO location on the PCI bus. + */ + virtual Addr calcPciIOAddr(Addr addr); + + /** + * Calculate the address for a memory location on the PCI bus. + */ + virtual Addr calcPciMemAddr(Addr addr); }; #endif // __DEV_T1000_HH__ diff --git a/src/dev/simconsole.cc b/src/dev/terminal.cc index e8dc1b210..fba0c6130 100644 --- a/src/dev/simconsole.cc +++ b/src/dev/terminal.cc @@ -30,27 +30,28 @@ */ /* @file - * Implements the user interface to a serial console + * Implements the user interface to a serial terminal */ #include <sys/ioctl.h> #include <sys/termios.h> -#include <sys/types.h> #include <errno.h> #include <poll.h> #include <unistd.h> +#include <cctype> #include <iostream> #include <fstream> #include <sstream> #include <string> +#include "base/atomicio.hh" #include "base/misc.hh" #include "base/output.hh" #include "base/socket.hh" #include "base/trace.hh" #include "dev/platform.hh" -#include "dev/simconsole.hh" +#include "dev/terminal.hh" #include "dev/uart.hh" using namespace std; @@ -59,50 +60,46 @@ using namespace std; /* * Poll event for the listen socket */ -SimConsole::ListenEvent::ListenEvent(SimConsole *c, int fd, int e) - : PollEvent(fd, e), cons(c) +Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e) + : PollEvent(fd, e), term(t) { } void -SimConsole::ListenEvent::process(int revent) +Terminal::ListenEvent::process(int revent) { - cons->accept(); + term->accept(); } /* * Poll event for the data socket */ -SimConsole::DataEvent::DataEvent(SimConsole *c, int fd, int e) - : PollEvent(fd, e), cons(c) +Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e) + : PollEvent(fd, e), term(t) { } void -SimConsole::DataEvent::process(int revent) +Terminal::DataEvent::process(int revent) { if (revent & POLLIN) - cons->data(); + term->data(); else if (revent & POLLNVAL) - cons->detach(); + term->detach(); } /* - * SimConsole code + * Terminal code */ -SimConsole::SimConsole(const Params *p) +Terminal::Terminal(const Params *p) : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number), data_fd(-1), txbuf(16384), rxbuf(16384), outfile(NULL) #if TRACING_ON == 1 , linebuf(16384) #endif { - if (!p->output.empty()) { - if (p->append_name) - outfile = simout.find(p->output + "." + p->name); - else - outfile = simout.find(p->output); - + if (p->output) { + outfile = simout.find(p->name); outfile->setf(ios::unitbuf); } @@ -110,7 +107,7 @@ SimConsole::SimConsole(const Params *p) listen(p->port); } -SimConsole::~SimConsole() +Terminal::~Terminal() { if (data_fd != -1) ::close(data_fd); @@ -123,15 +120,20 @@ SimConsole::~SimConsole() } /////////////////////////////////////////////////////////////////////// -// socket creation and console attach +// socket creation and terminal attach // void -SimConsole::listen(int port) +Terminal::listen(int port) { + if (ListenSocket::allDisabled()) { + warn_once("Sockets disabled, not accepting terminal connections"); + return; + } + while (!listener.listen(port, true)) { - DPRINTF(Console, - ": can't bind address console port %d inuse PID %d\n", + DPRINTF(Terminal, + ": can't bind address terminal port %d inuse PID %d\n", port, getpid()); port++; } @@ -147,15 +149,15 @@ SimConsole::listen(int port) } void -SimConsole::accept() +Terminal::accept() { if (!listener.islistening()) panic("%s: cannot accept a connection if not listening!", name()); int fd = listener.accept(true); if (data_fd != -1) { - char message[] = "console already attached!\n"; - ::write(fd, message, sizeof(message)); + char message[] = "terminal already attached!\n"; + atomic_write(fd, message, sizeof(message)); ::close(fd); return; } @@ -165,7 +167,7 @@ SimConsole::accept() pollQueue.schedule(dataEvent); stringstream stream; - ccprintf(stream, "==== m5 slave console: Console %d ====", number); + ccprintf(stream, "==== m5 slave terminal: Terminal %d ====", number); // we need an actual carriage return followed by a newline for the // terminal @@ -173,13 +175,13 @@ SimConsole::accept() write((const uint8_t *)stream.str().c_str(), stream.str().size()); - DPRINTFN("attach console %d\n", number); + DPRINTFN("attach terminal %d\n", number); txbuf.readall(data_fd); } void -SimConsole::detach() +Terminal::detach() { if (data_fd != -1) { ::close(data_fd); @@ -190,11 +192,11 @@ SimConsole::detach() delete dataEvent; dataEvent = NULL; - DPRINTFN("detach console %d\n", number); + DPRINTFN("detach terminal %d\n", number); } void -SimConsole::data() +Terminal::data() { uint8_t buf[1024]; int len; @@ -208,10 +210,10 @@ SimConsole::data() } size_t -SimConsole::read(uint8_t *buf, size_t len) +Terminal::read(uint8_t *buf, size_t len) { if (data_fd < 0) - panic("Console not properly attached.\n"); + panic("Terminal not properly attached.\n"); size_t ret; do { @@ -230,23 +232,16 @@ SimConsole::read(uint8_t *buf, size_t len) return ret; } -// Console output. +// Terminal output. size_t -SimConsole::write(const uint8_t *buf, size_t len) +Terminal::write(const uint8_t *buf, size_t len) { if (data_fd < 0) - panic("Console not properly attached.\n"); + panic("Terminal not properly attached.\n"); - size_t ret; - for (;;) { - ret = ::write(data_fd, buf, len); - - if (ret >= 0) - break; - - if (errno != EINTR) - detach(); - } + ssize_t ret = atomic_write(data_fd, buf, len); + if (ret < len) + detach(); return ret; } @@ -257,7 +252,7 @@ SimConsole::write(const uint8_t *buf, size_t len) #define RECEIVE_ERROR (ULL(3) << 62) uint8_t -SimConsole::in() +Terminal::in() { bool empty; uint8_t c; @@ -268,14 +263,14 @@ SimConsole::in() empty = rxbuf.empty(); - DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n", + DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n", isprint(c) ? c : ' ', c, !empty); return c; } uint64_t -SimConsole::console_in() +Terminal::console_in() { uint64_t value; @@ -287,26 +282,25 @@ SimConsole::console_in() value = RECEIVE_NONE; } - DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); + DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value); return value; } void -SimConsole::out(char c) +Terminal::out(char c) { #if TRACING_ON == 1 - if (DTRACE(Console)) { + if (DTRACE(Terminal)) { static char last = '\0'; - if (c != '\n' && c != '\r' || - last != '\n' && last != '\r') { + if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) { if (c == '\n' || c == '\r') { int size = linebuf.size(); char *buffer = new char[size + 1]; linebuf.read(buffer, size); buffer[size] = '\0'; - DPRINTF(Console, "%s\n", buffer); + DPRINTF(Terminal, "%s\n", buffer); delete [] buffer; } else { linebuf.write(c); @@ -325,13 +319,13 @@ SimConsole::out(char c) if (outfile) outfile->write(&c, 1); - DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", + DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n", isprint(c) ? c : ' ', (int)c); } -SimConsole * -SimConsoleParams::create() +Terminal * +TerminalParams::create() { - return new SimConsole(this); + return new Terminal(this); } diff --git a/src/dev/simconsole.hh b/src/dev/terminal.hh index c8d453960..d2499b6b2 100644 --- a/src/dev/simconsole.hh +++ b/src/dev/terminal.hh @@ -30,11 +30,11 @@ */ /* @file - * User Console Interface + * User Terminal Interface */ -#ifndef __CONSOLE_HH__ -#define __CONSOLE_HH__ +#ifndef __DEV_TERMINAL_HH__ +#define __DEV_TERMINAL_HH__ #include <iostream> @@ -43,12 +43,12 @@ #include "base/pollevent.hh" #include "base/socket.hh" #include "sim/sim_object.hh" -#include "params/SimConsole.hh" +#include "params/Terminal.hh" -class ConsoleListener; +class TerminalListener; class Uart; -class SimConsole : public SimObject +class Terminal : public SimObject { public: Uart *uart; @@ -57,10 +57,10 @@ class SimConsole : public SimObject class ListenEvent : public PollEvent { protected: - SimConsole *cons; + Terminal *term; public: - ListenEvent(SimConsole *c, int fd, int e); + ListenEvent(Terminal *t, int fd, int e); void process(int revent); }; @@ -70,10 +70,10 @@ class SimConsole : public SimObject class DataEvent : public PollEvent { protected: - SimConsole *cons; + Terminal *term; public: - DataEvent(SimConsole *c, int fd, int e); + DataEvent(Terminal *t, int fd, int e); void process(int revent); }; @@ -85,9 +85,9 @@ class SimConsole : public SimObject int data_fd; public: - typedef SimConsoleParams Params; - SimConsole(const Params *p); - ~SimConsole(); + typedef TerminalParams Params; + Terminal(const Params *p); + ~Terminal(); protected: ListenSocket listener; @@ -119,10 +119,10 @@ class SimConsole : public SimObject ///////////////// // OS interface - // Get a character from the console. + // Get a character from the terminal. uint8_t in(); - // get a character from the console in the console specific format + // get a character from the terminal in the console specific format // corresponds to GETC: // retval<63:61> // 000: success: character received @@ -136,11 +136,11 @@ class SimConsole : public SimObject // Interrupts are cleared when the buffer is empty. uint64_t console_in(); - // Send a character to the console + // Send a character to the terminal void out(char c); - //Ask the console if data is available + // Ask the terminal if data is available bool dataAvailable() { return !rxbuf.empty(); } }; -#endif // __CONSOLE_HH__ +#endif // __DEV_TERMINAL_HH__ diff --git a/src/dev/uart.cc b/src/dev/uart.cc index c9a2ae964..ab0ebde2c 100644 --- a/src/dev/uart.cc +++ b/src/dev/uart.cc @@ -32,17 +32,17 @@ * Implements a base class for UARTs */ -#include "dev/simconsole.hh" -#include "dev/uart.hh" #include "dev/platform.hh" +#include "dev/terminal.hh" +#include "dev/uart.hh" using namespace std; Uart::Uart(const Params *p) - : BasicPioDevice(p), platform(p->platform), cons(p->sim_console) + : BasicPioDevice(p), platform(p->platform), term(p->terminal) { status = 0; // set back pointers - cons->uart = this; + term->uart = this; } diff --git a/src/dev/uart.hh b/src/dev/uart.hh index f5d5e2855..ba10c204c 100644 --- a/src/dev/uart.hh +++ b/src/dev/uart.hh @@ -39,7 +39,7 @@ #include "dev/io_device.hh" #include "params/Uart.hh" -class SimConsole; +class Terminal; class Platform; const int RX_INT = 0x1; @@ -51,7 +51,7 @@ class Uart : public BasicPioDevice protected: int status; Platform *platform; - SimConsole *cons; + Terminal *term; public: typedef UartParams Params; diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc index b4dc93645..93f71f49b 100644 --- a/src/dev/uart8250.cc +++ b/src/dev/uart8250.cc @@ -38,9 +38,9 @@ #include "base/inifile.hh" #include "base/str.hh" // for to_number #include "base/trace.hh" -#include "dev/simconsole.hh" -#include "dev/uart8250.hh" #include "dev/platform.hh" +#include "dev/terminal.hh" +#include "dev/uart8250.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" @@ -48,7 +48,7 @@ using namespace std; using namespace TheISA; Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) - : Event(&mainEventQueue), uart(u) + : uart(u) { DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); intrBit = bit; @@ -93,9 +93,9 @@ Uart8250::IntrEvent::scheduleIntr() DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, curTick + interval); if (!scheduled()) - schedule(curTick + interval); + uart->schedule(this, curTick + interval); else - reschedule(curTick + interval); + uart->reschedule(this, curTick + interval); } @@ -120,8 +120,8 @@ Uart8250::read(PacketPtr pkt) switch (daddr) { case 0x0: if (!(LCR & 0x80)) { // read byte - if (cons->dataAvailable()) - pkt->set(cons->in()); + if (term->dataAvailable()) + pkt->set(term->in()); else { pkt->set((uint8_t)0); // A limited amount of these are ok. @@ -130,7 +130,7 @@ Uart8250::read(PacketPtr pkt) status &= ~RX_INT; platform->clearConsoleInt(); - if (cons->dataAvailable() && (IER & UART_IER_RDI)) + if (term->dataAvailable() && (IER & UART_IER_RDI)) rxIntrEvent.scheduleIntr(); } else { // dll divisor latch ; @@ -165,7 +165,7 @@ Uart8250::read(PacketPtr pkt) uint8_t lsr; lsr = 0; // check if there are any bytes to be read - if (cons->dataAvailable()) + if (term->dataAvailable()) lsr = UART_LSR_DR; lsr |= UART_LSR_TEMT | UART_LSR_THRE; pkt->set(lsr); @@ -201,7 +201,7 @@ Uart8250::write(PacketPtr pkt) switch (daddr) { case 0x0: if (!(LCR & 0x80)) { // write byte - cons->out(pkt->get<uint8_t>()); + term->out(pkt->get<uint8_t>()); platform->clearConsoleInt(); status &= ~TX_INT; if (UART_IER_THRI & IER) @@ -231,19 +231,19 @@ Uart8250::write(PacketPtr pkt) { DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); if (txIntrEvent.scheduled()) - txIntrEvent.deschedule(); + deschedule(txIntrEvent); if (status & TX_INT) platform->clearConsoleInt(); status &= ~TX_INT; } - if ((UART_IER_RDI & IER) && cons->dataAvailable()) { + if ((UART_IER_RDI & IER) && term->dataAvailable()) { DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); rxIntrEvent.scheduleIntr(); } else { DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); if (rxIntrEvent.scheduled()) - rxIntrEvent.deschedule(); + deschedule(rxIntrEvent); if (status & RX_INT) platform->clearConsoleInt(); status &= ~RX_INT; @@ -329,9 +329,9 @@ Uart8250::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxintrwhen); UNSERIALIZE_SCALAR(txintrwhen); if (rxintrwhen != 0) - rxIntrEvent.schedule(rxintrwhen); + schedule(rxIntrEvent, rxintrwhen); if (txintrwhen != 0) - txIntrEvent.schedule(txintrwhen); + schedule(txIntrEvent, txintrwhen); } Uart8250 * diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh index 2c69667e1..79c31d5cf 100644 --- a/src/dev/uart8250.hh +++ b/src/dev/uart8250.hh @@ -65,7 +65,7 @@ const uint8_t UART_LSR_DR = 0x01; const uint8_t UART_MCR_LOOP = 0x10; -class SimConsole; +class Terminal; class Platform; class Uart8250 : public Uart diff --git a/src/dev/x86/Cmos.py b/src/dev/x86/Cmos.py new file mode 100644 index 000000000..0a92145e2 --- /dev/null +++ b/src/dev/x86/Cmos.py @@ -0,0 +1,41 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from X86IntPin import X86IntSourcePin + +class Cmos(BasicPioDevice): + type = 'Cmos' + cxx_class='X86ISA::Cmos' + time = Param.Time('01/01/2009', + "System time to use ('Now' for actual time)") + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + int_pin = Param.X86IntSourcePin(X86IntSourcePin(), + 'Pin to signal RTC alarm interrupts to') diff --git a/src/dev/x86/I8042.py b/src/dev/x86/I8042.py new file mode 100644 index 000000000..31192adcd --- /dev/null +++ b/src/dev/x86/I8042.py @@ -0,0 +1,45 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from X86IntPin import X86IntSourcePin + +class I8042(BasicPioDevice): + type = 'I8042' + cxx_class = 'X86ISA::I8042' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + # This isn't actually used for anything here. + pio_addr = 0x0 + data_port = Param.Addr('Data port address') + command_port = Param.Addr('Command/status port address') + mouse_int_pin = Param.X86IntSourcePin(X86IntSourcePin(), + 'Pin to signal the mouse has data') + keyboard_int_pin = Param.X86IntSourcePin(X86IntSourcePin(), + 'Pin to signal the keyboard has data') diff --git a/src/dev/x86/I82094AA.py b/src/dev/x86/I82094AA.py new file mode 100644 index 000000000..9d57beed1 --- /dev/null +++ b/src/dev/x86/I82094AA.py @@ -0,0 +1,43 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from X86IntPin import X86IntSinkPin + +class I82094AA(BasicPioDevice): + type = 'I82094AA' + cxx_class = 'X86ISA::I82094AA' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + pio_addr = Param.Addr("Device address") + int_port = Port("Port for sending and receiving interrupt messages") + external_int_pic = Param.I8259(NULL, "External PIC, if any") + + def pin(self, line): + return X86IntSinkPin(device=self, number=line) diff --git a/src/dev/x86/I8237.py b/src/dev/x86/I8237.py new file mode 100644 index 000000000..20788a164 --- /dev/null +++ b/src/dev/x86/I8237.py @@ -0,0 +1,36 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice + +class I8237(BasicPioDevice): + type = 'I8237' + cxx_class = 'X86ISA::I8237' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") diff --git a/src/dev/x86/I8254.py b/src/dev/x86/I8254.py new file mode 100644 index 000000000..f468717cc --- /dev/null +++ b/src/dev/x86/I8254.py @@ -0,0 +1,39 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from X86IntPin import X86IntSourcePin + +class I8254(BasicPioDevice): + type = 'I8254' + cxx_class = 'X86ISA::I8254' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + int_pin = Param.X86IntSourcePin(X86IntSourcePin(), + 'Pin to signal timer interrupts to') diff --git a/src/dev/x86/I8259.py b/src/dev/x86/I8259.py new file mode 100644 index 000000000..0a516d30a --- /dev/null +++ b/src/dev/x86/I8259.py @@ -0,0 +1,50 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from X86IntPin import X86IntSourcePin, X86IntSinkPin + +class X86I8259CascadeMode(Enum): + map = {'I8259Master' : 0, + 'I8259Slave' : 1, + 'I8259Single' : 2 + } + +class I8259(BasicPioDevice): + type = 'I8259' + cxx_class='X86ISA::I8259' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + output = Param.X86IntSourcePin(X86IntSourcePin(), + 'The pin this I8259 drives') + mode = Param.X86I8259CascadeMode('How this I8259 is cascaded') + slave = Param.I8259(NULL, 'Slave I8259, if any') + + def pin(self, line): + return X86IntSinkPin(device=self, number=line) diff --git a/src/dev/x86/Opteron.py b/src/dev/x86/Opteron.py deleted file mode 100644 index cb015e2e7..000000000 --- a/src/dev/x86/Opteron.py +++ /dev/null @@ -1,18 +0,0 @@ -from m5.params import * -from m5.proxy import * -from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr -from Uart import Uart8250 -from Platform import Platform -from Pci import PciConfigAll -from SimConsole import SimConsole - -class Opteron(Platform): - type = 'Opteron' - system = Param.System(Parent.any, "system") - - pciconfig = PciConfigAll() - - def attachIO(self, bus): - self.pciconfig.pio = bus.default - bus.responder_set = True - bus.responder = self.pciconfig diff --git a/src/dev/x86/Pc.py b/src/dev/x86/Pc.py new file mode 100644 index 000000000..6f315cbcb --- /dev/null +++ b/src/dev/x86/Pc.py @@ -0,0 +1,83 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * + +from Device import IsaFake +from Pci import PciConfigAll +from Platform import Platform +from SouthBridge import SouthBridge +from Terminal import Terminal +from Uart import Uart8250 + +def x86IOAddress(port): + IO_address_space_base = 0x8000000000000000 + return IO_address_space_base + port; + +class Pc(Platform): + type = 'Pc' + system = Param.System(Parent.any, "system") + + pciconfig = PciConfigAll() + + south_bridge = SouthBridge() + + # "Non-existant" port used for timing purposes by the linux kernel + i_dont_exist = IsaFake(pio_addr=x86IOAddress(0x80), pio_size=1) + + # Ports behind the pci config and data regsiters. These don't do anything, + # but the linux kernel fiddles with them anway. + behind_pci = IsaFake(pio_addr=x86IOAddress(0xcf8), pio_size=8) + + # Serial port and terminal + terminal = Terminal() + com_1 = Uart8250() + com_1.pio_addr = x86IOAddress(0x3f8) + com_1.terminal = terminal + + # Devices to catch access to non-existant serial ports. + fake_com_2 = IsaFake(pio_addr=x86IOAddress(0x2f8), pio_size=8) + fake_com_3 = IsaFake(pio_addr=x86IOAddress(0x3e8), pio_size=8) + fake_com_4 = IsaFake(pio_addr=x86IOAddress(0x2e8), pio_size=8) + + # A device to catch accesses to the non-existant floppy controller. + fake_floppy = IsaFake(pio_addr=x86IOAddress(0x3f2), pio_size=2) + + def attachIO(self, bus): + self.south_bridge.attachIO(bus) + self.i_dont_exist.pio = bus.port + self.behind_pci.pio = bus.port + self.com_1.pio = bus.port + self.fake_com_2.pio = bus.port + self.fake_com_3.pio = bus.port + self.fake_com_4.pio = bus.port + self.fake_floppy.pio = bus.port + self.pciconfig.pio = bus.default + bus.responder_set = True + bus.responder = self.pciconfig diff --git a/src/dev/x86/PcSpeaker.py b/src/dev/x86/PcSpeaker.py new file mode 100644 index 000000000..7ca62ec1e --- /dev/null +++ b/src/dev/x86/PcSpeaker.py @@ -0,0 +1,37 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice + +class PcSpeaker(BasicPioDevice): + type = 'PcSpeaker' + cxx_class = 'X86ISA::Speaker' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + i8254 = Param.I8254('Timer that drives the speaker') diff --git a/src/dev/x86/SConscript b/src/dev/x86/SConscript index c500531b1..e7543dfdf 100644 --- a/src/dev/x86/SConscript +++ b/src/dev/x86/SConscript @@ -26,12 +26,44 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# Authors: Steve Reinhardt -# Gabe Black +# Authors: Gabe Black Import('*') if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'x86': - SimObject('Opteron.py') + SimObject('Pc.py') + Source('pc.cc') - Source('opteron.cc') + SimObject('SouthBridge.py') + Source('south_bridge.cc') + + SimObject('Cmos.py') + Source('cmos.cc') + TraceFlag('CMOS', 'Accesses to CMOS devices') + + SimObject('I8259.py') + Source('i8259.cc') + TraceFlag('I8259', 'Accesses to the I8259 PIC devices') + + SimObject('I8254.py') + Source('i8254.cc') + TraceFlag('I8254', 'Interrupts from the I8254 timer'); + + SimObject('I8237.py') + Source('i8237.cc') + TraceFlag('I8237', 'The I8237 dma controller'); + + SimObject('I8042.py') + Source('i8042.cc') + TraceFlag('I8042', 'The I8042 keyboard controller'); + + SimObject('PcSpeaker.py') + Source('speaker.cc') + TraceFlag('PcSpeaker') + + SimObject('I82094AA.py') + Source('i82094aa.cc') + TraceFlag('I82094AA') + + SimObject('X86IntPin.py') + Source('intdev.cc') diff --git a/src/dev/x86/SouthBridge.py b/src/dev/x86/SouthBridge.py new file mode 100644 index 000000000..d89ed9dc6 --- /dev/null +++ b/src/dev/x86/SouthBridge.py @@ -0,0 +1,122 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.proxy import * +from Cmos import Cmos +from I8042 import I8042 +from I82094AA import I82094AA +from I8237 import I8237 +from I8254 import I8254 +from I8259 import I8259 +from Ide import IdeController +from PcSpeaker import PcSpeaker +from X86IntPin import X86IntLine +from m5.SimObject import SimObject + +def x86IOAddress(port): + IO_address_space_base = 0x8000000000000000 + return IO_address_space_base + port; + +class SouthBridge(SimObject): + type = 'SouthBridge' + pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks") + platform = Param.Platform(Parent.any, "Platform this device is part of") + + _pic1 = I8259(pio_addr=x86IOAddress(0x20), mode='I8259Master') + _pic2 = I8259(pio_addr=x86IOAddress(0xA0), mode='I8259Slave') + _cmos = Cmos(pio_addr=x86IOAddress(0x70)) + _dma1 = I8237(pio_addr=x86IOAddress(0x0)) + _keyboard = I8042(data_port=x86IOAddress(0x60), \ + command_port=x86IOAddress(0x64)) + _pit = I8254(pio_addr=x86IOAddress(0x40)) + _speaker = PcSpeaker(pio_addr=x86IOAddress(0x61)) + _io_apic = I82094AA(pio_addr=0xFEC00000) + # This is to make sure the interrupt lines are instantiated. Don't use + # it for anything directly. + int_lines = VectorParam.X86IntLine([], "Interrupt lines") + + pic1 = Param.I8259(_pic1, "Master PIC") + pic2 = Param.I8259(_pic2, "Slave PIC") + cmos = Param.Cmos(_cmos, "CMOS memory and real time clock device") + dma1 = Param.I8237(_dma1, "The first dma controller") + keyboard = Param.I8042(_keyboard, "The keyboard controller") + pit = Param.I8254(_pit, "Programmable interval timer") + speaker = Param.PcSpeaker(_speaker, "PC speaker") + io_apic = Param.I82094AA(_io_apic, "I/O APIC") + + def connectPins(self, source, sink): + self.int_lines.append(X86IntLine(source=source, sink=sink)) + + # IDE controller + ide = IdeController(disks=[], pci_func=0, pci_dev=4, pci_bus=0) + ide.BAR0 = 0x1f0 + ide.BAR0LegacyIO = True + ide.BAR1 = 0x3f4 + ide.BAR1Size = '3B' + ide.BAR1LegacyIO = True + ide.BAR2 = 0x170 + ide.BAR2LegacyIO = True + ide.BAR3 = 0x374 + ide.BAR3Size = '3B' + ide.BAR3LegacyIO = True + ide.BAR4 = 1 + ide.Command = 1 + ide.InterruptLine = 14 + ide.InterruptPin = 1 + + def attachIO(self, bus): + # Route interupt signals + self.connectPins(self.pic1.output, self.io_apic.pin(0)) + self.connectPins(self.pic2.output, self.pic1.pin(2)) + self.connectPins(self.cmos.int_pin, self.pic2.pin(0)) + self.connectPins(self.pit.int_pin, self.pic1.pin(0)) + self.connectPins(self.pit.int_pin, self.io_apic.pin(2)) +# self.connectPins(self.keyboard.keyboard_int_pin, +# self.pic1.pin(1)) + self.connectPins(self.keyboard.keyboard_int_pin, + self.io_apic.pin(1)) +# self.connectPins(self.keyboard.mouse_int_pin, +# self.pic2.pin(4)) + self.connectPins(self.keyboard.mouse_int_pin, + self.io_apic.pin(12)) + # Tell the devices about each other + self.pic1.slave = self.pic2 + self.speaker.i8254 = self.pit + self.io_apic.external_int_pic = self.pic1 + # Connect to the bus + self.cmos.pio = bus.port + self.dma1.pio = bus.port + self.ide.pio = bus.port + self.keyboard.pio = bus.port + self.pic1.pio = bus.port + self.pic2.pio = bus.port + self.pit.pio = bus.port + self.speaker.pio = bus.port + self.io_apic.pio = bus.port + self.io_apic.int_port = bus.port diff --git a/src/dev/x86/X86IntPin.py b/src/dev/x86/X86IntPin.py new file mode 100644 index 000000000..35e274624 --- /dev/null +++ b/src/dev/x86/X86IntPin.py @@ -0,0 +1,51 @@ +# Copyright (c) 2008 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.params import * +from m5.SimObject import SimObject + +# A generic pin to drive an interrupt signal generated by a device. +class X86IntSourcePin(SimObject): + type = 'X86IntSourcePin' + cxx_class = 'X86ISA::IntSourcePin' + +# A generic pin to receive an interrupt signal generated by another device. +class X86IntSinkPin(SimObject): + type = 'X86IntSinkPin' + cxx_class = 'X86ISA::IntSinkPin' + + device = Param.SimObject("Device this pin belongs to") + number = Param.Int("The pin number on the device") + +# An interrupt line which is driven by a source pin and drives a sink pin. +class X86IntLine(SimObject): + type = 'X86IntLine' + cxx_class = 'X86ISA::IntLine' + + source = Param.X86IntSourcePin("Pin driving this line") + sink = Param.X86IntSinkPin("Pin driven by this line") diff --git a/src/dev/x86/cmos.cc b/src/dev/x86/cmos.cc new file mode 100644 index 000000000..e08c56e8c --- /dev/null +++ b/src/dev/x86/cmos.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "dev/x86/cmos.hh" +#include "dev/x86/intdev.hh" +#include "mem/packet_access.hh" + +void +X86ISA::Cmos::X86RTC::handleEvent() +{ + assert(intPin); + intPin->raise(); + //XXX This is a hack. + intPin->lower(); +} + +Tick +X86ISA::Cmos::read(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + switch(pkt->getAddr() - pioAddr) + { + case 0x0: + pkt->set(address); + break; + case 0x1: + pkt->set(readRegister(address)); + break; + default: + panic("Read from undefined CMOS port.\n"); + } + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::Cmos::write(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + switch(pkt->getAddr() - pioAddr) + { + case 0x0: + address = pkt->get<uint8_t>(); + break; + case 0x1: + writeRegister(address, pkt->get<uint8_t>()); + break; + default: + panic("Write to undefined CMOS port.\n"); + } + pkt->makeAtomicResponse(); + return latency; +} + +uint8_t +X86ISA::Cmos::readRegister(uint8_t reg) +{ + assert(reg < numRegs); + uint8_t val; + if (reg <= 0xD) { + val = rtc.readData(reg); + DPRINTF(CMOS, + "Reading CMOS RTC reg %x as %x.\n", reg, val); + } else { + val = regs[reg]; + DPRINTF(CMOS, + "Reading non-volitile CMOS address %x as %x.\n", reg, val); + } + return val; +} + +void +X86ISA::Cmos::writeRegister(uint8_t reg, uint8_t val) +{ + assert(reg < numRegs); + if (reg <= 0xD) { + DPRINTF(CMOS, "Writing CMOS RTC reg %x with %x.\n", + reg, val); + rtc.writeData(reg, val); + } else { + DPRINTF(CMOS, "Writing non-volitile CMOS address %x with %x.\n", + reg, val); + regs[reg] = val; + } +} + +X86ISA::Cmos * +CmosParams::create() +{ + return new X86ISA::Cmos(this); +} diff --git a/src/dev/x86/cmos.hh b/src/dev/x86/cmos.hh new file mode 100644 index 000000000..76276dbc1 --- /dev/null +++ b/src/dev/x86/cmos.hh @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_CMOS_HH__ +#define __DEV_X86_CMOS_HH__ + +#include "dev/io_device.hh" +#include "dev/mc146818.hh" +#include "params/Cmos.hh" + +namespace X86ISA +{ + +class IntSourcePin; + +class Cmos : public BasicPioDevice +{ + protected: + Tick latency; + + uint8_t address; + + static const int numRegs = 128; + + uint8_t regs[numRegs]; + + uint8_t readRegister(uint8_t reg); + void writeRegister(uint8_t reg, uint8_t val); + + class X86RTC : public MC146818 + { + protected: + IntSourcePin * intPin; + public: + X86RTC(EventManager *em, const std::string &n, const struct tm time, + bool bcd, Tick frequency, IntSourcePin * _intPin) : + MC146818(em, n, time, bcd, frequency), intPin(_intPin) + { + } + protected: + void handleEvent(); + } rtc; + + public: + typedef CmosParams Params; + + Cmos(const Params *p) : BasicPioDevice(p), latency(p->pio_latency), + rtc(this, "rtc", p->time, true, ULL(5000000000), p->int_pin) + { + pioSize = 2; + memset(regs, 0, numRegs * sizeof(uint8_t)); + address = 0; + } + + Tick read(PacketPtr pkt); + + Tick write(PacketPtr pkt); +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_CMOS_HH__ diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc new file mode 100644 index 000000000..afcbfdfb4 --- /dev/null +++ b/src/dev/x86/i8042.cc @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "base/bitunion.hh" +#include "dev/x86/i8042.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +// The 8042 has a whopping 32 bytes of internal RAM. +const uint8_t RamSize = 32; +const uint8_t NumOutputBits = 14; +const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83}; +const uint8_t X86ISA::PS2Mouse::ID[] = {0x00}; +const uint8_t CommandAck = 0xfa; +const uint8_t CommandNack = 0xfe; +const uint8_t BatSuccessful = 0xaa; + +void +X86ISA::I8042::addressRanges(AddrRangeList &range_list) +{ + range_list.clear(); + range_list.push_back(RangeSize(dataPort, 1)); + range_list.push_back(RangeSize(commandPort, 1)); +} + +void +X86ISA::I8042::writeData(uint8_t newData, bool mouse) +{ + DPRINTF(I8042, "Set data %#02x.\n", newData); + dataReg = newData; + statusReg.outputFull = 1; + statusReg.mouseOutputFull = (mouse ? 1 : 0); + if (!mouse && commandByte.keyboardFullInt) { + DPRINTF(I8042, "Sending keyboard interrupt.\n"); + keyboardIntPin->raise(); + //This is a hack + keyboardIntPin->lower(); + } else if (mouse && commandByte.mouseFullInt) { + DPRINTF(I8042, "Sending mouse interrupt.\n"); + mouseIntPin->raise(); + //This is a hack + mouseIntPin->lower(); + } +} + +void +X86ISA::PS2Device::ack() +{ + bufferData(&CommandAck, sizeof(CommandAck)); +} + +void +X86ISA::PS2Device::nack() +{ + bufferData(&CommandNack, sizeof(CommandNack)); +} + +void +X86ISA::PS2Device::bufferData(const uint8_t *data, int size) +{ + assert(data || size == 0); + while (size) { + outBuffer.push(*(data++)); + size--; + } +} + +uint8_t +X86ISA::I8042::readDataOut() +{ + uint8_t data = dataReg; + statusReg.outputFull = 0; + statusReg.mouseOutputFull = 0; + if (keyboard.hasData()) { + writeData(keyboard.getData(), false); + } else if (mouse.hasData()) { + writeData(mouse.getData(), true); + } + return data; +} + +bool +X86ISA::PS2Keyboard::processData(uint8_t data) +{ + if (lastCommand != NoCommand) { + switch (lastCommand) { + case LEDWrite: + DPRINTF(I8042, "Setting LEDs: " + "caps lock %s, num lock %s, scroll lock %s\n", + bits(data, 2) ? "on" : "off", + bits(data, 1) ? "on" : "off", + bits(data, 0) ? "on" : "off"); + ack(); + lastCommand = NoCommand; + break; + case TypematicInfo: + DPRINTF(I8042, "Setting typematic info to %#02x.\n", data); + ack(); + lastCommand = NoCommand; + break; + } + return hasData(); + } + switch (data) { + case LEDWrite: + DPRINTF(I8042, "Got LED write command.\n"); + ack(); + lastCommand = LEDWrite; + break; + case DiagnosticEcho: + panic("Keyboard diagnostic echo unimplemented.\n"); + case AlternateScanCodes: + panic("Accessing alternate scan codes unimplemented.\n"); + case ReadID: + DPRINTF(I8042, "Got keyboard read ID command.\n"); + ack(); + bufferData((uint8_t *)&ID, sizeof(ID)); + break; + case TypematicInfo: + DPRINTF(I8042, "Setting typematic info.\n"); + ack(); + lastCommand = TypematicInfo; + break; + case Enable: + DPRINTF(I8042, "Enabling the keyboard.\n"); + ack(); + break; + case Disable: + DPRINTF(I8042, "Disabling the keyboard.\n"); + ack(); + break; + case DefaultsAndDisable: + DPRINTF(I8042, "Disabling and resetting the keyboard.\n"); + ack(); + break; + case AllKeysToTypematic: + panic("Setting all keys to typemantic unimplemented.\n"); + case AllKeysToMakeRelease: + panic("Setting all keys to make/release unimplemented.\n"); + case AllKeysToMake: + panic("Setting all keys to make unimplemented.\n"); + case AllKeysToTypematicMakeRelease: + panic("Setting all keys to " + "typematic/make/release unimplemented.\n"); + case KeyToTypematic: + panic("Setting a key to typematic unimplemented.\n"); + case KeyToMakeRelease: + panic("Setting a key to make/release unimplemented.\n"); + case KeyToMakeOnly: + panic("Setting key to make only unimplemented.\n"); + case Resend: + panic("Keyboard resend unimplemented.\n"); + case Reset: + panic("Keyboard reset unimplemented.\n"); + default: + panic("Unknown keyboard command %#02x.\n", data); + } + return hasData(); +} + +bool +X86ISA::PS2Mouse::processData(uint8_t data) +{ + if (lastCommand != NoCommand) { + switch(lastCommand) { + case SetResolution: + DPRINTF(I8042, "Mouse resolution set to %d.\n", data); + resolution = data; + ack(); + lastCommand = NoCommand; + break; + case SampleRate: + DPRINTF(I8042, "Mouse sample rate %d samples " + "per second.\n", data); + sampleRate = data; + ack(); + lastCommand = NoCommand; + break; + default: + panic("Not expecting data for a mouse command.\n"); + } + return hasData(); + } + switch (data) { + case Scale1to1: + DPRINTF(I8042, "Setting mouse scale to 1:1.\n"); + status.twoToOne = 0; + ack(); + break; + case Scale2to1: + DPRINTF(I8042, "Setting mouse scale to 2:1.\n"); + status.twoToOne = 1; + ack(); + break; + case SetResolution: + DPRINTF(I8042, "Setting mouse resolution.\n"); + lastCommand = SetResolution; + ack(); + break; + case GetStatus: + DPRINTF(I8042, "Getting mouse status.\n"); + ack(); + bufferData((uint8_t *)&(status), 1); + bufferData(&resolution, sizeof(resolution)); + bufferData(&sampleRate, sizeof(sampleRate)); + break; + case ReadData: + panic("Reading mouse data unimplemented.\n"); + case ResetWrapMode: + panic("Resetting mouse wrap mode unimplemented.\n"); + case WrapMode: + panic("Setting mouse wrap mode unimplemented.\n"); + case RemoteMode: + panic("Setting mouse remote mode unimplemented.\n"); + case ReadID: + DPRINTF(I8042, "Mouse ID requested.\n"); + ack(); + bufferData(ID, sizeof(ID)); + break; + case SampleRate: + DPRINTF(I8042, "Setting mouse sample rate.\n"); + lastCommand = SampleRate; + ack(); + break; + case DisableReporting: + DPRINTF(I8042, "Disabling data reporting.\n"); + status.enabled = 0; + ack(); + break; + case EnableReporting: + DPRINTF(I8042, "Enabling data reporting.\n"); + status.enabled = 1; + ack(); + break; + case DefaultsAndDisable: + DPRINTF(I8042, "Disabling and resetting mouse.\n"); + sampleRate = 100; + resolution = 4; + status.twoToOne = 0; + status.enabled = 0; + ack(); + break; + case Resend: + panic("Mouse resend unimplemented.\n"); + case Reset: + DPRINTF(I8042, "Resetting the mouse.\n"); + sampleRate = 100; + resolution = 4; + status.twoToOne = 0; + status.enabled = 0; + ack(); + bufferData(&BatSuccessful, sizeof(BatSuccessful)); + bufferData(ID, sizeof(ID)); + break; + default: + warn("Unknown mouse command %#02x.\n", data); + nack(); + break; + } + return hasData(); +} + + +Tick +X86ISA::I8042::read(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + Addr addr = pkt->getAddr(); + if (addr == dataPort) { + uint8_t data = readDataOut(); + //DPRINTF(I8042, "Read from data port got %#02x.\n", data); + pkt->set<uint8_t>(data); + } else if (addr == commandPort) { + //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); + pkt->set<uint8_t>((uint8_t)statusReg); + } else { + panic("Read from unrecognized port %#x.\n", addr); + } + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::I8042::write(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + Addr addr = pkt->getAddr(); + uint8_t data = pkt->get<uint8_t>(); + if (addr == dataPort) { + statusReg.commandLast = 0; + switch (lastCommand) { + case NoCommand: + if (keyboard.processData(data)) { + writeData(keyboard.getData(), false); + } + break; + case WriteToMouse: + if (mouse.processData(data)) { + writeData(mouse.getData(), true); + } + break; + case WriteCommandByte: + commandByte = data; + DPRINTF(I8042, "Got data %#02x for \"Write " + "command byte\" command.\n", data); + statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest; + break; + case WriteMouseOutputBuff: + DPRINTF(I8042, "Got data %#02x for \"Write " + "mouse output buffer\" command.\n", data); + writeData(data, true); + break; + default: + panic("Data written for unrecognized " + "command %#02x\n", lastCommand); + } + lastCommand = NoCommand; + } else if (addr == commandPort) { + DPRINTF(I8042, "Got command %#02x.\n", data); + statusReg.commandLast = 1; + // These purposefully leave off the first byte of the controller RAM + // so it can be handled specially. + if (data > ReadControllerRamBase && + data < ReadControllerRamBase + RamSize) { + panic("Attempted to use i8042 read controller RAM command to " + "get byte %d.\n", data - ReadControllerRamBase); + } else if (data > WriteControllerRamBase && + data < WriteControllerRamBase + RamSize) { + panic("Attempted to use i8042 read controller RAM command to " + "get byte %d.\n", data - ReadControllerRamBase); + } else if (data >= PulseOutputBitBase && + data < PulseOutputBitBase + NumOutputBits) { + panic("Attempted to use i8042 pulse output bit command to " + "to pulse bit %d.\n", data - PulseOutputBitBase); + } + switch (data) { + case GetCommandByte: + DPRINTF(I8042, "Getting command byte.\n"); + writeData(commandByte); + break; + case WriteCommandByte: + DPRINTF(I8042, "Setting command byte.\n"); + lastCommand = WriteCommandByte; + break; + case CheckForPassword: + panic("i8042 \"Check for password\" command not implemented.\n"); + case LoadPassword: + panic("i8042 \"Load password\" command not implemented.\n"); + case CheckPassword: + panic("i8042 \"Check password\" command not implemented.\n"); + case DisableMouse: + DPRINTF(I8042, "Disabling mouse at controller.\n"); + commandByte.disableMouse = 1; + break; + case EnableMouse: + DPRINTF(I8042, "Enabling mouse at controller.\n"); + commandByte.disableMouse = 0; + break; + case TestMouse: + panic("i8042 \"Test mouse\" command not implemented.\n"); + case SelfTest: + panic("i8042 \"Self test\" command not implemented.\n"); + case InterfaceTest: + panic("i8042 \"Interface test\" command not implemented.\n"); + case DiagnosticDump: + panic("i8042 \"Diagnostic dump\" command not implemented.\n"); + case DisableKeyboard: + DPRINTF(I8042, "Disabling keyboard at controller.\n"); + commandByte.disableKeyboard = 1; + break; + case EnableKeyboard: + DPRINTF(I8042, "Enabling keyboard at controller.\n"); + commandByte.disableKeyboard = 0; + break; + case ReadInputPort: + panic("i8042 \"Read input port\" command not implemented.\n"); + case ContinuousPollLow: + panic("i8042 \"Continuous poll low\" command not implemented.\n"); + case ContinuousPollHigh: + panic("i8042 \"Continuous poll high\" command not implemented.\n"); + case ReadOutputPort: + panic("i8042 \"Read output port\" command not implemented.\n"); + case WriteOutputPort: + panic("i8042 \"Write output port\" command not implemented.\n"); + case WriteKeyboardOutputBuff: + panic("i8042 \"Write keyboard output buffer\" " + "command not implemented.\n"); + case WriteMouseOutputBuff: + DPRINTF(I8042, "Got command to write to mouse output buffer.\n"); + lastCommand = WriteMouseOutputBuff; + break; + case WriteToMouse: + DPRINTF(I8042, "Expecting mouse command.\n"); + lastCommand = WriteToMouse; + break; + case DisableA20: + panic("i8042 \"Disable A20\" command not implemented.\n"); + case EnableA20: + panic("i8042 \"Enable A20\" command not implemented.\n"); + case ReadTestInputs: + panic("i8042 \"Read test inputs\" command not implemented.\n"); + case SystemReset: + panic("i8042 \"System reset\" command not implemented.\n"); + default: + panic("Write to unknown i8042 " + "(keyboard controller) command port.\n"); + } + } else { + panic("Write to unrecognized port %#x.\n", addr); + } + pkt->makeAtomicResponse(); + return latency; +} + +X86ISA::I8042 * +I8042Params::create() +{ + return new X86ISA::I8042(this); +} diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh new file mode 100644 index 000000000..8a941f9a5 --- /dev/null +++ b/src/dev/x86/i8042.hh @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_I8042_HH__ +#define __DEV_X86_I8042_HH__ + +#include "dev/io_device.hh" +#include "dev/x86/intdev.hh" +#include "params/I8042.hh" + +#include <queue> + +namespace X86ISA +{ + +class IntPin; + +class PS2Device +{ + protected: + std::queue<uint8_t> outBuffer; + + static const uint16_t NoCommand = (uint16_t)(-1); + + uint16_t lastCommand; + void bufferData(const uint8_t *data, int size); + void ack(); + void nack(); + + public: + virtual ~PS2Device() + {}; + + PS2Device() : lastCommand(NoCommand) + {} + + bool hasData() + { + return !outBuffer.empty(); + } + + uint8_t getData() + { + uint8_t data = outBuffer.front(); + outBuffer.pop(); + return data; + } + + virtual bool processData(uint8_t data) = 0; +}; + +class PS2Mouse : public PS2Device +{ + protected: + static const uint8_t ID[]; + + enum Command + { + Scale1to1 = 0xE6, + Scale2to1 = 0xE7, + SetResolution = 0xE8, + GetStatus = 0xE9, + ReadData = 0xEB, + ResetWrapMode = 0xEC, + WrapMode = 0xEE, + RemoteMode = 0xF0, + ReadID = 0xF2, + SampleRate = 0xF3, + EnableReporting = 0xF4, + DisableReporting = 0xF5, + DefaultsAndDisable = 0xF6, + Resend = 0xFE, + Reset = 0xFF + }; + + BitUnion8(Status) + Bitfield<6> remote; + Bitfield<5> enabled; + Bitfield<4> twoToOne; + Bitfield<2> leftButton; + Bitfield<0> rightButton; + EndBitUnion(Status) + + Status status; + uint8_t resolution; + uint8_t sampleRate; + public: + PS2Mouse() : PS2Device(), status(0), resolution(4), sampleRate(100) + {} + + bool processData(uint8_t data); +}; + +class PS2Keyboard : public PS2Device +{ + protected: + static const uint8_t ID[]; + + enum Command + { + LEDWrite = 0xED, + DiagnosticEcho = 0xEE, + AlternateScanCodes = 0xF0, + ReadID = 0xF2, + TypematicInfo = 0xF3, + Enable = 0xF4, + Disable = 0xF5, + DefaultsAndDisable = 0xF6, + AllKeysToTypematic = 0xF7, + AllKeysToMakeRelease = 0xF8, + AllKeysToMake = 0xF9, + AllKeysToTypematicMakeRelease = 0xFA, + KeyToTypematic = 0xFB, + KeyToMakeRelease = 0xFC, + KeyToMakeOnly = 0xFD, + Resend = 0xFE, + Reset = 0xFF + }; + + public: + bool processData(uint8_t data); +}; + +class I8042 : public BasicPioDevice +{ + protected: + enum Command + { + GetCommandByte = 0x20, + ReadControllerRamBase = 0x20, + WriteCommandByte = 0x60, + WriteControllerRamBase = 0x60, + CheckForPassword = 0xA4, + LoadPassword = 0xA5, + CheckPassword = 0xA6, + DisableMouse = 0xA7, + EnableMouse = 0xA8, + TestMouse = 0xA9, + SelfTest = 0xAA, + InterfaceTest = 0xAB, + DiagnosticDump = 0xAC, + DisableKeyboard = 0xAD, + EnableKeyboard = 0xAE, + ReadInputPort = 0xC0, + ContinuousPollLow = 0xC1, + ContinuousPollHigh = 0xC2, + ReadOutputPort = 0xD0, + WriteOutputPort = 0xD1, + WriteKeyboardOutputBuff = 0xD2, + WriteMouseOutputBuff = 0xD3, + WriteToMouse = 0xD4, + DisableA20 = 0xDD, + EnableA20 = 0xDF, + ReadTestInputs = 0xE0, + PulseOutputBitBase = 0xF0, + SystemReset = 0xFE + }; + + BitUnion8(StatusReg) + Bitfield<7> parityError; + Bitfield<6> timeout; + Bitfield<5> mouseOutputFull; + Bitfield<4> keyboardUnlocked; + Bitfield<3> commandLast; + Bitfield<2> passedSelfTest; + Bitfield<1> inputFull; + Bitfield<0> outputFull; + EndBitUnion(StatusReg) + + BitUnion8(CommandByte) + Bitfield<6> convertScanCodes; + Bitfield<5> disableMouse; + Bitfield<4> disableKeyboard; + Bitfield<2> passedSelfTest; + Bitfield<1> mouseFullInt; + Bitfield<0> keyboardFullInt; + EndBitUnion(CommandByte) + + Tick latency; + Addr dataPort; + Addr commandPort; + + StatusReg statusReg; + CommandByte commandByte; + + uint8_t dataReg; + + static const uint16_t NoCommand = (uint16_t)(-1); + uint16_t lastCommand; + + IntSourcePin *mouseIntPin; + IntSourcePin *keyboardIntPin; + + PS2Mouse mouse; + PS2Keyboard keyboard; + + void writeData(uint8_t newData, bool mouse = false); + uint8_t readDataOut(); + + public: + typedef I8042Params Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + I8042(Params *p) : BasicPioDevice(p), latency(p->pio_latency), + dataPort(p->data_port), commandPort(p->command_port), + statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand), + mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin) + { + statusReg.passedSelfTest = 1; + statusReg.commandLast = 1; + statusReg.keyboardUnlocked = 1; + + commandByte.convertScanCodes = 1; + commandByte.passedSelfTest = 1; + commandByte.keyboardFullInt = 1; + } + + void addressRanges(AddrRangeList &range_list); + + Tick read(PacketPtr pkt); + + Tick write(PacketPtr pkt); +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_I8042_HH__ diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc new file mode 100644 index 000000000..d160fcb24 --- /dev/null +++ b/src/dev/x86/i82094aa.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/intmessage.hh" +#include "dev/x86/i82094aa.hh" +#include "dev/x86/i8259.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" +#include "sim/system.hh" + +X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this), + latency(p->pio_latency), pioAddr(p->pio_addr), + extIntPic(p->external_int_pic) +{ + // This assumes there's only one I/O APIC in the system + id = sys->numContexts(); + assert(id <= 0xf); + arbId = id; + regSel = 0; + RedirTableEntry entry = 0; + entry.mask = 1; + for (int i = 0; i < TableSize; i++) { + redirTable[i] = entry; + pinStates[i] = false; + } +} + +Tick +X86ISA::I82094AA::read(PacketPtr pkt) +{ + assert(pkt->getSize() == 4); + Addr offset = pkt->getAddr() - pioAddr; + switch(offset) { + case 0: + pkt->set<uint32_t>(regSel); + break; + case 16: + pkt->set<uint32_t>(readReg(regSel)); + break; + default: + panic("Illegal read from I/O APIC.\n"); + } + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::I82094AA::write(PacketPtr pkt) +{ + assert(pkt->getSize() == 4); + Addr offset = pkt->getAddr() - pioAddr; + switch(offset) { + case 0: + regSel = pkt->get<uint32_t>(); + break; + case 16: + writeReg(regSel, pkt->get<uint32_t>()); + break; + default: + panic("Illegal write to I/O APIC.\n"); + } + pkt->makeAtomicResponse(); + return latency; +} + +void +X86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value) +{ + if (offset == 0x0) { + id = bits(value, 27, 24); + } else if (offset == 0x1) { + // The IOAPICVER register is read only. + } else if (offset == 0x2) { + arbId = bits(value, 27, 24); + } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) { + int index = (offset - 0x10) / 2; + if (offset % 2) { + redirTable[index].topDW = value; + redirTable[index].topReserved = 0; + } else { + redirTable[index].bottomDW = value; + redirTable[index].bottomReserved = 0; + } + } else { + warn("Access to undefined I/O APIC register %#x.\n", offset); + } + DPRINTF(I82094AA, + "Wrote %#x to I/O APIC register %#x .\n", value, offset); +} + +uint32_t +X86ISA::I82094AA::readReg(uint8_t offset) +{ + uint32_t result = 0; + if (offset == 0x0) { + result = id << 24; + } else if (offset == 0x1) { + result = ((TableSize - 1) << 16) | APICVersion; + } else if (offset == 0x2) { + result = arbId << 24; + } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) { + int index = (offset - 0x10) / 2; + if (offset % 2) { + result = redirTable[index].topDW; + } else { + result = redirTable[index].bottomDW; + } + } else { + warn("Access to undefined I/O APIC register %#x.\n", offset); + } + DPRINTF(I82094AA, + "Read %#x from I/O APIC register %#x.\n", result, offset); + return result; +} + +void +X86ISA::I82094AA::signalInterrupt(int line) +{ + DPRINTF(I82094AA, "Received interrupt %d.\n", line); + assert(line < TableSize); + RedirTableEntry entry = redirTable[line]; + if (entry.mask) { + DPRINTF(I82094AA, "Entry was masked.\n"); + return; + } else { + TriggerIntMessage message; + message.destination = entry.dest; + if (entry.deliveryMode == DeliveryMode::ExtInt) { + assert(extIntPic); + message.vector = extIntPic->getVector(); + } else { + message.vector = entry.vector; + } + message.deliveryMode = entry.deliveryMode; + message.destMode = entry.destMode; + message.level = entry.polarity; + message.trigger = entry.trigger; + + if (DeliveryMode::isReserved(entry.deliveryMode)) { + fatal("Tried to use reserved delivery mode " + "for IO APIC entry %d.\n", line); + } else if (DTRACE(I82094AA)) { + DPRINTF(I82094AA, "Delivery mode is: %s.\n", + DeliveryMode::names[entry.deliveryMode]); + DPRINTF(I82094AA, "Vector is %#x.\n", message.vector); + } + + if (entry.destMode == 0) { + DPRINTF(I82094AA, + "Sending interrupt to APIC ID %d.\n", entry.dest); + PacketPtr pkt = buildIntRequest(entry.dest, message); + if (sys->getMemoryMode() == Enums::timing) + intPort->sendMessageTiming(pkt, latency); + else if (sys->getMemoryMode() == Enums::atomic) + intPort->sendMessageAtomic(pkt); + else + panic("Unrecognized memory mode.\n"); + } else { + DPRINTF(I82094AA, "Sending interrupts to APIC IDs:" + "%s%s%s%s%s%s%s%s\n", + bits((int)entry.dest, 0) ? " 0": "", + bits((int)entry.dest, 1) ? " 1": "", + bits((int)entry.dest, 2) ? " 2": "", + bits((int)entry.dest, 3) ? " 3": "", + bits((int)entry.dest, 4) ? " 4": "", + bits((int)entry.dest, 5) ? " 5": "", + bits((int)entry.dest, 6) ? " 6": "", + bits((int)entry.dest, 7) ? " 7": "" + ); + uint8_t dests = entry.dest; + uint8_t id = 0; + while(dests) { + if (dests & 0x1) { + PacketPtr pkt = buildIntRequest(id, message); + if (sys->getMemoryMode() == Enums::timing) + intPort->sendMessageTiming(pkt, latency); + else if (sys->getMemoryMode() == Enums::atomic) + intPort->sendMessageAtomic(pkt); + else + panic("Unrecognized memory mode.\n"); + } + dests >>= 1; + id++; + } + } + } +} + +void +X86ISA::I82094AA::raiseInterruptPin(int number) +{ + assert(number < TableSize); + if (!pinStates[number]) + signalInterrupt(number); + pinStates[number] = true; +} + +void +X86ISA::I82094AA::lowerInterruptPin(int number) +{ + assert(number < TableSize); + pinStates[number] = false; +} + +X86ISA::I82094AA * +I82094AAParams::create() +{ + return new X86ISA::I82094AA(this); +} diff --git a/src/dev/x86/i82094aa.hh b/src/dev/x86/i82094aa.hh new file mode 100644 index 000000000..b11e2bcb1 --- /dev/null +++ b/src/dev/x86/i82094aa.hh @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_I82094AA_HH__ +#define __DEV_X86_I82094AA_HH__ + +#include "base/bitunion.hh" +#include "base/range_map.hh" +#include "dev/io_device.hh" +#include "dev/x86/intdev.hh" +#include "params/I82094AA.hh" + +namespace X86ISA +{ + +class I8259; + +class I82094AA : public PioDevice, public IntDev +{ + public: + BitUnion64(RedirTableEntry) + Bitfield<63, 32> topDW; + Bitfield<55, 32> topReserved; + Bitfield<31, 0> bottomDW; + Bitfield<31, 17> bottomReserved; + Bitfield<63, 56> dest; + Bitfield<16> mask; + Bitfield<15> trigger; + Bitfield<14> remoteIRR; + Bitfield<13> polarity; + Bitfield<12> deliveryStatus; + Bitfield<11> destMode; + Bitfield<10, 8> deliveryMode; + Bitfield<7, 0> vector; + EndBitUnion(RedirTableEntry) + + protected: + Tick latency; + Addr pioAddr; + + I8259 * extIntPic; + + uint8_t regSel; + uint8_t id; + uint8_t arbId; + + static const uint8_t TableSize = 24; + // This implementation is based on version 0x11, but 0x14 avoids having + // to deal with the arbitration and APIC bus guck. + static const uint8_t APICVersion = 0x14; + + RedirTableEntry redirTable[TableSize]; + bool pinStates[TableSize]; + + public: + typedef I82094AAParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + I82094AA(Params *p); + + Tick read(PacketPtr pkt); + Tick write(PacketPtr pkt); + + void addressRanges(AddrRangeList &range_list) + { + range_list.clear(); + range_list.push_back(RangeEx(pioAddr, pioAddr + 4)); + range_list.push_back(RangeEx(pioAddr + 16, pioAddr + 20)); + } + + void getIntAddrRange(AddrRangeList &range_list) + { + range_list.clear(); + range_list.push_back(RangeEx(x86InterruptAddress(1, 0), + x86InterruptAddress(1, 0) + PhysAddrAPICRangeSize)); + } + + void writeReg(uint8_t offset, uint32_t value); + uint32_t readReg(uint8_t offset); + + Port *getPort(const std::string &if_name, int idx = -1) + { + if (if_name == "int_port") + return intPort; + return PioDevice::getPort(if_name, idx); + } + + void signalInterrupt(int line); + void raiseInterruptPin(int number); + void lowerInterruptPin(int number); +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__ diff --git a/src/dev/x86/i8237.cc b/src/dev/x86/i8237.cc new file mode 100644 index 000000000..f6ea9d75f --- /dev/null +++ b/src/dev/x86/i8237.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "dev/x86/i8237.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +Tick +X86ISA::I8237::read(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + Addr offset = pkt->getAddr() - pioAddr; + switch (offset) { + case 0x0: + panic("Read from i8237 channel 0 current address unimplemented.\n"); + case 0x1: + panic("Read from i8237 channel 0 remaining " + "word count unimplemented.\n"); + case 0x2: + panic("Read from i8237 channel 1 current address unimplemented.\n"); + case 0x3: + panic("Read from i8237 channel 1 remaining " + "word count unimplemented.\n"); + case 0x4: + panic("Read from i8237 channel 2 current address unimplemented.\n"); + case 0x5: + panic("Read from i8237 channel 2 remaining " + "word count unimplemented.\n"); + case 0x6: + panic("Read from i8237 channel 3 current address unimplemented.\n"); + case 0x7: + panic("Read from i8237 channel 3 remaining " + "word count unimplemented.\n"); + case 0x8: + panic("Read from i8237 status register unimplemented.\n"); + default: + panic("Read from undefined i8237 register %d.\n", offset); + } + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::I8237::write(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + Addr offset = pkt->getAddr() - pioAddr; + switch (offset) { + case 0x0: + panic("Write to i8237 channel 0 starting address unimplemented.\n"); + case 0x1: + panic("Write to i8237 channel 0 starting " + "word count unimplemented.\n"); + case 0x2: + panic("Write to i8237 channel 1 starting address unimplemented.\n"); + case 0x3: + panic("Write to i8237 channel 1 starting " + "word count unimplemented.\n"); + case 0x4: + panic("Write to i8237 channel 2 starting address unimplemented.\n"); + case 0x5: + panic("Write to i8237 channel 2 starting " + "word count unimplemented.\n"); + case 0x6: + panic("Write to i8237 channel 3 starting address unimplemented.\n"); + case 0x7: + panic("Write to i8237 channel 3 starting " + "word count unimplemented.\n"); + case 0x8: + panic("Write to i8237 command register unimplemented.\n"); + case 0x9: + panic("Write to i8237 request register unimplemented.\n"); + case 0xa: + { + uint8_t command = pkt->get<uint8_t>(); + uint8_t select = bits(command, 1, 0); + uint8_t bitVal = bits(command, 2); + if (!bitVal) + panic("Turning on i8237 channels unimplemented.\n"); + replaceBits(maskReg, select, bitVal); + } + break; + case 0xb: + panic("Write to i8237 mode register unimplemented.\n"); + case 0xc: + panic("Write to i8237 clear LSB/MSB flip-flop " + "register unimplemented.\n"); + case 0xd: + panic("Write to i8237 master clear/reset register unimplemented.\n"); + case 0xe: + panic("Write to i8237 clear mask register unimplemented.\n"); + case 0xf: + panic("Write to i8237 write all mask register bits unimplemented.\n"); + default: + panic("Write to undefined i8254 register.\n"); + } + pkt->makeAtomicResponse(); + return latency; +} + +X86ISA::I8237 * +I8237Params::create() +{ + return new X86ISA::I8237(this); +} diff --git a/src/cpu/o3/sparc/params.hh b/src/dev/x86/i8237.hh index 09f523818..2d73b8ab5 100644 --- a/src/cpu/o3/sparc/params.hh +++ b/src/dev/x86/i8237.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,34 +28,39 @@ * Authors: Gabe Black */ -#ifndef __CPU_O3_SPARC_PARAMS_HH__ -#define __CPU_O3_SPARC_PARAMS_HH__ +#ifndef __DEV_X86_I8237_HH__ +#define __DEV_X86_I8237_HH__ -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" +#include "dev/io_device.hh" +#include "params/I8237.hh" -//Forward declarations -namespace SparcISA +namespace X86ISA { - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ -class SparcSimpleParams : public O3Params +class I8237 : public BasicPioDevice { + protected: + Tick latency; + uint8_t maskReg; + public: + typedef I8237Params Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } - SparcISA::ITB *itb; - SparcISA::DTB *dtb; + I8237(Params *p) : BasicPioDevice(p), latency(p->pio_latency), maskReg(0) + { + pioSize = 16; + } + Tick read(PacketPtr pkt); + + Tick write(PacketPtr pkt); }; -#endif // __CPU_O3_SPARC_PARAMS_HH__ +}; // namespace X86ISA + +#endif //__DEV_X86_I8237_HH__ diff --git a/src/base/stats/statdb.cc b/src/dev/x86/i8254.cc index f9136807a..5eb28844a 100644 --- a/src/base/stats/statdb.cc +++ b/src/dev/x86/i8254.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,59 +25,59 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Nathan Binkert + * Authors: Gabe Black */ -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/statistics.hh" -#include "base/stats/statdb.hh" +#include "dev/x86/i8254.hh" +#include "dev/x86/intdev.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" -using namespace std; - -namespace Stats { -namespace Database { - -StatData * -find(void *stat) +void +X86ISA::I8254::counterInterrupt(unsigned int num) { - stat_map_t::const_iterator i = map().find(stat); - - if (i == map().end()) - return NULL; - - return (*i).second; + DPRINTF(I8254, "Interrupt from counter %d.\n", num); + if (num == 0) { + intPin->raise(); + //XXX This is a hack. + intPin->lower(); + } } -void -regStat(void *stat, StatData *data) +Tick +X86ISA::I8254::read(PacketPtr pkt) { - if (map().find(stat) != map().end()) - panic("shouldn't register stat twice!"); - - stats().push_back(data); - -#ifndef NDEBUG - pair<stat_map_t::iterator, bool> result = -#endif - map().insert(make_pair(stat, data)); - assert(result.second && "this should never fail"); - assert(map().find(stat) != map().end()); + assert(pkt->getSize() == 1); + Addr offset = pkt->getAddr() - pioAddr; + if (offset < 3) { + pkt->set(pit.readCounter(offset)); + } else if (offset == 3) { + pkt->set(uint8_t(-1)); + } else { + panic("Read from undefined i8254 register.\n"); + } + pkt->makeAtomicResponse(); + return latency; } -void -regPrint(void *stat) +Tick +X86ISA::I8254::write(PacketPtr pkt) { - StatData *data = find(stat); - assert(data); - data->flags |= print; + assert(pkt->getSize() == 1); + Addr offset = pkt->getAddr() - pioAddr; + if (offset < 3) { + pit.writeCounter(offset, pkt->get<uint8_t>()); + } else if (offset == 3) { + pit.writeControl(pkt->get<uint8_t>()); + } else { + panic("Write to undefined i8254 register.\n"); + } + pkt->makeAtomicResponse(); + return latency; } -TheDatabase &db() +X86ISA::I8254 * +I8254Params::create() { - static TheDatabase db; - return db; + return new X86ISA::I8254(this); } - -/* namespace Database */ } -/* namespace Stats */ } diff --git a/src/dev/x86/i8254.hh b/src/dev/x86/i8254.hh new file mode 100644 index 000000000..7de20dfd4 --- /dev/null +++ b/src/dev/x86/i8254.hh @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_I8254_HH__ +#define __DEV_X86_I8254_HH__ + +#include "dev/intel_8254_timer.hh" +#include "dev/io_device.hh" +#include "params/I8254.hh" + +namespace X86ISA +{ + +class IntSourcePin; + +class I8254 : public BasicPioDevice +{ + protected: + Tick latency; + class X86Intel8254Timer : public Intel8254Timer + { + protected: + I8254 * parent; + + void + counterInterrupt(unsigned int num) + { + parent->counterInterrupt(num); + } + + public: + X86Intel8254Timer(const std::string &name, I8254 * _parent) : + Intel8254Timer(_parent, name), parent(_parent) + {} + }; + + + X86Intel8254Timer pit; + + IntSourcePin *intPin; + + void counterInterrupt(unsigned int num); + + public: + typedef I8254Params Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + I8254(Params *p) : BasicPioDevice(p), latency(p->pio_latency), + pit(p->name, this), intPin(p->int_pin) + { + pioSize = 4; + } + Tick read(PacketPtr pkt); + + Tick write(PacketPtr pkt); + + bool + outputHigh(unsigned int num) + { + return pit.outputHigh(num); + } + + uint8_t + readCounter(unsigned int num) + { + return pit.readCounter(num); + } + + void + writeCounter(unsigned int num, const uint8_t data) + { + pit.writeCounter(num, data); + } + + void + writeControl(uint8_t val) + { + pit.writeControl(val); + } +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__ diff --git a/src/dev/x86/i8259.cc b/src/dev/x86/i8259.cc new file mode 100644 index 000000000..b868295eb --- /dev/null +++ b/src/dev/x86/i8259.cc @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "base/bitfield.hh" +#include "dev/x86/i82094aa.hh" +#include "dev/x86/i8259.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +X86ISA::I8259::I8259(Params * p) : BasicPioDevice(p), IntDev(this), + latency(p->pio_latency), output(p->output), + mode(p->mode), slave(p->slave), + IRR(0), ISR(0), IMR(0), + readIRR(true), initControlWord(0), autoEOI(false) +{ + for (int i = 0; i < NumLines; i++) + pinStates[i] = false; + pioSize = 2; +} + +Tick +X86ISA::I8259::read(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + switch(pkt->getAddr() - pioAddr) + { + case 0x0: + if (readIRR) { + DPRINTF(I8259, "Reading IRR as %#x.\n", IRR); + pkt->set(IRR); + } else { + DPRINTF(I8259, "Reading ISR as %#x.\n", ISR); + pkt->set(ISR); + } + break; + case 0x1: + DPRINTF(I8259, "Reading IMR as %#x.\n", IMR); + pkt->set(IMR); + break; + } + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::I8259::write(PacketPtr pkt) +{ + assert(pkt->getSize() == 1); + uint8_t val = pkt->get<uint8_t>(); + switch (pkt->getAddr() - pioAddr) { + case 0x0: + if (bits(val, 4)) { + DPRINTF(I8259, "Received initialization command word 1.\n"); + IMR = 0; + edgeTriggered = bits(val, 3); + DPRINTF(I8259, "%s triggered mode.\n", + edgeTriggered ? "Edge" : "Level"); + cascadeMode = !bits(val, 1); + DPRINTF(I8259, "%s mode.\n", + cascadeMode ? "Cascade" : "Single"); + expectICW4 = bits(val, 0); + if (!expectICW4) { + autoEOI = false; + } + initControlWord = 1; + DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2); + } else if (bits(val, 4, 3) == 0) { + DPRINTF(I8259, "Received operation command word 2.\n"); + switch (bits(val, 7, 5)) { + case 0x0: + DPRINTF(I8259, + "Subcommand: Rotate in auto-EOI mode (clear).\n"); + break; + case 0x1: + { + int line = findMsbSet(ISR); + DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n", + line); + handleEOI(line); + } + break; + case 0x2: + DPRINTF(I8259, "Subcommand: No operation.\n"); + break; + case 0x3: + { + int line = bits(val, 2, 0); + DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n", + line); + handleEOI(line); + } + break; + case 0x4: + DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n"); + break; + case 0x5: + DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n"); + break; + case 0x6: + DPRINTF(I8259, "Subcommand: Set priority command.\n"); + DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n", + bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8); + break; + case 0x7: + DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n"); + DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n", + bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8); + break; + } + } else if (bits(val, 4, 3) == 1) { + DPRINTF(I8259, "Received operation command word 3.\n"); + if (bits(val, 7)) { + DPRINTF(I8259, "%s special mask mode.\n", + bits(val, 6) ? "Set" : "Clear"); + } + if (bits(val, 1)) { + readIRR = bits(val, 0); + DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR"); + } + } + break; + case 0x1: + switch (initControlWord) { + case 0x0: + DPRINTF(I8259, "Received operation command word 1.\n"); + DPRINTF(I8259, "Wrote IMR value %#x.\n", val); + IMR = val; + break; + case 0x1: + DPRINTF(I8259, "Received initialization command word 2.\n"); + vectorOffset = val & ~mask(3); + DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n", + vectorOffset, vectorOffset | mask(3)); + if (cascadeMode) { + initControlWord++; + } else { + cascadeBits = 0; + initControlWord = 0; + } + break; + case 0x2: + DPRINTF(I8259, "Received initialization command word 3.\n"); + if (mode == Enums::I8259Master) { + DPRINTF(I8259, "Slaves attached to IRQs:%s%s%s%s%s%s%s%s\n", + bits(val, 0) ? " 0" : "", + bits(val, 1) ? " 1" : "", + bits(val, 2) ? " 2" : "", + bits(val, 3) ? " 3" : "", + bits(val, 4) ? " 4" : "", + bits(val, 5) ? " 5" : "", + bits(val, 6) ? " 6" : "", + bits(val, 7) ? " 7" : ""); + cascadeBits = val; + } else { + DPRINTF(I8259, "Slave ID is %d.\n", val & mask(3)); + cascadeBits = val & mask(3); + } + if (expectICW4) + initControlWord++; + else + initControlWord = 0; + break; + case 0x3: + DPRINTF(I8259, "Received initialization command word 4.\n"); + if (bits(val, 4)) { + DPRINTF(I8259, "Special fully nested mode.\n"); + } else { + DPRINTF(I8259, "Not special fully nested mode.\n"); + } + if (bits(val, 3) == 0) { + DPRINTF(I8259, "Nonbuffered.\n"); + } else if (bits(val, 2) == 0) { + DPRINTF(I8259, "Buffered.\n"); + } else { + DPRINTF(I8259, "Unrecognized buffer mode.\n"); + } + autoEOI = bits(val, 1); + DPRINTF(I8259, "%s End Of Interrupt.\n", + autoEOI ? "Automatic" : "Normal"); + + DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85"); + initControlWord = 0; + break; + } + break; + } + pkt->makeAtomicResponse(); + return latency; +} + +void +X86ISA::I8259::handleEOI(int line) +{ + ISR &= ~(1 << line); + // There may be an interrupt that was waiting which can + // now be sent. + if (IRR) + requestInterrupt(findMsbSet(IRR)); +} + +void +X86ISA::I8259::requestInterrupt(int line) +{ + if (bits(ISR, 7, line) == 0) { + if (output) { + DPRINTF(I8259, "Propogating interrupt.\n"); + output->raise(); + //XXX This is a hack. + output->lower(); + } else { + warn("Received interrupt but didn't have " + "anyone to tell about it.\n"); + } + } +} + +void +X86ISA::I8259::signalInterrupt(int line) +{ + DPRINTF(I8259, "Interrupt requested for line %d.\n", line); + if (line >= NumLines) + fatal("Line number %d doesn't exist. The max is %d.\n", + line, NumLines - 1); + if (bits(IMR, line)) { + DPRINTF(I8259, "Interrupt %d was masked.\n", line); + } else { + IRR |= 1 << line; + requestInterrupt(line); + } +} + +void +X86ISA::I8259::raiseInterruptPin(int number) +{ + DPRINTF(I8259, "Interrupt signal raised for pin %d.\n", number); + if (number >= NumLines) + fatal("Line number %d doesn't exist. The max is %d.\n", + number, NumLines - 1); + if (!pinStates[number]) + signalInterrupt(number); + pinStates[number] = true; +} + +void +X86ISA::I8259::lowerInterruptPin(int number) +{ + DPRINTF(I8259, "Interrupt signal lowered for pin %d.\n", number); + if (number >= NumLines) + fatal("Line number %d doesn't exist. The max is %d.\n", + number, NumLines - 1); + pinStates[number] = false; +} + +int +X86ISA::I8259::getVector() +{ + /* + * This code only handles one slave. Since that's how the PC platform + * always uses the 8259 PIC, there shouldn't be any need for more. If + * there -is- a need for more for some reason, "slave" can become a + * vector of slaves. + */ + int line = findMsbSet(IRR); + IRR &= ~(1 << line); + DPRINTF(I8259, "Interrupt %d was accepted.\n", line); + if (autoEOI) { + handleEOI(line); + } else { + ISR |= 1 << line; + } + if (slave && bits(cascadeBits, line)) { + DPRINTF(I8259, "Interrupt was from slave who will " + "provide the vector.\n"); + return slave->getVector(); + } + return line | vectorOffset; +} + +X86ISA::I8259 * +I8259Params::create() +{ + return new X86ISA::I8259(this); +} diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh new file mode 100644 index 000000000..dfb56646a --- /dev/null +++ b/src/dev/x86/i8259.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_I8259_HH__ +#define __DEV_X86_I8259_HH__ + +#include "dev/io_device.hh" +#include "dev/x86/intdev.hh" +#include "params/I8259.hh" +#include "enums/X86I8259CascadeMode.hh" + +namespace X86ISA +{ + +class I82094AA; + +class I8259 : public BasicPioDevice, public IntDev +{ + protected: + static const int NumLines = 8; + bool pinStates[NumLines]; + + Tick latency; + IntSourcePin *output; + Enums::X86I8259CascadeMode mode; + I8259 * slave; + + // Interrupt Request Register + uint8_t IRR; + // In Service Register + uint8_t ISR; + // Interrupt Mask Register + uint8_t IMR; + + // The higher order bits of the vector to return + uint8_t vectorOffset; + + bool cascadeMode; + // A bit vector of lines with slaves attached, or the slave id, depending + // on if this is a master or slave PIC. + uint8_t cascadeBits; + + bool edgeTriggered; + bool readIRR; + + // State machine information for reading in initialization control words. + bool expectICW4; + int initControlWord; + + // Whether or not the PIC is in auto EOI mode. + bool autoEOI; + + void requestInterrupt(int line); + void handleEOI(int line); + + public: + typedef I8259Params Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + I8259(Params * p); + + Tick read(PacketPtr pkt); + Tick write(PacketPtr pkt); + + void signalInterrupt(int line); + void raiseInterruptPin(int number); + void lowerInterruptPin(int number); + int getVector(); +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_I8259_HH__ diff --git a/src/dev/x86/intdev.cc b/src/dev/x86/intdev.cc new file mode 100644 index 000000000..e386687a9 --- /dev/null +++ b/src/dev/x86/intdev.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "dev/x86/intdev.hh" + +X86ISA::IntSourcePin * +X86IntSourcePinParams::create() +{ + return new X86ISA::IntSourcePin(this); +} + +X86ISA::IntSinkPin * +X86IntSinkPinParams::create() +{ + return new X86ISA::IntSinkPin(this); +} + +X86ISA::IntLine * +X86IntLineParams::create() +{ + return new X86ISA::IntLine(this); +} diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh new file mode 100644 index 000000000..ca8e7eea5 --- /dev/null +++ b/src/dev/x86/intdev.hh @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_INTDEV_HH__ +#define __DEV_X86_INTDEV_HH__ + +#include <assert.h> +#include <string> + +#include "arch/x86/x86_traits.hh" +#include "mem/mem_object.hh" +#include "mem/mport.hh" +#include "sim/sim_object.hh" +#include "params/X86IntSourcePin.hh" +#include "params/X86IntSinkPin.hh" +#include "params/X86IntLine.hh" + +namespace X86ISA { + +class IntDev +{ + protected: + class IntPort : public MessagePort + { + IntDev * device; + Tick latency; + Addr intAddr; + public: + IntPort(const std::string &_name, MemObject * _parent, + IntDev *dev, Tick _latency) : + MessagePort(_name, _parent), device(dev), latency(_latency) + { + } + + void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) + { + snoop = false; + device->getIntAddrRange(resp); + } + + Tick recvMessage(PacketPtr pkt) + { + return device->recvMessage(pkt); + } + + void recvStatusChange(Status status) + { + if (status == RangeChange) { + sendStatusChange(Port::RangeChange); + } + } + + }; + + IntPort * intPort; + + public: + IntDev(MemObject * parent, Tick latency = 0) + { + if (parent != NULL) { + intPort = new IntPort(parent->name() + ".int_port", + parent, this, latency); + } else { + intPort = NULL; + } + } + + virtual ~IntDev() + {} + + virtual void + signalInterrupt(int line) + { + panic("signalInterrupt not implemented.\n"); + } + + virtual void + raiseInterruptPin(int number) + { + panic("raiseInterruptPin not implemented.\n"); + } + + virtual void + lowerInterruptPin(int number) + { + panic("lowerInterruptPin not implemented.\n"); + } + + virtual Tick + recvMessage(PacketPtr pkt) + { + panic("recvMessage not implemented.\n"); + return 0; + } + + virtual void + getIntAddrRange(AddrRangeList &range_list) + { + panic("intAddrRange not implemented.\n"); + } +}; + +class IntSinkPin : public SimObject +{ + public: + IntDev * device; + int number; + + typedef X86IntSinkPinParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + IntSinkPin(Params *p) : SimObject(p), + device(dynamic_cast<IntDev *>(p->device)), number(p->number) + { + assert(device); + } +}; + +class IntSourcePin : public SimObject +{ + protected: + std::vector<IntSinkPin *> sinks; + + public: + typedef X86IntSourcePinParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + void + addSink(IntSinkPin *sink) + { + sinks.push_back(sink); + } + + void + raise() + { + for (int i = 0; i < sinks.size(); i++) { + const IntSinkPin &pin = *sinks[i]; + pin.device->raiseInterruptPin(pin.number); + } + } + + void + lower() + { + for (int i = 0; i < sinks.size(); i++) { + const IntSinkPin &pin = *sinks[i]; + pin.device->lowerInterruptPin(pin.number); + } + } + + IntSourcePin(Params *p) : SimObject(p) + {} +}; + +class IntLine : public SimObject +{ + protected: + IntSourcePin *source; + IntSinkPin *sink; + + public: + typedef X86IntLineParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + IntLine(Params *p) : SimObject(p), source(p->source), sink(p->sink) + { + source->addSink(sink); + } +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_INTDEV_HH__ diff --git a/src/dev/x86/pc.cc b/src/dev/x86/pc.cc new file mode 100644 index 000000000..d1ab4af7f --- /dev/null +++ b/src/dev/x86/pc.cc @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +/** @file + * Implementation of PC platform. + */ + +#include <deque> +#include <string> +#include <vector> + +#include "arch/x86/intmessage.hh" +#include "arch/x86/x86_traits.hh" +#include "cpu/intr_control.hh" +#include "dev/terminal.hh" +#include "dev/x86/i82094aa.hh" +#include "dev/x86/i8254.hh" +#include "dev/x86/i8259.hh" +#include "dev/x86/pc.hh" +#include "dev/x86/south_bridge.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +Pc::Pc(const Params *p) + : Platform(p), system(p->system) +{ + southBridge = NULL; + // set the back pointer from the system to myself + system->platform = this; +} + +void +Pc::init() +{ + assert(southBridge); + + /* + * Initialize the timer. + */ + I8254 & timer = *southBridge->pit; + //Timer 0, mode 2, no bcd, 16 bit count + timer.writeControl(0x34); + //Timer 0, latch command + timer.writeControl(0x00); + //Write a 16 bit count of 0 + timer.writeCounter(0, 0); + timer.writeCounter(0, 0); + + /* + * Initialize the I/O APIC. + */ + I82094AA & ioApic = *southBridge->ioApic; + I82094AA::RedirTableEntry entry = 0; + entry.deliveryMode = DeliveryMode::ExtInt; + entry.vector = 0x20; + ioApic.writeReg(0x10, entry.bottomDW); + ioApic.writeReg(0x11, entry.topDW); + entry.deliveryMode = DeliveryMode::Fixed; + entry.vector = 0x24; + ioApic.writeReg(0x18, entry.bottomDW); + ioApic.writeReg(0x19, entry.topDW); + entry.mask = 1; + entry.vector = 0x21; + ioApic.writeReg(0x12, entry.bottomDW); + ioApic.writeReg(0x13, entry.topDW); + entry.vector = 0x20; + ioApic.writeReg(0x14, entry.bottomDW); + ioApic.writeReg(0x15, entry.topDW); + entry.vector = 0x28; + ioApic.writeReg(0x20, entry.bottomDW); + ioApic.writeReg(0x21, entry.topDW); + entry.vector = 0x2C; + ioApic.writeReg(0x28, entry.bottomDW); + ioApic.writeReg(0x29, entry.topDW); + entry.vector = 0x2E; + ioApic.writeReg(0x2C, entry.bottomDW); + ioApic.writeReg(0x2D, entry.topDW); + entry.vector = 0x30; + ioApic.writeReg(0x30, entry.bottomDW); + ioApic.writeReg(0x31, entry.topDW); +} + +Tick +Pc::intrFrequency() +{ + panic("Need implementation for intrFrequency\n"); + M5_DUMMY_RETURN +} + +void +Pc::postConsoleInt() +{ + southBridge->ioApic->signalInterrupt(4); + southBridge->pic1->signalInterrupt(4); +} + +void +Pc::clearConsoleInt() +{ + warn_once("Don't know what interrupt to clear for console.\n"); + //panic("Need implementation\n"); +} + +void +Pc::postPciInt(int line) +{ + southBridge->ioApic->signalInterrupt(line); +} + +void +Pc::clearPciInt(int line) +{ + warn_once("Tried to clear PCI interrupt %d\n", line); +} + +Addr +Pc::pciToDma(Addr pciAddr) const +{ + return pciAddr; +} + +Addr +Pc::calcPciConfigAddr(int bus, int dev, int func) +{ + assert(func < 8); + assert(dev < 32); + assert(bus == 0); + return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11)); +} + +Addr +Pc::calcPciIOAddr(Addr addr) +{ + return PhysAddrPrefixIO + addr; +} + +Addr +Pc::calcPciMemAddr(Addr addr) +{ + return addr; +} + +Pc * +PcParams::create() +{ + return new Pc(this); +} diff --git a/src/dev/x86/opteron.hh b/src/dev/x86/pc.hh index 3026bce73..427cc4165 100644 --- a/src/dev/x86/opteron.hh +++ b/src/dev/x86/pc.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,29 +30,36 @@ /** * @file - * Declaration of top level class for the Opteron platform chips. This class + * Declaration of top level class for PC platform components. This class * just retains pointers to all its children so the children can communicate. */ -#ifndef __DEV_Opteron_HH__ -#define __DEV_Opteron_HH__ +#ifndef __DEV_PC_HH__ +#define __DEV_PC_HH__ #include "dev/platform.hh" -#include "params/Opteron.hh" +#include "params/Pc.hh" class IdeController; class System; +class SouthBridge; -class Opteron : public Platform +class Pc : public Platform { public: /** Pointer to the system */ System *system; + SouthBridge *southBridge; public: - typedef OpteronParams Params; + typedef PcParams Params; - Opteron(const Params *p); + /** + * Do platform initialization stuff + */ + void init(); + + Pc(const Params *p); /** * Return the interrupting frequency to AlphaAccess @@ -86,7 +93,17 @@ class Opteron : public Platform /** * Calculate the configuration address given a bus/dev/func. */ - virtual Addr calcConfigAddr(int bus, int dev, int func); + virtual Addr calcPciConfigAddr(int bus, int dev, int func); + + /** + * Calculate the address for an IO location on the PCI bus. + */ + virtual Addr calcPciIOAddr(Addr addr); + + /** + * Calculate the address for a memory location on the PCI bus. + */ + virtual Addr calcPciMemAddr(Addr addr); }; -#endif // __DEV_OPTERON_HH__ +#endif // __DEV_PC_HH__ diff --git a/src/dev/x86/south_bridge.cc b/src/dev/x86/south_bridge.cc new file mode 100644 index 000000000..c456f478d --- /dev/null +++ b/src/dev/x86/south_bridge.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include <assert.h> + +#include "dev/x86/pc.hh" +#include "dev/x86/south_bridge.hh" + +using namespace X86ISA; + +SouthBridge::SouthBridge(const Params *p) : SimObject(p), + platform(p->platform), pit(p->pit), pic1(p->pic1), pic2(p->pic2), + cmos(p->cmos), speaker(p->speaker), ioApic(p->io_apic) +{ + // Let the platform know where we are + Pc * pc = dynamic_cast<Pc *>(platform); + assert(pc); + pc->southBridge = this; +} + +SouthBridge * +SouthBridgeParams::create() +{ + return new SouthBridge(this); +} diff --git a/src/dev/x86/south_bridge.hh b/src/dev/x86/south_bridge.hh new file mode 100644 index 000000000..61d6d387a --- /dev/null +++ b/src/dev/x86/south_bridge.hh @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __DEV_X86_SOUTH_BRIDGE_HH__ +#define __DEV_X86_SOUTH_BRIDGE_HH__ + +#include "sim/sim_object.hh" +#include "params/SouthBridge.hh" + +namespace X86ISA +{ + class I8254; + class I8259; + class Cmos; + class Speaker; + class I82094AA; +} + +class SouthBridge : public SimObject +{ + protected: + Platform * platform; + + public: + X86ISA::I8254 * pit; + X86ISA::I8259 * pic1; + X86ISA::I8259 * pic2; + X86ISA::Cmos * cmos; + X86ISA::Speaker * speaker; + X86ISA::I82094AA * ioApic; + + public: + typedef SouthBridgeParams Params; + SouthBridge(const Params *p); + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } +}; + +#endif //__DEV_X86_SOUTH_BRIDGE_HH__ diff --git a/src/dev/x86/speaker.cc b/src/dev/x86/speaker.cc new file mode 100644 index 000000000..c6eb9db9e --- /dev/null +++ b/src/dev/x86/speaker.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "base/bitunion.hh" +#include "base/trace.hh" +#include "dev/x86/i8254.hh" +#include "dev/x86/speaker.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +Tick +X86ISA::Speaker::read(PacketPtr pkt) +{ + assert(pkt->getAddr() == pioAddr); + assert(pkt->getSize() == 1); + controlVal.timer = timer->outputHigh(2) ? 1 : 0; + DPRINTF(PcSpeaker, + "Reading from speaker device: gate %s, speaker %s, output %s.\n", + controlVal.gate ? "on" : "off", + controlVal.speaker ? "on" : "off", + controlVal.timer ? "on" : "off"); + pkt->set((uint8_t)controlVal); + pkt->makeAtomicResponse(); + return latency; +} + +Tick +X86ISA::Speaker::write(PacketPtr pkt) +{ + assert(pkt->getAddr() == pioAddr); + assert(pkt->getSize() == 1); + SpeakerControl val = pkt->get<uint8_t>(); + controlVal.gate = val.gate; + //Change the gate value in the timer. + if (!val.gate) + warn("The gate bit of the pc speaker isn't implemented and " + "is always on.\n"); + //This would control whether the timer output is hooked up to a physical + //speaker. Since M5 can't make noise, it's value doesn't actually do + //anything. + controlVal.speaker = val.speaker; + DPRINTF(PcSpeaker, "Writing to speaker device: gate %s, speaker %s.\n", + controlVal.gate ? "on" : "off", controlVal.speaker ? "on" : "off"); + pkt->makeAtomicResponse(); + return latency; +} + +X86ISA::Speaker * +PcSpeakerParams::create() +{ + return new X86ISA::Speaker(this); +} diff --git a/src/arch/arm/syscallreturn.hh b/src/dev/x86/speaker.hh index ad46c2232..6778dcb28 100644 --- a/src/arch/arm/syscallreturn.hh +++ b/src/dev/x86/speaker.hh @@ -1,6 +1,5 @@ /* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * Copyright (c) 2007-2008 The Florida State University + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,31 +26,54 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black - * Korey Sewell - * Stephen Hines */ -#ifndef __ARCH_ARM_SYSCALLRETURN_HH__ -#define __ARCH_ARM_SYSCALLRETURN_HH__ +#ifndef __DEV_X86_SPEAKER_HH__ +#define __DEV_X86_SPEAKER_HH__ -#include "sim/syscallreturn.hh" -#include "cpu/thread_context.hh" +#include "base/bitunion.hh" +#include "params/PcSpeaker.hh" -namespace ArmISA +namespace X86ISA { - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext *tc) + +class I8254; + +class Speaker : public BasicPioDevice +{ + protected: + Tick latency; + + BitUnion8(SpeakerControl) + Bitfield<0> gate; + Bitfield<1> speaker; + Bitfield<5> timer; + EndBitUnion(SpeakerControl) + + SpeakerControl controlVal; + + I8254 * timer; + + public: + typedef PcSpeakerParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + Speaker(Params *p) : BasicPioDevice(p), + latency(p->pio_latency), controlVal(0), timer(p->i8254) { - if (return_value.successful()) { - // no error - //regs->setIntReg(SyscallSuccessReg, 0); - tc->setIntReg(ReturnValueReg, return_value.value()); - } else { - // got an error, return details - //regs->setIntReg(SyscallSuccessReg, (IntReg) -1); - tc->setIntReg(ReturnValueReg, return_value.value()); - } + pioSize = 1; } -} -#endif + Tick read(PacketPtr pkt); + + Tick write(PacketPtr pkt); +}; + +}; // namespace X86ISA + +#endif //__DEV_X86_SPEAKER_HH__ diff --git a/src/kern/SConscript b/src/kern/SConscript index 509e6b3f7..fc682aee0 100644 --- a/src/kern/SConscript +++ b/src/kern/SConscript @@ -40,11 +40,13 @@ if env['FULL_SYSTEM']: Source('linux/events.cc') Source('linux/linux_syscalls.cc') Source('linux/printk.cc') - + if env['TARGET_ISA'] == 'alpha': Source('tru64/dump_mbuf.cc') Source('tru64/printf.cc') Source('tru64/tru64_events.cc') Source('tru64/tru64_syscalls.cc') TraceFlag('BADADDR') - +else: + Source('linux/linux.cc') + Source('operatingsystem.cc') diff --git a/src/kern/kernel_stats.hh b/src/kern/kernel_stats.hh index 66248c9c8..85a47ec00 100644 --- a/src/kern/kernel_stats.hh +++ b/src/kern/kernel_stats.hh @@ -51,17 +51,17 @@ class Statistics : public Serializable std::string myname; protected: - Stats::Scalar<> _arm; - Stats::Scalar<> _quiesce; - Stats::Scalar<> _hwrei; + Stats::Scalar _arm; + Stats::Scalar _quiesce; + Stats::Scalar _hwrei; - Stats::Vector<> _iplCount; - Stats::Vector<> _iplGood; - Stats::Vector<> _iplTicks; + Stats::Vector _iplCount; + Stats::Vector _iplGood; + Stats::Vector _iplTicks; Stats::Formula _iplUsed; - Stats::Vector<> _syscall; -// Stats::Vector<> _faults; + Stats::Vector _syscall; +// Stats::Vector _faults; private: int iplLast; diff --git a/src/arch/alpha/syscallreturn.hh b/src/kern/linux/linux.cc index 47b4ac8c7..b14e3c709 100644 --- a/src/arch/alpha/syscallreturn.hh +++ b/src/kern/linux/linux.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2005 The Regents of The University of Michigan + * Copyright (c) 2009 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,34 +25,41 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Steve Reinhardt - * Gabe Black + * Authors: Ali Saidi */ -#ifndef __ARCH_ALPHA_SYSCALLRETURN_HH__ -#define __ARCH_ALPHA_SYSCALLRETURN_HH__ +#include <string> #include "cpu/thread_context.hh" -#include "sim/syscallreturn.hh" +#include "kern/linux/linux.hh" +#include "sim/process.hh" +#include "sim/system.hh" -namespace AlphaISA +int +Linux::openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc) { - static inline void setSyscallReturn(SyscallReturn return_value, - ThreadContext * tc) - { - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - tc->setIntReg(SyscallSuccessReg, 0); - tc->setIntReg(ReturnValueReg, return_value.value()); - } else { - // got an error, return details - tc->setIntReg(SyscallSuccessReg, (IntReg)-1); - tc->setIntReg(ReturnValueReg, -return_value.value()); - } + DPRINTF(SyscallVerbose, "Opening special file: %s\n", path.c_str()); + if (path.compare(0, 13, "/proc/meminfo") == 0) { + std::string data = Linux::procMeminfo(process, tc); + FILE *f = tmpfile(); + int fd = fileno(f); + int ret M5_VAR_USED = fwrite(data.c_str(), 1, data.size(), f); + assert(ret == data.size()); + rewind(f); + return fd; } + + warn("Attempting to open special file: %s. Ignorning. Simulation may" + " take un-expected code path or be non-deterministic until proper" + " handling is implemented.\n", path.c_str()); + return -1; +} + +std::string +Linux::procMeminfo(LiveProcess *process, ThreadContext *tc) +{ + return csprintf("MemTotal:%12d kB\nMemFree: %12d kB\n", + process->system->memSize() >> 10, + process->system->freeMemSize() >> 10); } -#endif diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh index 6e0b37d91..ad35fa726 100644 --- a/src/kern/linux/linux.hh +++ b/src/kern/linux/linux.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2004-2009 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,9 +39,13 @@ class Linux {}; #else //!FULL_SYSTEM #include <inttypes.h> +#include <string> #include "kern/operatingsystem.hh" +class ThreadContext; +class LiveProcess; + /// /// This class encapsulates the types, structures, constants, /// functions, and syscall-number mappings specific to the Alpha Linux @@ -65,46 +69,46 @@ class Linux : public OperatingSystem /// gets #defined to something else on some systems. This type /// can be specialized by architecture specific "Linux" classes typedef struct { - uint32_t st_dev; //!< device - uint32_t st_ino; //!< inode - uint32_t st_mode; //!< mode - uint32_t st_nlink; //!< link count - uint32_t st_uid; //!< owner's user ID - uint32_t st_gid; //!< owner's group ID - uint32_t st_rdev; //!< device number - int32_t _pad1; //!< for alignment - int64_t st_size; //!< file size in bytes - uint64_t st_atimeX; //!< time of last access - uint64_t st_mtimeX; //!< time of last modification - uint64_t st_ctimeX; //!< time of last status change - uint32_t st_blksize; //!< optimal I/O block size - int32_t st_blocks; //!< number of blocks allocated - uint32_t st_flags; //!< flags - uint32_t st_gen; //!< unknown + uint32_t st_dev; //!< device + uint32_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + uint32_t st_uid; //!< owner's user ID + uint32_t st_gid; //!< owner's group ID + uint32_t st_rdev; //!< device number + int32_t _pad1; //!< for alignment + int64_t st_size; //!< file size in bytes + uint64_t st_atimeX; //!< time of last access + uint64_t st_mtimeX; //!< time of last modification + uint64_t st_ctimeX; //!< time of last status change + uint32_t st_blksize; //!< optimal I/O block size + int32_t st_blocks; //!< number of blocks allocated + uint32_t st_flags; //!< flags + uint32_t st_gen; //!< unknown } tgt_stat; // same for stat64 typedef struct { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_rdev; - int64_t st_size; - uint64_t st_blocks; - - uint32_t st_mode; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_blksize; - uint32_t st_nlink; - uint32_t __pad0; - - uint64_t st_atimeX; - uint64_t st_atime_nsec; - uint64_t st_mtimeX; - uint64_t st_mtime_nsec; - uint64_t st_ctimeX; - uint64_t st_ctime_nsec; - int64_t ___unused[3]; + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_rdev; + int64_t st_size; + uint64_t st_blocks; + + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_blksize; + uint32_t st_nlink; + uint32_t __pad0; + + uint64_t st_atimeX; + uint64_t st_atime_nsec; + uint64_t st_mtimeX; + uint64_t st_mtime_nsec; + uint64_t st_ctimeX; + uint64_t st_ctime_nsec; + int64_t ___unused[3]; } tgt_stat64; /// Length of strings in struct utsname (plus 1 for null char). @@ -112,23 +116,23 @@ class Linux : public OperatingSystem /// Interface struct for uname(). struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. }; /// Limit struct for getrlimit/setrlimit. struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit }; /// For gettimeofday(). struct timeval { - int64_t tv_sec; //!< seconds - int64_t tv_usec; //!< microseconds + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds }; // For writev/readv @@ -140,24 +144,27 @@ class Linux : public OperatingSystem /// For getrusage(). struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - int64_t ru_maxrss; //!< max rss - int64_t ru_ixrss; //!< integral shared memory size - int64_t ru_idrss; //!< integral unshared data " - int64_t ru_isrss; //!< integral unshared stack " - int64_t ru_minflt; //!< page reclaims - total vmfaults - int64_t ru_majflt; //!< page faults - int64_t ru_nswap; //!< swaps - int64_t ru_inblock; //!< block input operations - int64_t ru_oublock; //!< block output operations - int64_t ru_msgsnd; //!< messages sent - int64_t ru_msgrcv; //!< messages received - int64_t ru_nsignals; //!< signals received - int64_t ru_nvcsw; //!< voluntary context switches - int64_t ru_nivcsw; //!< involuntary " + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " }; + static int openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc); + static std::string procMeminfo(LiveProcess *process, ThreadContext *tc); + }; // class Linux diff --git a/src/kern/operatingsystem.cc b/src/kern/operatingsystem.cc new file mode 100644 index 000000000..8951b8193 --- /dev/null +++ b/src/kern/operatingsystem.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + + +#include "kern/operatingsystem.hh" +#include "base/misc.hh" + +int +OperatingSystem::openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc) +{ + warn("Attempting to open special file: %s. Ignorning. Simulation may" + " take un-expected code path or be non-deterministic until proper" + " handling is implemented.\n", path.c_str()); + return -1; +} + + diff --git a/src/kern/operatingsystem.hh b/src/kern/operatingsystem.hh index 99358ae03..712b97c35 100644 --- a/src/kern/operatingsystem.hh +++ b/src/kern/operatingsystem.hh @@ -40,12 +40,16 @@ class OperatingSystem {}; #else //!FULL_SYSTEM +#include <string> + +class LiveProcess; +class ThreadContext; /// This struct is used to build an target-OS-dependent table that /// maps the target's open() flags to the host open() flags. struct OpenFlagTransTable { - int tgtFlag; //!< Target system flag value. - int hostFlag; //!< Corresponding host system flag value. + int tgtFlag; //!< Target system flag value. + int hostFlag; //!< Corresponding host system flag value. }; @@ -71,23 +75,23 @@ class OperatingSystem { /// Interface struct for uname(). typedef struct { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. } utsname; /// Limit struct for getrlimit/setrlimit. typedef struct { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit } rlimit; /// For gettimeofday(). typedef struct { - int64_t tv_sec; //!< seconds - int64_t tv_usec; //!< microseconds + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds } timeval; // For writev/readv @@ -99,24 +103,26 @@ class OperatingSystem { /// For getrusage(). typedef struct { - timeval ru_utime; //!< user time used - timeval ru_stime; //!< system time used - int64_t ru_maxrss; //!< max rss - int64_t ru_ixrss; //!< integral shared memory size - int64_t ru_idrss; //!< integral unshared data " - int64_t ru_isrss; //!< integral unshared stack " - int64_t ru_minflt; //!< page reclaims - total vmfaults - int64_t ru_majflt; //!< page faults - int64_t ru_nswap; //!< swaps - int64_t ru_inblock; //!< block input operations - int64_t ru_oublock; //!< block output operations - int64_t ru_msgsnd; //!< messages sent - int64_t ru_msgrcv; //!< messages received - int64_t ru_nsignals; //!< signals received - int64_t ru_nvcsw; //!< voluntary context switches - int64_t ru_nivcsw; //!< involuntary " + timeval ru_utime; //!< user time used + timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " } rusage; + static int openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc); + }; // class OperatingSystem diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh index ed574fdbf..a55ce2c80 100644 --- a/src/kern/solaris/solaris.hh +++ b/src/kern/solaris/solaris.hh @@ -76,39 +76,39 @@ class Solaris : public OperatingSystem /// Stat buffer. Note that we can't call it 'stat' since that /// gets #defined to something else on some systems. typedef struct { - uint64_t st_dev; //!< device - uint64_t st_ino; //!< inode - uint32_t st_mode; //!< mode - uint32_t st_nlink; //!< link count - int32_t st_uid; //!< owner's user ID - int32_t st_gid; //!< owner's group ID - uint64_t st_rdev; //!< device number - int64_t st_size; //!< file size in bytes - //struct tgt_timespec st_atimeX; //!< time of last access - //struct tgt_timespec st_mtimeX; //!< time of last modification - //struct tgt_timespec st_ctimeX; //!< time of last status change + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + //struct tgt_timespec st_atimeX; //!< time of last access + //struct tgt_timespec st_mtimeX; //!< time of last modification + //struct tgt_timespec st_ctimeX; //!< time of last status change int64_t st_atimeX, st_mtimeX, st_ctimeX; - int32_t st_blksize; //!< optimal I/O block size - int64_t st_blocks; //!< number of blocks allocated + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated char st_fstype[16]; } tgt_stat; // same for stat64 typedef struct { - uint64_t st_dev; //!< device - uint64_t st_ino; //!< inode - uint32_t st_mode; //!< mode - uint32_t st_nlink; //!< link count - int32_t st_uid; //!< owner's user ID - int32_t st_gid; //!< owner's group ID - uint64_t st_rdev; //!< device number - int64_t st_size; //!< file size in bytes - //struct tgt_timespec st_atimeX; //!< time of last access - //struct tgt_timespec st_mtimeX; //!< time of last modification - //struct tgt_timespec st_ctimeX; //!< time of last status change + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + //struct tgt_timespec st_atimeX; //!< time of last access + //struct tgt_timespec st_mtimeX; //!< time of last modification + //struct tgt_timespec st_ctimeX; //!< time of last status change int64_t st_atimeX, st_mtimeX, st_ctimeX; - int32_t st_blksize; //!< optimal I/O block size - int64_t st_blocks; //!< number of blocks allocated + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated char st_fstype[16]; } tgt_stat64; @@ -117,11 +117,11 @@ class Solaris : public OperatingSystem /// Interface struct for uname(). typedef struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. } utsname; }; // class Solaris diff --git a/src/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh index cb5a84a7e..78b5ead7a 100644 --- a/src/kern/tru64/mbuf.hh +++ b/src/kern/tru64/mbuf.hh @@ -37,63 +37,63 @@ namespace tru64 { struct m_hdr { - Addr mh_next; // 0x00 - Addr mh_nextpkt; // 0x08 - Addr mh_data; // 0x10 - int32_t mh_len; // 0x18 - int32_t mh_type; // 0x1C - int32_t mh_flags; // 0x20 - int32_t mh_pad0; // 0x24 - Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40 + Addr mh_next; // 0x00 + Addr mh_nextpkt; // 0x08 + Addr mh_data; // 0x10 + int32_t mh_len; // 0x18 + int32_t mh_type; // 0x1C + int32_t mh_flags; // 0x20 + int32_t mh_pad0; // 0x24 + Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40 }; -struct pkthdr { - int32_t len; - int32_t protocolSum; - Addr rcvif; +struct pkthdr { + int32_t len; + int32_t protocolSum; + Addr rcvif; }; struct m_ext { - Addr ext_buf; // 0x00 - Addr ext_free; // 0x08 - uint32_t ext_size; // 0x10 - uint32_t ext_pad0; // 0x14 - Addr ext_arg; // 0x18 - struct ext_refq { - Addr forw, back; // 0x20, 0x28 + Addr ext_buf; // 0x00 + Addr ext_free; // 0x08 + uint32_t ext_size; // 0x10 + uint32_t ext_pad0; // 0x14 + Addr ext_arg; // 0x18 + struct ext_refq { + Addr forw, back; // 0x20, 0x28 } ext_ref; - Addr uiomove_f; // 0x30 - int32_t protocolSum; // 0x38 - int32_t bytesSummed; // 0x3C - Addr checksum; // 0x40 + Addr uiomove_f; // 0x30 + int32_t protocolSum; // 0x38 + int32_t bytesSummed; // 0x3C + Addr checksum; // 0x40 }; struct mbuf { - struct m_hdr m_hdr; + struct m_hdr m_hdr; union { struct { - struct pkthdr MH_pkthdr; + struct pkthdr MH_pkthdr; union { - struct m_ext MH_ext; - char MH_databuf[1]; + struct m_ext MH_ext; + char MH_databuf[1]; } MH_dat; } MH; - char M_databuf[1]; + char M_databuf[1]; } M_dat; }; #define m_attr m_hdr.mh_attr -#define m_next m_hdr.mh_next -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_type m_hdr.mh_type -#define m_flags m_hdr.mh_flags -#define m_nextpkt m_hdr.mh_nextpkt -#define m_act m_nextpkt -#define m_pkthdr M_dat.MH.MH_pkthdr -#define m_ext M_dat.MH.MH_dat.MH_ext -#define m_pktdat M_dat.MH.MH_dat.MH_databuf -#define m_dat M_dat.M_databuf +#define m_next m_hdr.mh_next +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_type m_hdr.mh_type +#define m_flags m_hdr.mh_flags +#define m_nextpkt m_hdr.mh_nextpkt +#define m_act m_nextpkt +#define m_pkthdr M_dat.MH.MH_pkthdr +#define m_ext M_dat.MH.MH_dat.MH_ext +#define m_pktdat M_dat.MH.MH_dat.MH_databuf +#define m_dat M_dat.M_databuf } diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh index 70fb4d688..b1af4ec0e 100644 --- a/src/kern/tru64/tru64.hh +++ b/src/kern/tru64/tru64.hh @@ -52,7 +52,7 @@ class Tru64 {}; #include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <string.h> // for memset() +#include <string.h> // for memset() #include <unistd.h> #include "cpu/base.hh" @@ -102,7 +102,7 @@ class Tru64 : public OperatingSystem int32_t f_retired5; int32_t f_retired6; int32_t f_retired7; - fsid_t f_fsid; + fsid_t f_fsid; int32_t f_spare[9]; char f_retired8[90]; char f_retired9[90]; @@ -141,10 +141,10 @@ class Tru64 : public OperatingSystem /// For getdirentries(). struct dirent { - ino_t d_ino; //!< file number of entry - uint16_t d_reclen; //!< length of this record - uint16_t d_namlen; //!< length of string in d_name - char d_name[256]; //!< dummy name length + ino_t d_ino; //!< file number of entry + uint16_t d_reclen; //!< length of this record + uint16_t d_namlen; //!< length of string in d_name + char d_name[256]; //!< dummy name length }; @@ -162,106 +162,106 @@ class Tru64 : public OperatingSystem /// Limit struct for getrlimit/setrlimit. struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit }; /// For getsysinfo() GSI_CPU_INFO option. struct cpu_info { - uint32_t current_cpu; //!< current_cpu - uint32_t cpus_in_box; //!< cpus_in_box - uint32_t cpu_type; //!< cpu_type - uint32_t ncpus; //!< ncpus - uint64_t cpus_present; //!< cpus_present - uint64_t cpus_running; //!< cpus_running - uint64_t cpu_binding; //!< cpu_binding - uint64_t cpu_ex_binding; //!< cpu_ex_binding - uint32_t mhz; //!< mhz - uint32_t unused[3]; //!< future expansion + uint32_t current_cpu; //!< current_cpu + uint32_t cpus_in_box; //!< cpus_in_box + uint32_t cpu_type; //!< cpu_type + uint32_t ncpus; //!< ncpus + uint64_t cpus_present; //!< cpus_present + uint64_t cpus_running; //!< cpus_running + uint64_t cpu_binding; //!< cpu_binding + uint64_t cpu_ex_binding; //!< cpu_ex_binding + uint32_t mhz; //!< mhz + uint32_t unused[3]; //!< future expansion }; /// For gettimeofday. struct timeval { - uint32_t tv_sec; //!< seconds - uint32_t tv_usec; //!< microseconds + uint32_t tv_sec; //!< seconds + uint32_t tv_usec; //!< microseconds }; /// For getrusage(). struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - uint64_t ru_maxrss; //!< ru_maxrss - uint64_t ru_ixrss; //!< integral shared memory size - uint64_t ru_idrss; //!< integral unshared data " - uint64_t ru_isrss; //!< integral unshared stack " - uint64_t ru_minflt; //!< page reclaims - total vmfaults - uint64_t ru_majflt; //!< page faults - uint64_t ru_nswap; //!< swaps - uint64_t ru_inblock; //!< block input operations - uint64_t ru_oublock; //!< block output operations - uint64_t ru_msgsnd; //!< messages sent - uint64_t ru_msgrcv; //!< messages received - uint64_t ru_nsignals; //!< signals received - uint64_t ru_nvcsw; //!< voluntary context switches - uint64_t ru_nivcsw; //!< involuntary " + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + uint64_t ru_maxrss; //!< ru_maxrss + uint64_t ru_ixrss; //!< integral shared memory size + uint64_t ru_idrss; //!< integral unshared data " + uint64_t ru_isrss; //!< integral unshared stack " + uint64_t ru_minflt; //!< page reclaims - total vmfaults + uint64_t ru_majflt; //!< page faults + uint64_t ru_nswap; //!< swaps + uint64_t ru_inblock; //!< block input operations + uint64_t ru_oublock; //!< block output operations + uint64_t ru_msgsnd; //!< messages sent + uint64_t ru_msgrcv; //!< messages received + uint64_t ru_nsignals; //!< signals received + uint64_t ru_nvcsw; //!< voluntary context switches + uint64_t ru_nivcsw; //!< involuntary " }; /// For sigreturn(). struct sigcontext { - int64_t sc_onstack; //!< sigstack state to restore - int64_t sc_mask; //!< signal mask to restore - int64_t sc_pc; //!< pc at time of signal - int64_t sc_ps; //!< psl to retore - int64_t sc_regs[32]; //!< processor regs 0 to 31 - int64_t sc_ownedfp; //!< fp has been used - int64_t sc_fpregs[32]; //!< fp regs 0 to 31 - uint64_t sc_fpcr; //!< floating point control reg - uint64_t sc_fp_control; //!< software fpcr - int64_t sc_reserved1; //!< reserved for kernel - uint32_t sc_kreserved1; //!< reserved for kernel - uint32_t sc_kreserved2; //!< reserved for kernel - size_t sc_ssize; //!< stack size - caddr_t sc_sbase; //!< stack start - uint64_t sc_traparg_a0; //!< a0 argument to trap on exc - uint64_t sc_traparg_a1; //!< a1 argument to trap on exc - uint64_t sc_traparg_a2; //!< a2 argument to trap on exc - uint64_t sc_fp_trap_pc; //!< imprecise pc - uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg - uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc + int64_t sc_onstack; //!< sigstack state to restore + int64_t sc_mask; //!< signal mask to restore + int64_t sc_pc; //!< pc at time of signal + int64_t sc_ps; //!< psl to retore + int64_t sc_regs[32]; //!< processor regs 0 to 31 + int64_t sc_ownedfp; //!< fp has been used + int64_t sc_fpregs[32]; //!< fp regs 0 to 31 + uint64_t sc_fpcr; //!< floating point control reg + uint64_t sc_fp_control; //!< software fpcr + int64_t sc_reserved1; //!< reserved for kernel + uint32_t sc_kreserved1; //!< reserved for kernel + uint32_t sc_kreserved2; //!< reserved for kernel + size_t sc_ssize; //!< stack size + caddr_t sc_sbase; //!< stack start + uint64_t sc_traparg_a0; //!< a0 argument to trap on exc + uint64_t sc_traparg_a1; //!< a1 argument to trap on exc + uint64_t sc_traparg_a2; //!< a2 argument to trap on exc + uint64_t sc_fp_trap_pc; //!< imprecise pc + uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg + uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc }; /// For table(). struct tbl_sysinfo { - uint64_t si_user; //!< User time - uint64_t si_nice; //!< Nice time - uint64_t si_sys; //!< System time - uint64_t si_idle; //!< Idle time - uint64_t si_hz; //!< hz - uint64_t si_phz; //!< phz - uint64_t si_boottime; //!< Boot time in seconds - uint64_t wait; //!< Wait time - uint32_t si_max_procs; //!< rpb->rpb_numprocs - uint32_t pad; //!< padding + uint64_t si_user; //!< User time + uint64_t si_nice; //!< Nice time + uint64_t si_sys; //!< System time + uint64_t si_idle; //!< Idle time + uint64_t si_hz; //!< hz + uint64_t si_phz; //!< phz + uint64_t si_boottime; //!< Boot time in seconds + uint64_t wait; //!< Wait time + uint32_t si_max_procs; //!< rpb->rpb_numprocs + uint32_t pad; //!< padding }; /// For stack_create. struct vm_stack { // was void * - Addr address; //!< address hint - size_t rsize; //!< red zone size - size_t ysize; //!< yellow zone size - size_t gsize; //!< green zone size - size_t swap; //!< amount of swap to reserve - size_t incr; //!< growth increment - uint64_t align; //!< address alignment - uint64_t flags; //!< MAP_FIXED etc. + Addr address; //!< address hint + size_t rsize; //!< red zone size + size_t ysize; //!< yellow zone size + size_t gsize; //!< green zone size + size_t swap; //!< amount of swap to reserve + size_t incr; //!< growth increment + uint64_t align; //!< address alignment + uint64_t flags; //!< MAP_FIXED etc. // was struct memalloc_attr * - Addr attr; //!< allocation policy - uint64_t reserved; //!< reserved + Addr attr; //!< allocation policy + uint64_t reserved; //!< reserved }; /// Return values for nxm calls. @@ -271,17 +271,17 @@ class Tru64 : public OperatingSystem }; /// For nxm_task_init. - static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP + static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP /// Task attribute structure. struct nxm_task_attr { - int64_t nxm_callback; //!< nxm_callback - unsigned int nxm_version; //!< nxm_version - unsigned short nxm_uniq_offset; //!< nxm_uniq_offset - unsigned short flags; //!< flags - int nxm_quantum; //!< nxm_quantum - int pad1; //!< pad1 - int64_t pad2; //!< pad2 + int64_t nxm_callback; //!< nxm_callback + unsigned int nxm_version; //!< nxm_version + unsigned short nxm_uniq_offset; //!< nxm_uniq_offset + unsigned short flags; //!< flags + int nxm_quantum; //!< nxm_quantum + int pad1; //!< pad1 + int64_t pad2; //!< pad2 }; /// Signal set. @@ -316,9 +316,9 @@ class Tru64 : public OperatingSystem // the kernel but are never context-switched by the library. int nxm_ssig; //!< scheduler's synchronous signals - int reserved1; //!< reserved1 + int reserved1; //!< reserved1 int64_t nxm_active; //!< scheduler active - int64_t reserved2; //!< reserved2 + int64_t reserved2; //!< reserved2 }; struct nxm_sched_state { @@ -328,14 +328,14 @@ class Tru64 : public OperatingSystem int nxm_set_quantum; //!< quantum reset value int nxm_sysevent; //!< syscall state // struct nxm_upcall * - Addr nxm_uc_ret; //!< stack ptr of null thread + Addr nxm_uc_ret; //!< stack ptr of null thread // void * Addr nxm_tid; //!< scheduler's thread id int64_t nxm_va; //!< page fault address // struct nxm_pth_state * Addr nxm_pthid; //!< id of null thread uint64_t nxm_bound_pcs_count; //!< bound PCS thread count - int64_t pad[2]; //!< pad + int64_t pad[2]; //!< pad }; /// nxm_shared. @@ -343,7 +343,7 @@ class Tru64 : public OperatingSystem int64_t nxm_callback; //!< address of upcall routine unsigned int nxm_version; //!< version number unsigned short nxm_uniq_offset; //!< correction factor for TEB - unsigned short pad1; //!< pad1 + unsigned short pad1; //!< pad1 int64_t space[2]; //!< future growth struct nxm_sched_state nxm_ss[1]; //!< array of shared areas }; @@ -368,29 +368,29 @@ class Tru64 : public OperatingSystem /// For nxm_thread_create. enum nxm_thread_type { - NXM_TYPE_SCS = 0, - NXM_TYPE_VP = 1, - NXM_TYPE_MANAGER = 2 + NXM_TYPE_SCS = 0, + NXM_TYPE_VP = 1, + NXM_TYPE_MANAGER = 2 }; /// Thread attributes. struct nxm_thread_attr { - int version; //!< version - int type; //!< type - int cancel_flags; //!< cancel_flags - int priority; //!< priority - int policy; //!< policy - int signal_type; //!< signal_type + int version; //!< version + int type; //!< type + int cancel_flags; //!< cancel_flags + int priority; //!< priority + int policy; //!< policy + int signal_type; //!< signal_type // void * - Addr pthid; //!< pthid - sigset_t sigmask; //!< sigmask + Addr pthid; //!< pthid + sigset_t sigmask; //!< sigmask /// Initial register values. struct { - uint64_t pc; //!< pc - uint64_t sp; //!< sp - uint64_t a0; //!< a0 + uint64_t pc; //!< pc + uint64_t sp; //!< sp + uint64_t a0; //!< a0 } registers; - uint64_t pad2[2]; //!< pad2 + uint64_t pad2[2]; //!< pad2 }; /// Helper function to convert a host statfs buffer to a target statfs @@ -437,10 +437,10 @@ class Tru64 : public OperatingSystem #ifdef __CYGWIN__ panic("getdirent not implemented on cygwin!"); #else - int fd = process->sim_fd(tc->getSyscallArg(0)); - Addr tgt_buf = tc->getSyscallArg(1); - int tgt_nbytes = tc->getSyscallArg(2); - Addr tgt_basep = tc->getSyscallArg(3); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); + Addr tgt_buf = process->getSyscallArg(tc, 1); + int tgt_nbytes = process->getSyscallArg(tc, 2); + Addr tgt_basep = process->getSyscallArg(tc, 3); char * const host_buf = new char[tgt_nbytes]; @@ -496,7 +496,7 @@ class Tru64 : public OperatingSystem using namespace TheISA; using TheISA::RegFile; - TypedBufferArg<Tru64::sigcontext> sc(tc->getSyscallArg(0)); + TypedBufferArg<Tru64::sigcontext> sc(process->getSyscallArg(tc, 0)); sc.copyIn(tc->getMemPort()); @@ -528,7 +528,7 @@ class Tru64 : public OperatingSystem { using namespace TheISA; - TypedBufferArg<Tru64::vm_stack> argp(tc->getSyscallArg(0)); + TypedBufferArg<Tru64::vm_stack> argp(process->getSyscallArg(tc, 0)); argp.copyIn(tc->getMemPort()); @@ -576,8 +576,9 @@ class Tru64 : public OperatingSystem using namespace std; using namespace TheISA; - TypedBufferArg<Tru64::nxm_task_attr> attrp(tc->getSyscallArg(0)); - TypedBufferArg<Addr> configptr_ptr(tc->getSyscallArg(1)); + TypedBufferArg<Tru64::nxm_task_attr> + attrp(process->getSyscallArg(tc, 0)); + TypedBufferArg<Addr> configptr_ptr(process->getSyscallArg(tc, 1)); attrp.copyIn(tc->getMemPort()); @@ -605,7 +606,7 @@ class Tru64 : public OperatingSystem process->numCpus() * sizeof(Tru64::nxm_slot_state_t); cur_addr += slot_state_size; // now the per-RAD state struct (we only support one RAD) - cur_addr = 0x14000; // bump up addr for alignment + cur_addr = 0x14000; // bump up addr for alignment Addr rad_state_addr = cur_addr; int rad_state_size = (sizeof(Tru64::nxm_shared) @@ -616,7 +617,7 @@ class Tru64 : public OperatingSystem TypedBufferArg<Tru64::nxm_config_info> config(config_addr); config->nxm_nslots_per_rad = htog(process->numCpus()); - config->nxm_nrads = htog(1); // only one RAD in our system! + config->nxm_nrads = htog(1); // only one RAD in our system! config->nxm_slot_state = htog(slot_state_addr); config->nxm_rad[0] = htog(rad_state_addr); @@ -683,14 +684,14 @@ class Tru64 : public OperatingSystem /// Initialize thread context. static void - init_thread_context(ThreadContext *tc, + init_thread_context(LiveProcess *process, ThreadContext *tc, Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) { using namespace TheISA; tc->clearArchRegs(); - tc->setIntReg(TheISA::ArgumentReg[0], gtoh(attrp->registers.a0)); + process->setSyscallArg(tc, 0, gtoh(attrp->registers.a0)); tc->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); tc->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ, uniq_val); @@ -709,9 +710,10 @@ class Tru64 : public OperatingSystem using namespace std; using namespace TheISA; - TypedBufferArg<Tru64::nxm_thread_attr> attrp(tc->getSyscallArg(0)); - TypedBufferArg<uint64_t> kidp(tc->getSyscallArg(1)); - int thread_index = tc->getSyscallArg(2); + TypedBufferArg<Tru64::nxm_thread_attr> + attrp(process->getSyscallArg(tc, 0)); + TypedBufferArg<uint64_t> kidp(process->getSyscallArg(tc, 1)); + int thread_index = process->getSyscallArg(tc, 2); // get attribute args attrp.copyIn(tc->getMemPort()); @@ -723,7 +725,7 @@ class Tru64 : public OperatingSystem abort(); } - if (thread_index < 0 | thread_index > process->numCpus()) { + if (thread_index < 0 || thread_index > process->numCpus()) { cerr << "nxm_thread_create: bad thread index " << thread_index << endl; abort(); @@ -789,21 +791,18 @@ class Tru64 : public OperatingSystem slot_state.copyOut(tc->getMemPort()); // Find a free simulator thread context. - for (int i = 0; i < process->numCpus(); ++i) { - ThreadContext *tc = process->threadContexts[i]; - - if (tc->status() == ThreadContext::Unallocated) { - // inactive context... grab it - init_thread_context(tc, attrp, uniq_val); - - // This is supposed to be a port number, but we'll try - // and get away with just sticking the thread index - // here. - *kidp = htog(thread_index); - kidp.copyOut(tc->getMemPort()); - - return 0; - } + ThreadContext *tc = process->findFreeContext(); + if (tc) { + // inactive context... grab it + init_thread_context(process, tc, attrp, uniq_val); + + // This is supposed to be a port number, but we'll try + // and get away with just sticking the thread index + // here. + *kidp = htog(thread_index); + kidp.copyOut(tc->getMemPort()); + + return 0; } // fell out of loop... no available inactive context @@ -833,11 +832,11 @@ class Tru64 : public OperatingSystem { using namespace std; - uint64_t tid = tc->getSyscallArg(0); - uint64_t secs = tc->getSyscallArg(1); - uint64_t flags = tc->getSyscallArg(2); - uint64_t action = tc->getSyscallArg(3); - uint64_t usecs = tc->getSyscallArg(4); + uint64_t tid = process->getSyscallArg(tc, 0); + uint64_t secs = process->getSyscallArg(tc, 1); + uint64_t flags = process->getSyscallArg(tc, 2); + uint64_t action = process->getSyscallArg(tc, 3); + uint64_t usecs = process->getSyscallArg(tc, 4); cout << tc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " " << secs << " " << flags << " " << action << " " << usecs << endl; @@ -852,11 +851,11 @@ class Tru64 : public OperatingSystem { using namespace std; - Addr uaddr = tc->getSyscallArg(0); - uint64_t val = tc->getSyscallArg(1); - uint64_t secs = tc->getSyscallArg(2); - uint64_t usecs = tc->getSyscallArg(3); - uint64_t flags = tc->getSyscallArg(4); + Addr uaddr = process->getSyscallArg(tc, 0); + uint64_t val = process->getSyscallArg(tc, 1); + uint64_t secs = process->getSyscallArg(tc, 2); + uint64_t usecs = process->getSyscallArg(tc, 3); + uint64_t flags = process->getSyscallArg(tc, 4); BaseCPU *cpu = tc->getCpuPtr(); @@ -875,7 +874,7 @@ class Tru64 : public OperatingSystem { using namespace std; - Addr uaddr = tc->getSyscallArg(0); + Addr uaddr = process->getSyscallArg(tc, 0); cout << tc->getCpuPtr()->name() << ": nxm_unblock " << hex << uaddr << dec << endl; @@ -976,7 +975,7 @@ class Tru64 : public OperatingSystem m5_mutex_lockFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - Addr uaddr = tc->getSyscallArg(0); + Addr uaddr = process->getSyscallArg(tc, 0); m5_lock_mutex(uaddr, process, tc); @@ -993,7 +992,7 @@ class Tru64 : public OperatingSystem { using namespace TheISA; - Addr uaddr = tc->getSyscallArg(0); + Addr uaddr = process->getSyscallArg(tc, 0); TypedBufferArg<uint64_t> lockp(uaddr); lockp.copyIn(tc->getMemPort()); @@ -1013,7 +1012,7 @@ class Tru64 : public OperatingSystem m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - Addr uaddr = tc->getSyscallArg(0); + Addr uaddr = process->getSyscallArg(tc, 0); m5_unlock_mutex(uaddr, process, tc); @@ -1025,7 +1024,7 @@ class Tru64 : public OperatingSystem m5_cond_signalFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - Addr cond_addr = tc->getSyscallArg(0); + Addr cond_addr = process->getSyscallArg(tc, 0); // Wake up one process waiting on the condition variable. activate_waiting_context(cond_addr, process); @@ -1038,7 +1037,7 @@ class Tru64 : public OperatingSystem m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - Addr cond_addr = tc->getSyscallArg(0); + Addr cond_addr = process->getSyscallArg(tc, 0); activate_waiting_context(cond_addr, process, true); @@ -1052,8 +1051,8 @@ class Tru64 : public OperatingSystem { using namespace TheISA; - Addr cond_addr = tc->getSyscallArg(0); - Addr lock_addr = tc->getSyscallArg(1); + Addr cond_addr = process->getSyscallArg(tc, 0); + Addr lock_addr = process->getSyscallArg(tc, 1); TypedBufferArg<uint64_t> condp(cond_addr); TypedBufferArg<uint64_t> lockp(lock_addr); @@ -1085,10 +1084,10 @@ class Tru64 : public OperatingSystem indirectSyscallFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int new_callnum = tc->getSyscallArg(0); + int new_callnum = process->getSyscallArg(tc, 0); for (int i = 0; i < 5; ++i) - tc->setSyscallArg(i, tc->getSyscallArg(i+1)); + process->setSyscallArg(tc, i, process->getSyscallArg(tc, i+1)); SyscallDesc *new_desc = process->getDesc(new_callnum); @@ -1111,37 +1110,37 @@ class Tru64_F64 : public Tru64 /// On some hosts (notably Linux) define st_atime, st_mtime, and /// st_ctime as macros, so we append an X to get around this. struct F64_stat { - dev_t st_dev; //!< st_dev - int32_t st_retired1; //!< st_retired1 - mode_t st_mode; //!< st_mode - nlink_t st_nlink; //!< st_nlink - uint16_t st_nlink_reserved; //!< st_nlink_reserved - uid_t st_uid; //!< st_uid - gid_t st_gid; //!< st_gid - dev_t st_rdev; //!< st_rdev - dev_t st_ldev; //!< st_ldev - off_t st_size; //!< st_size - time_t st_retired2; //!< st_retired2 - int32_t st_uatime; //!< st_uatime - time_t st_retired3; //!< st_retired3 - int32_t st_umtime; //!< st_umtime - time_t st_retired4; //!< st_retired4 - int32_t st_uctime; //!< st_uctime - int32_t st_retired5; //!< st_retired5 - int32_t st_retired6; //!< st_retired6 - uint32_t st_flags; //!< st_flags - uint32_t st_gen; //!< st_gen - uint64_t st_spare[4]; //!< st_spare[4] - ino_t st_ino; //!< st_ino - int32_t st_ino_reserved; //!< st_ino_reserved - time_t st_atimeX; //!< st_atime - int32_t st_atime_reserved; //!< st_atime_reserved - time_t st_mtimeX; //!< st_mtime - int32_t st_mtime_reserved; //!< st_mtime_reserved - time_t st_ctimeX; //!< st_ctime - int32_t st_ctime_reserved; //!< st_ctime_reserved - uint64_t st_blksize; //!< st_blksize - uint64_t st_blocks; //!< st_blocks + dev_t st_dev; //!< st_dev + int32_t st_retired1; //!< st_retired1 + mode_t st_mode; //!< st_mode + nlink_t st_nlink; //!< st_nlink + uint16_t st_nlink_reserved; //!< st_nlink_reserved + uid_t st_uid; //!< st_uid + gid_t st_gid; //!< st_gid + dev_t st_rdev; //!< st_rdev + dev_t st_ldev; //!< st_ldev + off_t st_size; //!< st_size + time_t st_retired2; //!< st_retired2 + int32_t st_uatime; //!< st_uatime + time_t st_retired3; //!< st_retired3 + int32_t st_umtime; //!< st_umtime + time_t st_retired4; //!< st_retired4 + int32_t st_uctime; //!< st_uctime + int32_t st_retired5; //!< st_retired5 + int32_t st_retired6; //!< st_retired6 + uint32_t st_flags; //!< st_flags + uint32_t st_gen; //!< st_gen + uint64_t st_spare[4]; //!< st_spare[4] + ino_t st_ino; //!< st_ino + int32_t st_ino_reserved; //!< st_ino_reserved + time_t st_atimeX; //!< st_atime + int32_t st_atime_reserved; //!< st_atime_reserved + time_t st_mtimeX; //!< st_mtime + int32_t st_mtime_reserved; //!< st_mtime_reserved + time_t st_ctimeX; //!< st_ctime + int32_t st_ctime_reserved; //!< st_ctime_reserved + uint64_t st_blksize; //!< st_blksize + uint64_t st_blocks; //!< st_blocks }; typedef F64_stat tgt_stat; diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc index c798c3ced..4867df559 100644 --- a/src/kern/tru64/tru64_events.cc +++ b/src/kern/tru64/tru64_events.cc @@ -51,7 +51,7 @@ BadAddrEvent::process(ThreadContext *tc) // annotation for vmunix::badaddr in: // simos/simulation/apps/tcl/osf/tlaser.tcl - uint64_t a0 = tc->readIntReg(ArgumentReg[0]); + uint64_t a0 = tc->readIntReg(16); AddrRangeList resp; bool snoop; @@ -59,20 +59,19 @@ BadAddrEvent::process(ThreadContext *tc) bool found = false; tc->getPhysPort()->getPeerAddressRanges(resp, snoop); - for(iter = resp.begin(); iter != resp.end(); iter++) - { - if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) + for (iter = resp.begin(); iter != resp.end(); iter++) { + if (*iter == (K0Seg2Phys(a0) & PAddrImplMask)) found = true; } - if (!TheISA::IsK0Seg(a0) || found ) { + if (!IsK0Seg(a0) || found ) { DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); tc->setIntReg(ReturnValueReg, 0x1); SkipFuncEvent::process(tc); - } - else + } else { DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0); + } } void diff --git a/src/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc index 8051b9efb..602271b36 100644 --- a/src/kern/tru64/tru64_syscalls.cc +++ b/src/kern/tru64/tru64_syscalls.cc @@ -33,394 +33,394 @@ namespace { const char * standard_strings[SystemCalls<Tru64>::StandardNumber] = { - "syscall", // 0 - "exit", // 1 - "fork", // 2 - "read", // 3 - "write", // 4 - "old_open", // 5 - "close", // 6 - "wait4", // 7 - "old_creat", // 8 - "link", // 9 - - "unlink", // 10 - "execv", // 11 - "chdir", // 12 - "fchdir", // 13 - "mknod", // 14 - "chmod", // 15 - "chown", // 16 - "obreak", // 17 - "pre_F64_getfsstat", // 18 - "lseek", // 19 - - "getpid", // 20 - "mount", // 21 - "unmount", // 22 - "setuid", // 23 - "getuid", // 24 - "exec_with_loader", // 25 - "ptrace", // 26 - "recvmsg", // 27 - "sendmsg", // 28 - "recvfrom", // 29 - - "accept", // 30 - "getpeername", // 31 - "getsockname", // 32 - "access", // 33 - "chflags", // 34 - "fchflags", // 35 - "sync", // 36 - "kill", // 37 - "old_stat", // 38 - "setpgid", // 39 - - "old_lstat", // 40 - "dup", // 41 - "pipe", // 42 - "set_program_attributes", // 43 - "profil", // 44 - "open", // 45 - "obsolete_osigaction", // 46 - "getgid", // 47 - "sigprocmask", // 48 - "getlogin", // 49 - - "setlogin", // 50 - "acct", // 51 - "sigpending", // 52 - "classcntl", // 53 - "ioctl", // 54 - "reboot", // 55 - "revoke", // 56 - "symlink", // 57 - "readlink", // 58 - "execve", // 59 - - "umask", // 60 - "chroot", // 61 - "old_fstat", // 62 - "getpgrp", // 63 - "getpagesize", // 64 - "mremap", // 65 - "vfork", // 66 - "pre_F64_stat", // 67 - "pre_F64_lstat", // 68 - "sbrk", // 69 - - "sstk", // 70 - "mmap", // 71 - "ovadvise", // 72 - "munmap", // 73 - "mprotect", // 74 - "madvise", // 75 - "old_vhangup", // 76 - "kmodcall", // 77 - "mincore", // 78 - "getgroups", // 79 - - "setgroups", // 80 - "old_getpgrp", // 81 - "setpgrp", // 82 - "setitimer", // 83 - "old_wait", // 84 - "table", // 85 - "getitimer", // 86 - "gethostname", // 87 - "sethostname", // 88 - "getdtablesize", // 89 - - "dup2", // 90 - "pre_F64_fstat", // 91 - "fcntl", // 92 - "select", // 93 - "poll", // 94 - "fsync", // 95 - "setpriority", // 96 - "socket", // 97 - "connect", // 98 - "old_accept", // 99 - - "getpriority", // 100 - "old_send", // 101 - "old_recv", // 102 - "sigreturn", // 103 - "bind", // 104 - "setsockopt", // 105 - "listen", // 106 - "plock", // 107 - "old_sigvec", // 108 - "old_sigblock", // 109 - - "old_sigsetmask", // 110 - "sigsuspend", // 111 - "sigstack", // 112 - "old_recvmsg", // 113 - "old_sendmsg", // 114 - "obsolete_vtrcae", // 115 - "gettimeofday", // 116 - "getrusage", // 117 - "getsockopt", // 118 - "numa_syscalls", // 119 - - "readv", // 120 - "writev", // 121 - "settimeofday", // 122 - "fchown", // 123 - "fchmod", // 124 - "old_recvfrom", // 125 - "setreuid", // 126 - "setregid", // 127 - "rename", // 128 - "truncate", // 129 - - "ftruncate", // 130 - "flock", // 131 - "setgid", // 132 - "sendto", // 133 - "shutdown", // 134 - "socketpair", // 135 - "mkdir", // 136 - "rmdir", // 137 - "utimes", // 138 - "obsolete_42_sigreturn", // 139 - - "adjtime", // 140 - "old_getpeername", // 141 - "gethostid", // 142 - "sethostid", // 143 - "getrlimit", // 144 - "setrlimit", // 145 - "old_killpg", // 146 - "setsid", // 147 - "quotactl", // 148 - "oldquota", // 149 - - "old_getsockname", // 150 - "pread", // 151 - "pwrite", // 152 - "pid_block", // 153 - "pid_unblock", // 154 - "signal_urti", // 155 - "sigaction", // 156 - "sigwaitprim", // 157 - "nfssvc", // 158 - "getdirentries", // 159 - - "pre_F64_statfs", // 160 - "pre_F64_fstatfs", // 161 - 0, // 162 - "async_daemon", // 163 - "getfh", // 164 - "getdomainname", // 165 - "setdomainname", // 166 - 0, // 167 - 0, // 168 - "exportfs", // 169 - - 0, // 170 - 0, // 171 - 0, // 172 - 0, // 173 - 0, // 174 - 0, // 175 - 0, // 176 - 0, // 177 - 0, // 178 - 0, // 179 - - 0, // 180 - "alt_plock", // 181 - 0, // 182 - 0, // 183 - "getmnt", // 184 - 0, // 185 - 0, // 186 - "alt_sigpending", // 187 - "alt_setsid", // 188 - 0, // 189 - - 0, // 190 - 0, // 191 - 0, // 192 - 0, // 193 - 0, // 194 - 0, // 195 - 0, // 196 - 0, // 197 - 0, // 198 - "swapon", // 199 - - "msgctl", // 200 - "msgget", // 201 - "msgrcv", // 202 - "msgsnd", // 203 - "semctl", // 204 - "semget", // 205 - "semop", // 206 - "uname", // 207 - "lchown", // 208 - "shmat", // 209 - - "shmctl", // 210 - "shmdt", // 211 - "shmget", // 212 - "mvalid", // 213 - "getaddressconf", // 214 - "msleep", // 215 - "mwakeup", // 216 - "msync", // 217 - "signal", // 218 - "utc_gettime", // 219 - - "utc_adjtime", // 220 - 0, // 221 - "security", // 222 - "kloadcall", // 223 - "stat", // 224 - "lstat", // 225 - "fstat", // 226 - "statfs", // 227 - "fstatfs", // 228 - "getfsstat", // 229 - - "gettimeofday64", // 230 - "settimeofday64", // 231 - 0, // 232 - "getpgid", // 233 - "getsid", // 234 - "sigaltstack", // 235 - "waitid", // 236 - "priocntlset", // 237 - "sigsendset", // 238 - "set_speculative", // 239 - - "msfs_syscall", // 240 - "sysinfo", // 241 - "uadmin", // 242 - "fuser", // 243 - "proplist_syscall", // 244 - "ntp_adjtime", // 245 - "ntp_gettime", // 246 - "pathconf", // 247 - "fpathconf", // 248 - "sync2", // 249 - - "uswitch", // 250 - "usleep_thread", // 251 - "audcntl", // 252 - "audgen", // 253 - "sysfs", // 254 - "subsys_info", // 255 - "getsysinfo", // 256 - "setsysinfo", // 257 - "afs_syscall", // 258 - "swapctl", // 259 - - "memcntl", // 260 - "fdatasync", // 261 - "oflock", // 262 - "_F64_readv", // 263 - "_F64_writev", // 264 - "cdslxlate", // 265 - "sendfile", // 266 + "syscall", // 0 + "exit", // 1 + "fork", // 2 + "read", // 3 + "write", // 4 + "old_open", // 5 + "close", // 6 + "wait4", // 7 + "old_creat", // 8 + "link", // 9 + + "unlink", // 10 + "execv", // 11 + "chdir", // 12 + "fchdir", // 13 + "mknod", // 14 + "chmod", // 15 + "chown", // 16 + "obreak", // 17 + "pre_F64_getfsstat", // 18 + "lseek", // 19 + + "getpid", // 20 + "mount", // 21 + "unmount", // 22 + "setuid", // 23 + "getuid", // 24 + "exec_with_loader", // 25 + "ptrace", // 26 + "recvmsg", // 27 + "sendmsg", // 28 + "recvfrom", // 29 + + "accept", // 30 + "getpeername", // 31 + "getsockname", // 32 + "access", // 33 + "chflags", // 34 + "fchflags", // 35 + "sync", // 36 + "kill", // 37 + "old_stat", // 38 + "setpgid", // 39 + + "old_lstat", // 40 + "dup", // 41 + "pipe", // 42 + "set_program_attributes", // 43 + "profil", // 44 + "open", // 45 + "obsolete_osigaction", // 46 + "getgid", // 47 + "sigprocmask", // 48 + "getlogin", // 49 + + "setlogin", // 50 + "acct", // 51 + "sigpending", // 52 + "classcntl", // 53 + "ioctl", // 54 + "reboot", // 55 + "revoke", // 56 + "symlink", // 57 + "readlink", // 58 + "execve", // 59 + + "umask", // 60 + "chroot", // 61 + "old_fstat", // 62 + "getpgrp", // 63 + "getpagesize", // 64 + "mremap", // 65 + "vfork", // 66 + "pre_F64_stat", // 67 + "pre_F64_lstat", // 68 + "sbrk", // 69 + + "sstk", // 70 + "mmap", // 71 + "ovadvise", // 72 + "munmap", // 73 + "mprotect", // 74 + "madvise", // 75 + "old_vhangup", // 76 + "kmodcall", // 77 + "mincore", // 78 + "getgroups", // 79 + + "setgroups", // 80 + "old_getpgrp", // 81 + "setpgrp", // 82 + "setitimer", // 83 + "old_wait", // 84 + "table", // 85 + "getitimer", // 86 + "gethostname", // 87 + "sethostname", // 88 + "getdtablesize", // 89 + + "dup2", // 90 + "pre_F64_fstat", // 91 + "fcntl", // 92 + "select", // 93 + "poll", // 94 + "fsync", // 95 + "setpriority", // 96 + "socket", // 97 + "connect", // 98 + "old_accept", // 99 + + "getpriority", // 100 + "old_send", // 101 + "old_recv", // 102 + "sigreturn", // 103 + "bind", // 104 + "setsockopt", // 105 + "listen", // 106 + "plock", // 107 + "old_sigvec", // 108 + "old_sigblock", // 109 + + "old_sigsetmask", // 110 + "sigsuspend", // 111 + "sigstack", // 112 + "old_recvmsg", // 113 + "old_sendmsg", // 114 + "obsolete_vtrcae", // 115 + "gettimeofday", // 116 + "getrusage", // 117 + "getsockopt", // 118 + "numa_syscalls", // 119 + + "readv", // 120 + "writev", // 121 + "settimeofday", // 122 + "fchown", // 123 + "fchmod", // 124 + "old_recvfrom", // 125 + "setreuid", // 126 + "setregid", // 127 + "rename", // 128 + "truncate", // 129 + + "ftruncate", // 130 + "flock", // 131 + "setgid", // 132 + "sendto", // 133 + "shutdown", // 134 + "socketpair", // 135 + "mkdir", // 136 + "rmdir", // 137 + "utimes", // 138 + "obsolete_42_sigreturn", // 139 + + "adjtime", // 140 + "old_getpeername", // 141 + "gethostid", // 142 + "sethostid", // 143 + "getrlimit", // 144 + "setrlimit", // 145 + "old_killpg", // 146 + "setsid", // 147 + "quotactl", // 148 + "oldquota", // 149 + + "old_getsockname", // 150 + "pread", // 151 + "pwrite", // 152 + "pid_block", // 153 + "pid_unblock", // 154 + "signal_urti", // 155 + "sigaction", // 156 + "sigwaitprim", // 157 + "nfssvc", // 158 + "getdirentries", // 159 + + "pre_F64_statfs", // 160 + "pre_F64_fstatfs", // 161 + 0, // 162 + "async_daemon", // 163 + "getfh", // 164 + "getdomainname", // 165 + "setdomainname", // 166 + 0, // 167 + 0, // 168 + "exportfs", // 169 + + 0, // 170 + 0, // 171 + 0, // 172 + 0, // 173 + 0, // 174 + 0, // 175 + 0, // 176 + 0, // 177 + 0, // 178 + 0, // 179 + + 0, // 180 + "alt_plock", // 181 + 0, // 182 + 0, // 183 + "getmnt", // 184 + 0, // 185 + 0, // 186 + "alt_sigpending", // 187 + "alt_setsid", // 188 + 0, // 189 + + 0, // 190 + 0, // 191 + 0, // 192 + 0, // 193 + 0, // 194 + 0, // 195 + 0, // 196 + 0, // 197 + 0, // 198 + "swapon", // 199 + + "msgctl", // 200 + "msgget", // 201 + "msgrcv", // 202 + "msgsnd", // 203 + "semctl", // 204 + "semget", // 205 + "semop", // 206 + "uname", // 207 + "lchown", // 208 + "shmat", // 209 + + "shmctl", // 210 + "shmdt", // 211 + "shmget", // 212 + "mvalid", // 213 + "getaddressconf", // 214 + "msleep", // 215 + "mwakeup", // 216 + "msync", // 217 + "signal", // 218 + "utc_gettime", // 219 + + "utc_adjtime", // 220 + 0, // 221 + "security", // 222 + "kloadcall", // 223 + "stat", // 224 + "lstat", // 225 + "fstat", // 226 + "statfs", // 227 + "fstatfs", // 228 + "getfsstat", // 229 + + "gettimeofday64", // 230 + "settimeofday64", // 231 + 0, // 232 + "getpgid", // 233 + "getsid", // 234 + "sigaltstack", // 235 + "waitid", // 236 + "priocntlset", // 237 + "sigsendset", // 238 + "set_speculative", // 239 + + "msfs_syscall", // 240 + "sysinfo", // 241 + "uadmin", // 242 + "fuser", // 243 + "proplist_syscall", // 244 + "ntp_adjtime", // 245 + "ntp_gettime", // 246 + "pathconf", // 247 + "fpathconf", // 248 + "sync2", // 249 + + "uswitch", // 250 + "usleep_thread", // 251 + "audcntl", // 252 + "audgen", // 253 + "sysfs", // 254 + "subsys_info", // 255 + "getsysinfo", // 256 + "setsysinfo", // 257 + "afs_syscall", // 258 + "swapctl", // 259 + + "memcntl", // 260 + "fdatasync", // 261 + "oflock", // 262 + "_F64_readv", // 263 + "_F64_writev", // 264 + "cdslxlate", // 265 + "sendfile", // 266 }; const char * mach_strings[SystemCalls<Tru64>::MachNumber] = { - 0, // 0 - 0, // 1 - 0, // 2 - 0, // 3 - 0, // 4 - 0, // 5 - 0, // 6 - 0, // 7 - 0, // 8 - 0, // 9 - - "task_self", // 10 - "thread_reply", // 11 - "task_notify", // 12 - "thread_self", // 13 - 0, // 14 - 0, // 15 - 0, // 16 - 0, // 17 - 0, // 18 - 0, // 19 - - "msg_send_trap", // 20 - "msg_receive_trap", // 21 - "msg_rpc_trap", // 22 - 0, // 23 - "nxm_block", // 24 - "nxm_unblock", // 25 - 0, // 26 - 0, // 27 - 0, // 28 - "nxm_thread_destroy", // 29 - - "lw_wire", // 30 - "lw_unwire", // 31 - "nxm_thread_create", // 32 - "nxm_task_init", // 33 - 0, // 34 - "nxm_idle", // 35 - "nxm_wakeup_idle", // 36 - "nxm_set_pthid", // 37 - "nxm_thread_kill", // 38 - "nxm_thread_block", // 39 - - "nxm_thread_wakeup", // 40 - "init_process", // 41 - "nxm_get_binding", // 42 - "map_fd", // 43 - "nxm_resched", // 44 - "nxm_set_cancel", // 45 - "nxm_set_binding", // 46 - "stack_create", // 47 - "nxm_get_state", // 48 - "nxm_thread_suspend", // 49 - - "nxm_thread_resume", // 50 - "nxm_signal_check", // 51 - "htg_unix_syscall", // 52 - 0, // 53 - 0, // 54 - "host_self", // 55 - "host_priv_self", // 56 - 0, // 57 - 0, // 58 - "swtch_pri", // 59 - - "swtch", // 60 - "thread_switch", // 61 - "semop_fast", // 62 - "nxm_pshared_init", // 63 - "nxm_pshared_block", // 64 - "nxm_pshared_unblock", // 65 - "nxm_pshared_destroy", // 66 - "nxm_swtch_pri", // 67 - "lw_syscall", // 68 - 0, // 69 - - "mach_sctimes_0", // 70 - "mach_sctimes_1", // 71 - "mach_sctimes_2", // 72 - "mach_sctimes_3", // 73 - "mach_sctimes_4", // 74 - "mach_sctimes_5", // 75 - "mach_sctimes_6", // 76 - "mach_sctimes_7", // 77 - "mach_sctimes_8", // 78 - "mach_sctimes_9", // 79 - - "mach_sctimes_10", // 80 - "mach_sctimes_11", // 81 - "mach_sctimes_port_alloc_dealloc", // 82 + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 0, // 8 + 0, // 9 + + "task_self", // 10 + "thread_reply", // 11 + "task_notify", // 12 + "thread_self", // 13 + 0, // 14 + 0, // 15 + 0, // 16 + 0, // 17 + 0, // 18 + 0, // 19 + + "msg_send_trap", // 20 + "msg_receive_trap", // 21 + "msg_rpc_trap", // 22 + 0, // 23 + "nxm_block", // 24 + "nxm_unblock", // 25 + 0, // 26 + 0, // 27 + 0, // 28 + "nxm_thread_destroy", // 29 + + "lw_wire", // 30 + "lw_unwire", // 31 + "nxm_thread_create", // 32 + "nxm_task_init", // 33 + 0, // 34 + "nxm_idle", // 35 + "nxm_wakeup_idle", // 36 + "nxm_set_pthid", // 37 + "nxm_thread_kill", // 38 + "nxm_thread_block", // 39 + + "nxm_thread_wakeup", // 40 + "init_process", // 41 + "nxm_get_binding", // 42 + "map_fd", // 43 + "nxm_resched", // 44 + "nxm_set_cancel", // 45 + "nxm_set_binding", // 46 + "stack_create", // 47 + "nxm_get_state", // 48 + "nxm_thread_suspend", // 49 + + "nxm_thread_resume", // 50 + "nxm_signal_check", // 51 + "htg_unix_syscall", // 52 + 0, // 53 + 0, // 54 + "host_self", // 55 + "host_priv_self", // 56 + 0, // 57 + 0, // 58 + "swtch_pri", // 59 + + "swtch", // 60 + "thread_switch", // 61 + "semop_fast", // 62 + "nxm_pshared_init", // 63 + "nxm_pshared_block", // 64 + "nxm_pshared_unblock", // 65 + "nxm_pshared_destroy", // 66 + "nxm_swtch_pri", // 67 + "lw_syscall", // 68 + 0, // 69 + + "mach_sctimes_0", // 70 + "mach_sctimes_1", // 71 + "mach_sctimes_2", // 72 + "mach_sctimes_3", // 73 + "mach_sctimes_4", // 74 + "mach_sctimes_5", // 75 + "mach_sctimes_6", // 76 + "mach_sctimes_7", // 77 + "mach_sctimes_8", // 78 + "mach_sctimes_9", // 79 + + "mach_sctimes_10", // 80 + "mach_sctimes_11", // 81 + "mach_sctimes_port_alloc_dealloc", // 82 }; } diff --git a/src/mem/PhysicalMemory.py b/src/mem/PhysicalMemory.py index 99bd27f2b..95cc73daa 100644 --- a/src/mem/PhysicalMemory.py +++ b/src/mem/PhysicalMemory.py @@ -1,4 +1,4 @@ -# Copyright (c) 2005-2007 The Regents of The University of Michigan +# Copyright (c) 2005-2008 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,8 +35,10 @@ class PhysicalMemory(MemObject): port = VectorPort("the access port") range = Param.AddrRange(AddrRange('128MB'), "Device Address") file = Param.String('', "memory mapped file") - latency = Param.Latency('1t', "latency of an access") + latency = Param.Latency('30ns', "latency of an access") + latency_var = Param.Latency('0ns', "access variablity") zero = Param.Bool(False, "zero initialize memory") + null = Param.Bool(False, "do not store data, always return zero") class DRAMMemory(PhysicalMemory): type = 'DRAMMemory' diff --git a/src/mem/SConscript b/src/mem/SConscript index b572f703c..0b0017f81 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -43,6 +43,7 @@ Source('packet.cc') Source('physical.cc') Source('port.cc') Source('tport.cc') +Source('mport.cc') if env['FULL_SYSTEM']: Source('vport.cc') diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 3d3966491..cc9b83d3e 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -47,7 +47,7 @@ Bridge::BridgePort::BridgePort(const std::string &_name, int _delay, int _nack_delay, int _req_limit, int _resp_limit, std::vector<Range<Addr> > filter_ranges) - : Port(_name), bridge(_bridge), otherPort(_otherPort), + : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort), delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges), outstandingResponses(0), queuedRequests(0), inRetry(false), reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) @@ -89,7 +89,7 @@ void Bridge::init() { // Make sure that both sides are connected to. - if (portA.getPeer() == NULL || portB.getPeer() == NULL) + if (!portA.isConnected() || !portB.isConnected()) fatal("Both ports of bus bridge are not connected to a bus.\n"); if (portA.peerBlockSize() != portB.peerBlockSize()) @@ -130,7 +130,7 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt) return true; } - if (pkt->needsResponse()) + if (pkt->needsResponse()) { if (respQueueFull()) { DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", @@ -141,6 +141,7 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt) DPRINTF(BusBridge, "Request Needs response, reserving space\n"); ++outstandingResponses; } + } otherPort->queueForSendTiming(pkt); @@ -161,7 +162,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt) // nothing on the list, add it and we're done if (sendQueue.empty()) { assert(!sendEvent.scheduled()); - sendEvent.schedule(readyTime); + schedule(sendEvent, readyTime); sendQueue.push_back(buf); return; } @@ -183,7 +184,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt) while (i != end && !done) { if (readyTime < (*i)->ready) { if (i == begin) - sendEvent.reschedule(readyTime); + reschedule(sendEvent, readyTime); sendQueue.insert(i,buf); done = true; } @@ -226,7 +227,7 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) // should already be an event scheduled for sending the head // packet. if (sendQueue.empty()) { - sendEvent.schedule(readyTime); + schedule(sendEvent, readyTime); } sendQueue.push_back(buf); } @@ -280,7 +281,7 @@ Bridge::BridgePort::trySend() if (!sendQueue.empty()) { buf = sendQueue.front(); DPRINTF(BusBridge, "Scheduling next send\n"); - sendEvent.schedule(std::max(buf->ready, curTick + 1)); + schedule(sendEvent, std::max(buf->ready, curTick + 1)); } } else { DPRINTF(BusBridge, " unsuccessful\n"); @@ -301,7 +302,7 @@ Bridge::BridgePort::recvRetry() if (nextReady <= curTick) trySend(); else - sendEvent.schedule(nextReady); + schedule(sendEvent, nextReady); } /** Function called by the port when the bus is receiving a Atomic diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 1331a45f9..40f033811 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -42,6 +42,7 @@ #include <inttypes.h> #include <queue> +#include "base/fast_alloc.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" #include "mem/port.hh" @@ -73,7 +74,7 @@ class Bridge : public MemObject /** Pass ranges from one side of the bridge to the other? */ std::vector<Range<Addr> > filterRanges; - class PacketBuffer : public Packet::SenderState { + class PacketBuffer : public Packet::SenderState, public FastAlloc { public: Tick ready; @@ -145,11 +146,8 @@ class Bridge : public MemObject BridgePort *port; public: - SendEvent(BridgePort *p) - : Event(&mainEventQueue), port(p) {} - + SendEvent(BridgePort *p) : port(p) {} virtual void process() { port->trySend(); } - virtual const char *description() const { return "bridge send"; } }; diff --git a/src/mem/bus.cc b/src/mem/bus.cc index ff4512aca..2eb823051 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -97,34 +97,39 @@ Bus::init() intIter->second->sendStatusChange(Port::RangeChange); } -Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) +Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) + : bus(_bus) {} -void Bus::BusFreeEvent::process() +void +Bus::BusFreeEvent::process() { bus->recvRetry(-1); } -const char * Bus::BusFreeEvent::description() const +const char * +Bus::BusFreeEvent::description() const { return "bus became available"; } -void Bus::preparePacket(PacketPtr pkt, Tick & headerTime) +Tick +Bus::calcPacketTiming(PacketPtr pkt) { - //Bring tickNextIdle up to the present tick - //There is some potential ambiguity where a cycle starts, which might make - //a difference when devices are acting right around a cycle boundary. Using - //a < allows things which happen exactly on a cycle boundary to take up - //only the following cycle. Anything that happens later will have to "wait" - //for the end of that cycle, and then start using the bus after that. + // Bring tickNextIdle up to the present tick. + // There is some potential ambiguity where a cycle starts, which + // might make a difference when devices are acting right around a + // cycle boundary. Using a < allows things which happen exactly on + // a cycle boundary to take up only the following cycle. Anything + // that happens later will have to "wait" for the end of that + // cycle, and then start using the bus after that. if (tickNextIdle < curTick) { tickNextIdle = curTick; if (tickNextIdle % clock != 0) tickNextIdle = curTick - (curTick % clock) + clock; } - headerTime = tickNextIdle + headerCycles * clock; + Tick headerTime = tickNextIdle + headerCycles * clock; // The packet will be sent. Figure out how long it occupies the bus, and // how much of that time is for the first "word", aka bus width. @@ -142,17 +147,20 @@ void Bus::preparePacket(PacketPtr pkt, Tick & headerTime) pkt->firstWordTime = headerTime + clock; pkt->finishTime = headerTime + numCycles * clock; + + return headerTime; } void Bus::occupyBus(Tick until) { + if (until == 0) { + // shortcut for express snoop packets + return; + } + tickNextIdle = until; + reschedule(busIdle, tickNextIdle, true); - if (!busIdle.scheduled()) { - busIdle.schedule(tickNextIdle); - } else { - busIdle.reschedule(tickNextIdle); - } DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", curTick, tickNextIdle); } @@ -190,11 +198,8 @@ Bus::recvTiming(PacketPtr pkt) DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); - Tick headerTime = 0; - - if (!pkt->isExpressSnoop()) { - preparePacket(pkt, headerTime); - } + Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); + Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; short dest = pkt->getDest(); int dest_port_id; @@ -243,17 +248,16 @@ Bus::recvTiming(PacketPtr pkt) DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); addToRetryList(src_port); - if (!pkt->isExpressSnoop()) { - occupyBus(headerTime); - } + occupyBus(headerFinishTime); return false; } - // send OK, fall through + // send OK, fall through... pkt may have been deleted by + // target at this point, so it should *not* be referenced + // again. We'll set it to NULL here just to be safe. + pkt = NULL; } - if (!pkt->isExpressSnoop()) { - occupyBus(pkt->finishTime); - } + occupyBus(packetFinishTime); // Packet was successfully sent. // Also take care of retries @@ -289,7 +293,7 @@ Bus::recvRetry(int id) //Burn a cycle for the missed grant. tickNextIdle += clock; - busIdle.reschedule(tickNextIdle, true); + reschedule(busIdle, tickNextIdle, true); } } //If we weren't able to drain before, we might be able to now. @@ -327,10 +331,10 @@ Bus::findPort(Addr addr) if (responderSet) { panic("Unable to find destination for addr (user set default " - "responder): %#llx", addr); + "responder): %#llx\n", addr); } else { DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " - "default port", addr); + "default port\n", addr); return defaultId; } @@ -519,9 +523,12 @@ Bus::recvStatusChange(Port::Status status, int id) for (iter = ranges.begin(); iter != ranges.end(); iter++) { DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", iter->start, iter->end, id); - if (portMap.insert(*iter, id) == portMap.end()) - panic("Two devices with same range\n"); - + if (portMap.insert(*iter, id) == portMap.end()) { + int conflict_id = portMap.find(*iter)->second; + fatal("%s has two ports with same range:\n\t%s\n\t%s\n", + name(), interfaces[id]->getPeer()->name(), + interfaces[conflict_id]->getPeer()->name()); + } } } DPRINTF(MMU, "port list has %d entries\n", portMap.size()); diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 274c02de4..74901d626 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -245,10 +245,12 @@ class Bus : public MemObject */ void addressRanges(AddrRangeList &resp, bool &snoop, int id); - /** Prepare a packet to be sent on the bus. The header finishes at tick - * headerTime + /** Calculate the timing parameters for the packet. Updates the + * firstWordTime and finishTime fields of the packet object. + * Returns the tick at which the packet header is completed (which + * will be all that is sent if the target rejects the packet). */ - void preparePacket(PacketPtr pkt, Tick & headerTime); + Tick calcPacketTiming(PacketPtr pkt); /** Occupy the bus until until */ void occupyBus(Tick until); diff --git a/src/mem/cache/BaseCache.py b/src/mem/cache/BaseCache.py index f6d42b1ef..bef1b45d2 100644 --- a/src/mem/cache/BaseCache.py +++ b/src/mem/cache/BaseCache.py @@ -38,8 +38,6 @@ class BaseCache(MemObject): block_size = Param.Int("block size in bytes") latency = Param.Latency("Latency") hash_delay = Param.Int(1, "time in cycles of hash access") - lifo = Param.Bool(False, - "whether this NIC partition should use LIFO repl. policy") max_miss_count = Param.Counter(0, "number of misses to handle before calling exit") mshrs = Param.Int("number of MSHRs (max outstanding requests)") @@ -47,9 +45,6 @@ class BaseCache(MemObject): "always service demand misses first") repl = Param.Repl(NULL, "replacement policy") size = Param.MemorySize("capacity in bytes") - split = Param.Bool(False, "whether or not this cache is split") - split_size = Param.Int(0, - "How many ways of the cache belong to CPU/LRU partition") subblock_size = Param.Int(0, "Size of subblock in IIC used for compression") tgts_per_mshr = Param.Int("max number of accesses per MSHR") @@ -57,12 +52,10 @@ class BaseCache(MemObject): two_queue = Param.Bool(False, "whether the lifo should have two queue replacement") write_buffers = Param.Int(8, "number of write buffers") - prefetch_miss = Param.Bool(False, - "wheter you are using the hardware prefetcher from Miss stream") - prefetch_access = Param.Bool(False, - "wheter you are using the hardware prefetcher from Access stream") + prefetch_on_access = Param.Bool(False, + "notify the hardware prefetcher on every access (not just misses)") prefetcher_size = Param.Int(100, - "Number of entries in the harware prefetch queue") + "Number of entries in the hardware prefetch queue") prefetch_past_page = Param.Bool(False, "Allow prefetches to cross virtual page boundaries") prefetch_serial_squash = Param.Bool(False, @@ -74,9 +67,9 @@ class BaseCache(MemObject): prefetch_policy = Param.Prefetch('none', "Type of prefetcher to use") prefetch_cache_check_push = Param.Bool(True, - "Check if in cash on push or pop of prefetch queue") + "Check if in cache on push or pop of prefetch queue") prefetch_use_cpu_id = Param.Bool(True, - "Use the CPU ID to seperate calculations of prefetches") + "Use the CPU ID to separate calculations of prefetches") prefetch_data_accesses_only = Param.Bool(False, "Only prefetch on data not on instruction accesses") cpu_side = Port("Port on side closer to CPU") diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index ac0d54bf6..956375530 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -122,7 +122,7 @@ BaseCache::CachePort::clearBlocked() mustSendRetry = false; SendRetryEvent *ev = new SendRetryEvent(this, true); // @TODO: need to find a better time (next bus cycle?) - ev->schedule(curTick + 1); + schedule(ev, curTick + 1); } } diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index d97021024..4319717e5 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -223,14 +223,14 @@ class BaseCache : public MemObject */ /** Number of hits per thread for each type of command. @sa Packet::Command */ - Stats::Vector<> hits[MemCmd::NUM_MEM_CMDS]; + Stats::Vector hits[MemCmd::NUM_MEM_CMDS]; /** Number of hits for demand accesses. */ Stats::Formula demandHits; /** Number of hit for all accesses. */ Stats::Formula overallHits; /** Number of misses per thread for each type of command. @sa Packet::Command */ - Stats::Vector<> misses[MemCmd::NUM_MEM_CMDS]; + Stats::Vector misses[MemCmd::NUM_MEM_CMDS]; /** Number of misses for demand accesses. */ Stats::Formula demandMisses; /** Number of misses for all accesses. */ @@ -240,7 +240,7 @@ class BaseCache : public MemObject * Total number of cycles per thread/command spent waiting for a miss. * Used to calculate the average miss latency. */ - Stats::Vector<> missLatency[MemCmd::NUM_MEM_CMDS]; + Stats::Vector missLatency[MemCmd::NUM_MEM_CMDS]; /** Total number of cycles spent waiting for demand misses. */ Stats::Formula demandMissLatency; /** Total number of cycles spent waiting for all misses. */ @@ -268,50 +268,50 @@ class BaseCache : public MemObject Stats::Formula overallAvgMissLatency; /** The total number of cycles blocked for each blocked cause. */ - Stats::Vector<> blocked_cycles; + Stats::Vector blocked_cycles; /** The number of times this cache blocked for each blocked cause. */ - Stats::Vector<> blocked_causes; + Stats::Vector blocked_causes; /** The average number of cycles blocked for each blocked cause. */ Stats::Formula avg_blocked; /** The number of fast writes (WH64) performed. */ - Stats::Scalar<> fastWrites; + Stats::Scalar fastWrites; /** The number of cache copies performed. */ - Stats::Scalar<> cacheCopies; + Stats::Scalar cacheCopies; /** Number of blocks written back per thread. */ - Stats::Vector<> writebacks; + Stats::Vector writebacks; /** Number of misses that hit in the MSHRs per command and thread. */ - Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS]; + Stats::Vector mshr_hits[MemCmd::NUM_MEM_CMDS]; /** Demand misses that hit in the MSHRs. */ Stats::Formula demandMshrHits; /** Total number of misses that hit in the MSHRs. */ Stats::Formula overallMshrHits; /** Number of misses that miss in the MSHRs, per command and thread. */ - Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS]; + Stats::Vector mshr_misses[MemCmd::NUM_MEM_CMDS]; /** Demand misses that miss in the MSHRs. */ Stats::Formula demandMshrMisses; /** Total number of misses that miss in the MSHRs. */ Stats::Formula overallMshrMisses; /** Number of misses that miss in the MSHRs, per command and thread. */ - Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS]; + Stats::Vector mshr_uncacheable[MemCmd::NUM_MEM_CMDS]; /** Total number of misses that miss in the MSHRs. */ Stats::Formula overallMshrUncacheable; /** Total cycle latency of each MSHR miss, per command and thread. */ - Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS]; + Stats::Vector mshr_miss_latency[MemCmd::NUM_MEM_CMDS]; /** Total cycle latency of demand MSHR misses. */ Stats::Formula demandMshrMissLatency; /** Total cycle latency of overall MSHR misses. */ Stats::Formula overallMshrMissLatency; /** Total cycle latency of each MSHR miss, per command and thread. */ - Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS]; + Stats::Vector mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS]; /** Total cycle latency of overall MSHR misses. */ Stats::Formula overallMshrUncacheableLatency; @@ -342,11 +342,11 @@ class BaseCache : public MemObject Stats::Formula overallAvgMshrUncacheableLatency; /** The number of times a thread hit its MSHR cap. */ - Stats::Vector<> mshr_cap_events; + Stats::Vector mshr_cap_events; /** The number of times software prefetches caused the MSHR to block. */ - Stats::Vector<> soft_prefetch_mshr_full; + Stats::Vector soft_prefetch_mshr_full; - Stats::Scalar<> mshr_no_allocate_misses; + Stats::Scalar mshr_no_allocate_misses; /** * @} @@ -445,12 +445,6 @@ class BaseCache : public MemObject } } - Tick nextMSHRReadyTime() - { - return std::min(mshrQueue.nextMSHRReadyTime(), - writeBuffer.nextMSHRReadyTime()); - } - /** * Request the master bus for the given cause and time. * @param cause The reason for the request. @@ -467,10 +461,11 @@ class BaseCache : public MemObject */ void deassertMemSideBusRequest(RequestCause cause) { - // obsolete!! - assert(false); - // memSidePort->deassertBusRequest(cause); - // checkDrain(); + // Obsolete... we no longer signal bus requests explicitly so + // we can't deassert them. Leaving this in as a no-op since + // the prefetcher calls it to indicate that it no longer wants + // to request a prefetch, and someday that might be + // interesting again. } virtual unsigned int drain(Event *de); @@ -481,7 +476,7 @@ class BaseCache : public MemObject void incMissCount(PacketPtr pkt) { - misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; + misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; if (missCount) { --missCount; diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh index 127c547ac..fe65672d6 100644 --- a/src/mem/cache/blk.hh +++ b/src/mem/cache/blk.hh @@ -38,8 +38,8 @@ #include <list> #include "base/printable.hh" -#include "sim/core.hh" // for Tick -#include "arch/isa_traits.hh" // for Addr +#include "sim/core.hh" // for Tick +#include "arch/isa_traits.hh" // for Addr #include "mem/packet.hh" #include "mem/request.hh" @@ -48,17 +48,17 @@ */ enum CacheBlkStatusBits { /** valid, readable */ - BlkValid = 0x01, + BlkValid = 0x01, /** write permission */ - BlkWritable = 0x02, + BlkWritable = 0x02, /** read permission (yes, block can be valid but not readable) */ - BlkReadable = 0x04, + BlkReadable = 0x04, /** dirty (modified) */ - BlkDirty = 0x08, + BlkDirty = 0x08, /** block was referenced */ - BlkReferenced = 0x10, + BlkReferenced = 0x10, /** block was a hardware prefetch yet unaccessed*/ - BlkHWPrefetched = 0x20 + BlkHWPrefetched = 0x20 }; /** @@ -108,18 +108,16 @@ class CacheBlk */ class Lock { public: - int cpuNum; // locking CPU - int threadNum; // locking thread ID within CPU + int contextId; // locking context // check for matching execution context bool matchesContext(Request *req) { - return (cpuNum == req->getCpuNum() && - threadNum == req->getThreadNum()); + return (contextId == req->contextId()); } Lock(Request *req) - : cpuNum(req->getCpuNum()), threadNum(req->getThreadNum()) + : contextId(req->contextId()) { } }; @@ -207,7 +205,7 @@ class CacheBlk * be touched. * @return True if the block was a hardware prefetch, unaccesed. */ - bool isPrefetch() const + bool wasPrefetched() const { return (status & BlkHWPrefetched) != 0; } diff --git a/src/mem/cache/builder.cc b/src/mem/cache/builder.cc index db900c64c..599353b88 100644 --- a/src/mem/cache/builder.cc +++ b/src/mem/cache/builder.cc @@ -38,7 +38,6 @@ // Must be included first to determine which caches we want #include "enums/Prefetch.hh" #include "mem/config/cache.hh" -#include "mem/config/prefetch.hh" #include "mem/cache/base.hh" #include "mem/cache/cache.hh" #include "mem/bus.hh" @@ -57,149 +56,78 @@ #include "mem/cache/tags/iic.hh" #endif -#if defined(USE_CACHE_SPLIT) -#include "mem/cache/tags/split.hh" -#endif - -#if defined(USE_CACHE_SPLIT_LIFO) -#include "mem/cache/tags/split_lifo.hh" -#endif - //Prefetcher Headers -#if defined(USE_GHB) #include "mem/cache/prefetch/ghb.hh" -#endif -#if defined(USE_TAGGED) #include "mem/cache/prefetch/tagged.hh" -#endif -#if defined(USE_STRIDED) #include "mem/cache/prefetch/stride.hh" -#endif using namespace std; using namespace TheISA; -#define BUILD_CACHE(TAGS, tags) \ - do { \ - BasePrefetcher *pf; \ - if (prefetch_policy == Enums::tagged) { \ - BUILD_TAGGED_PREFETCHER(TAGS); \ - } \ - else if (prefetch_policy == Enums::stride) { \ - BUILD_STRIDED_PREFETCHER(TAGS); \ - } \ - else if (prefetch_policy == Enums::ghb) { \ - BUILD_GHB_PREFETCHER(TAGS); \ - } \ - else { \ - BUILD_NULL_PREFETCHER(TAGS); \ - } \ - Cache<TAGS> *retval = \ - new Cache<TAGS>(this, tags, pf); \ - return retval; \ +#define BUILD_CACHE(TAGS, tags) \ + do { \ + BasePrefetcher *pf; \ + if (prefetch_policy == Enums::tagged) { \ + pf = new TaggedPrefetcher(this); \ + } \ + else if (prefetch_policy == Enums::stride) { \ + pf = new StridePrefetcher(this); \ + } \ + else if (prefetch_policy == Enums::ghb) { \ + pf = new GHBPrefetcher(this); \ + } \ + else { \ + pf = NULL; \ + } \ + Cache<TAGS> *retval = \ + new Cache<TAGS>(this, tags, pf); \ + return retval; \ } while (0) -#define BUILD_CACHE_PANIC(x) do { \ - panic("%s not compiled into M5", x); \ +#define BUILD_CACHE_PANIC(x) do { \ + panic("%s not compiled into M5", x); \ } while (0) #if defined(USE_CACHE_FALRU) -#define BUILD_FALRU_CACHE do { \ +#define BUILD_FALRU_CACHE do { \ FALRU *tags = new FALRU(block_size, size, latency); \ - BUILD_CACHE(FALRU, tags); \ + BUILD_CACHE(FALRU, tags); \ } while (0) #else #define BUILD_FALRU_CACHE BUILD_CACHE_PANIC("falru cache") #endif #if defined(USE_CACHE_LRU) -#define BUILD_LRU_CACHE do { \ - LRU *tags = new LRU(numSets, block_size, assoc, latency); \ - BUILD_CACHE(LRU, tags); \ +#define BUILD_LRU_CACHE do { \ + LRU *tags = new LRU(numSets, block_size, assoc, latency); \ + BUILD_CACHE(LRU, tags); \ } while (0) #else #define BUILD_LRU_CACHE BUILD_CACHE_PANIC("lru cache") #endif -#if defined(USE_CACHE_SPLIT) -#define BUILD_SPLIT_CACHE do { \ - Split *tags = new Split(numSets, block_size, assoc, split_size, lifo, \ - two_queue, latency); \ - BUILD_CACHE(Split, tags); \ - } while (0) -#else -#define BUILD_SPLIT_CACHE BUILD_CACHE_PANIC("split cache") -#endif - -#if defined(USE_CACHE_SPLIT_LIFO) -#define BUILD_SPLIT_LIFO_CACHE do { \ - SplitLIFO *tags = new SplitLIFO(block_size, size, assoc, \ - latency, two_queue, -1); \ - BUILD_CACHE(SplitLIFO, tags); \ - } while (0) -#else -#define BUILD_SPLIT_LIFO_CACHE BUILD_CACHE_PANIC("lifo cache") -#endif - #if defined(USE_CACHE_IIC) -#define BUILD_IIC_CACHE do { \ - IIC *tags = new IIC(iic_params); \ - BUILD_CACHE(IIC, tags); \ +#define BUILD_IIC_CACHE do { \ + IIC *tags = new IIC(iic_params); \ + BUILD_CACHE(IIC, tags); \ } while (0) #else #define BUILD_IIC_CACHE BUILD_CACHE_PANIC("iic") #endif -#define BUILD_CACHES do { \ - if (repl == NULL) { \ - if (numSets == 1) { \ - BUILD_FALRU_CACHE; \ - } else { \ - if (split == true) { \ - BUILD_SPLIT_CACHE; \ - } else if (lifo == true) { \ - BUILD_SPLIT_LIFO_CACHE; \ - } else { \ - BUILD_LRU_CACHE; \ - } \ - } \ - } else { \ - BUILD_IIC_CACHE; \ - } \ - } while (0) - -#define BUILD_COHERENCE(b) do { \ +#define BUILD_CACHES do { \ + if (repl == NULL) { \ + if (numSets == 1) { \ + BUILD_FALRU_CACHE; \ + } else { \ + BUILD_LRU_CACHE; \ + } \ + } else { \ + BUILD_IIC_CACHE; \ + } \ } while (0) -#if defined(USE_TAGGED) -#define BUILD_TAGGED_PREFETCHER(t) \ - pf = new TaggedPrefetcher(this) -#else -#define BUILD_TAGGED_PREFETCHER(t) BUILD_CACHE_PANIC("Tagged Prefetcher") -#endif - -#if defined(USE_STRIDED) -#define BUILD_STRIDED_PREFETCHER(t) \ - pf = new StridePrefetcher(this) -#else -#define BUILD_STRIDED_PREFETCHER(t) BUILD_CACHE_PANIC("Stride Prefetcher") -#endif - -#if defined(USE_GHB) -#define BUILD_GHB_PREFETCHER(t) \ - pf = new GHBPrefetcher(this) -#else -#define BUILD_GHB_PREFETCHER(t) BUILD_CACHE_PANIC("GHB Prefetcher") -#endif - -#if defined(USE_TAGGED) -#define BUILD_NULL_PREFETCHER(t) \ - pf = new TaggedPrefetcher(this) -#else -#define BUILD_NULL_PREFETCHER(t) BUILD_CACHE_PANIC("NULL Prefetcher (uses Tagged)") -#endif - BaseCache * BaseCacheParams::create() { @@ -208,24 +136,6 @@ BaseCacheParams::create() subblock_size = block_size; } - //Warnings about prefetcher policy - if (prefetch_policy == Enums::none) { - if (prefetch_miss || prefetch_access) - panic("With no prefetcher, you shouldn't prefetch from" - " either miss or access stream\n"); - } - - if (prefetch_policy == Enums::tagged || prefetch_policy == Enums::stride || - prefetch_policy == Enums::ghb) { - - if (!prefetch_miss && !prefetch_access) - warn("With this prefetcher you should chose a prefetch" - " stream (miss or access)\nNo Prefetching will occur\n"); - - if (prefetch_miss && prefetch_access) - panic("Can't do prefetches from both miss and access stream"); - } - #if defined(USE_CACHE_IIC) // Build IIC params IIC::Params iic_params; diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc index c640d4a60..d403535fc 100644 --- a/src/mem/cache/cache.cc +++ b/src/mem/cache/cache.cc @@ -50,14 +50,6 @@ #include "mem/cache/tags/iic.hh" #endif -#if defined(USE_CACHE_SPLIT) -#include "mem/cache/tags/split.hh" -#endif - -#if defined(USE_CACHE_SPLIT_LIFO) -#include "mem/cache/tags/split_lifo.hh" -#endif - #include "mem/cache/cache_impl.hh" // Template Instantiations @@ -76,12 +68,4 @@ template class Cache<IIC>; template class Cache<LRU>; #endif -#if defined(USE_CACHE_SPLIT) -template class Cache<Split>; -#endif - -#if defined(USE_CACHE_SPLIT_LIFO) -template class Cache<SplitLIFO>; -#endif - #endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index f5f65d4dd..4570b067b 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -64,8 +64,6 @@ class Cache : public BaseCache /** A typedef for a list of BlkType pointers. */ typedef typename TagStore::BlkList BlkList; - bool prefetchAccess; - protected: class CpuSidePort : public CachePort @@ -137,21 +135,14 @@ class Cache : public BaseCache BlkType *tempBlock; /** - * Can this cache should allocate a block on a line-sized write miss. + * This cache should allocate a block on a line-sized write miss. */ const bool doFastWrites; - const bool prefetchMiss; - /** - * Handle a replacement for the given request. - * @param blk A pointer to the block, usually NULL - * @param pkt The memory request to satisfy. - * @param new_state The new state of the block. - * @param writebacks A list to store any generated writebacks. + * Notify the prefetcher on every access, not just misses. */ - BlkType* doReplacement(BlkType *blk, PacketPtr pkt, - CacheBlk::State new_state, PacketList &writebacks); + const bool prefetchOnAccess; /** * Does all the processing necessary to perform the provided request. @@ -159,10 +150,10 @@ class Cache : public BaseCache * @param lat The latency of the access. * @param writebacks List for any writebacks that need to be performed. * @param update True if the replacement data should be updated. - * @return Pointer to the cache block touched by the request. NULL if it - * was a miss. + * @return Boolean indicating whether the request was satisfied. */ - bool access(PacketPtr pkt, BlkType *&blk, int &lat); + bool access(PacketPtr pkt, BlkType *&blk, + int &lat, PacketList &writebacks); /** *Handle doing the Compare and Swap function for SPARC. @@ -181,7 +172,6 @@ class Cache : public BaseCache * Populates a cache block and handles all outstanding requests for the * satisfied fill request. This version takes two memory requests. One * contains the fill data, the other is an optional target to satisfy. - * Used for Cache::probe. * @param pkt The memory request with the fill data. * @param blk The cache block if it already exists. * @param writebacks List for any writebacks that need to be performed. @@ -331,6 +321,11 @@ class Cache : public BaseCache bool inMissQueue(Addr addr) { return (mshrQueue.findMatch(addr) != 0); } + + /** + * Find next request ready time from among possible sources. + */ + Tick nextMSHRReadyTime(); }; #endif // __CACHE_HH__ diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index e546e2a9a..a78fd3637 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -38,6 +38,7 @@ */ #include "sim/host.hh" +#include "base/fast_alloc.hh" #include "base/misc.hh" #include "base/range_ops.hh" @@ -52,11 +53,10 @@ template<class TagStore> Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf) : BaseCache(p), - prefetchAccess(p->prefetch_access), tags(tags), prefetcher(pf), doFastWrites(true), - prefetchMiss(p->prefetch_miss) + prefetchOnAccess(p->prefetch_on_access) { tempBlock = new BlkType(); tempBlock->data = new uint8_t[blkSize]; @@ -71,7 +71,8 @@ Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf) memSidePort->setOtherPort(cpuSidePort); tags->setCache(this); - prefetcher->setCache(this); + if (prefetcher) + prefetcher->setCache(this); } template<class TagStore> @@ -80,7 +81,8 @@ Cache<TagStore>::regStats() { BaseCache::regStats(); tags->regStats(name()); - prefetcher->regStats(name()); + if (prefetcher) + prefetcher->regStats(name()); } template<class TagStore> @@ -147,8 +149,10 @@ Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt) panic("Invalid size for conditional read/write\n"); } - if (overwrite_mem) + if (overwrite_mem) { std::memcpy(blk_data, &overwrite_val, pkt->getSize()); + blk->status |= BlkDirty; + } } @@ -259,7 +263,8 @@ Cache<TagStore>::squash(int threadNum) template<class TagStore> bool -Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat) +Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, + int &lat, PacketList &writebacks) { if (pkt->req->isUncacheable()) { blk = NULL; @@ -267,34 +272,16 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat) return false; } - blk = tags->findBlock(pkt->getAddr(), lat); - - if (prefetchAccess) { - //We are determining prefetches on access stream, call prefetcher - prefetcher->handleMiss(pkt, curTick); - } + blk = tags->accessBlock(pkt->getAddr(), lat); DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(), pkt->getAddr(), (blk) ? "hit" : "miss"); if (blk != NULL) { - if (blk->isPrefetch()) { - //Signal that this was a hit under prefetch (no need for - //use prefetch (only can get here if true) - DPRINTF(HWPrefetch, "Hit a block that was prefetched\n"); - blk->status &= ~BlkHWPrefetched; - if (prefetchMiss) { - //If we are using the miss stream, signal the - //prefetcher otherwise the access stream would have - //already signaled this hit - prefetcher->handleMiss(pkt, curTick); - } - } - if (pkt->needsExclusive() ? blk->isWritable() : blk->isReadable()) { // OK to satisfy access - hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; + hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; satisfyCpuSideRequest(pkt, blk); return true; } @@ -307,7 +294,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat) // into the cache without having a writeable copy (or any copy at // all). if (pkt->cmd == MemCmd::Writeback) { - PacketList writebacks; assert(blkSize == pkt->getSize()); if (blk == NULL) { // need to do a replacement @@ -318,19 +304,14 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat) incMissCount(pkt); return false; } + tags->insertBlock(pkt->getAddr(), blk); blk->status = BlkValid | BlkReadable; } std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize); blk->status |= BlkDirty; - // copy writebacks from replacement to write buffer - while (!writebacks.empty()) { - PacketPtr wbPkt = writebacks.front(); - allocateWriteBuffer(wbPkt, curTick + hitLatency, true); - writebacks.pop_front(); - } // nothing else to do; writeback doesn't expect response assert(!pkt->needsResponse()); - hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; + hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; return true; } @@ -346,7 +327,7 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat) } -class ForwardResponseRecord : public Packet::SenderState +class ForwardResponseRecord : public Packet::SenderState, public FastAlloc { Packet::SenderState *prevSenderState; int prevSrc; @@ -407,6 +388,9 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) memSidePort->sendTiming(snoopPkt); // main memory will delete snoopPkt } + // since we're the official target but we aren't responding, + // delete the packet now. + delete pkt; return true; } @@ -423,13 +407,13 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) int lat = hitLatency; BlkType *blk = NULL; - bool satisfied = access(pkt, blk, lat); + PacketList writebacks; + + bool satisfied = access(pkt, blk, lat, writebacks); #if 0 /** @todo make the fast write alloc (wh64) work with coherence. */ - PacketList writebacks; - // If this is a block size write/hint (WH64) allocate the block here // if the coherence protocol allows it. if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() && @@ -447,15 +431,11 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) ++fastWrites; } } - - // copy writebacks to write buffer - while (!writebacks.empty()) { - PacketPtr wbPkt = writebacks.front(); - allocateWriteBuffer(wbPkt, time, true); - writebacks.pop_front(); - } #endif + // track time of availability of next prefetch, if any + Tick next_pf_time = 0; + bool needsResponse = pkt->needsResponse(); if (satisfied) { @@ -465,10 +445,14 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) } else { delete pkt; } + + if (prefetcher && (prefetchOnAccess || (blk && blk->wasPrefetched()))) { + if (blk) + blk->status &= ~BlkHWPrefetched; + next_pf_time = prefetcher->notify(pkt, time); + } } else { // miss - if (prefetchMiss) - prefetcher->handleMiss(pkt, time); Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1)); MSHR *mshr = mshrQueue.findMatch(blk_addr); @@ -476,8 +460,8 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) if (mshr) { // MSHR hit //@todo remove hw_pf here - mshr_hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) { + mshr_hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; + if (mshr->threadNum != 0/*pkt->req->threadId()*/) { mshr->threadNum = -1; } mshr->allocateTarget(pkt, time, order++); @@ -491,7 +475,7 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) } } else { // no MSHR - mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; + mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; // always mark as cache fill for now... if we implement // no-write-allocate or bypass accesses this will have to // be changed. @@ -520,9 +504,23 @@ Cache<TagStore>::timingAccess(PacketPtr pkt) allocateMissBuffer(pkt, time, true); } + + if (prefetcher) { + next_pf_time = prefetcher->notify(pkt, time); + } } } + if (next_pf_time != 0) + requestMemSideBus(Request_PF, std::max(time, next_pf_time)); + + // copy writebacks to write buffer + while (!writebacks.empty()) { + PacketPtr wbPkt = writebacks.front(); + allocateWriteBuffer(wbPkt, time, true); + writebacks.pop_front(); + } + return true; } @@ -610,53 +608,79 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt) // access in timing mode BlkType *blk = NULL; + PacketList writebacks; - if (!access(pkt, blk, lat)) { + if (!access(pkt, blk, lat, writebacks)) { // MISS - PacketPtr busPkt = getBusPacket(pkt, blk, pkt->needsExclusive()); + PacketPtr bus_pkt = getBusPacket(pkt, blk, pkt->needsExclusive()); - bool isCacheFill = (busPkt != NULL); + bool is_forward = (bus_pkt == NULL); - if (busPkt == NULL) { + if (is_forward) { // just forwarding the same request to the next level // no local cache operation involved - busPkt = pkt; + bus_pkt = pkt; } DPRINTF(Cache, "Sending an atomic %s for %x\n", - busPkt->cmdString(), busPkt->getAddr()); + bus_pkt->cmdString(), bus_pkt->getAddr()); #if TRACING_ON CacheBlk::State old_state = blk ? blk->status : 0; #endif - lat += memSidePort->sendAtomic(busPkt); + lat += memSidePort->sendAtomic(bus_pkt); DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n", - busPkt->cmdString(), busPkt->getAddr(), old_state); - - bool is_error = busPkt->isError(); - assert(!busPkt->wasNacked()); - - if (is_error && pkt->needsResponse()) { - pkt->makeAtomicResponse(); - pkt->copyError(busPkt); - } else if (isCacheFill && !is_error) { - PacketList writebacks; - blk = handleFill(busPkt, blk, writebacks); - satisfyCpuSideRequest(pkt, blk); - delete busPkt; - - // Handle writebacks if needed - while (!writebacks.empty()){ - PacketPtr wbPkt = writebacks.front(); - memSidePort->sendAtomic(wbPkt); - writebacks.pop_front(); - delete wbPkt; + bus_pkt->cmdString(), bus_pkt->getAddr(), old_state); + + assert(!bus_pkt->wasNacked()); + + // If packet was a forward, the response (if any) is already + // in place in the bus_pkt == pkt structure, so we don't need + // to do anything. Otherwise, use the separate bus_pkt to + // generate response to pkt and then delete it. + if (!is_forward) { + if (pkt->needsResponse()) { + assert(bus_pkt->isResponse()); + if (bus_pkt->isError()) { + pkt->makeAtomicResponse(); + pkt->copyError(bus_pkt); + } else if (bus_pkt->isRead() || + bus_pkt->cmd == MemCmd::UpgradeResp) { + // we're updating cache state to allow us to + // satisfy the upstream request from the cache + blk = handleFill(bus_pkt, blk, writebacks); + satisfyCpuSideRequest(pkt, blk); + } else { + // we're satisfying the upstream request without + // modifying cache state, e.g., a write-through + pkt->makeAtomicResponse(); + } } + delete bus_pkt; } } + // Note that we don't invoke the prefetcher at all in atomic mode. + // It's not clear how to do it properly, particularly for + // prefetchers that aggressively generate prefetch candidates and + // rely on bandwidth contention to throttle them; these will tend + // to pollute the cache in atomic mode since there is no bandwidth + // contention. If we ever do want to enable prefetching in atomic + // mode, though, this is the place to do it... see timingAccess() + // for an example (though we'd want to issue the prefetch(es) + // immediately rather than calling requestMemSideBus() as we do + // there). + + // Handle writebacks if needed + while (!writebacks.empty()){ + PacketPtr wbPkt = writebacks.front(); + memSidePort->sendAtomic(wbPkt); + writebacks.pop_front(); + delete wbPkt; + } + // We now have the block one way or another (hit or completed miss) if (pkt->needsResponse()) { @@ -742,14 +766,17 @@ Cache<TagStore>::handleResponse(PacketPtr pkt) PacketList writebacks; if (pkt->req->isUncacheable()) { - mshr_uncacheable_lat[stats_cmd_idx][0/*pkt->req->getThreadNum()*/] += + mshr_uncacheable_lat[stats_cmd_idx][0/*pkt->req->threadId()*/] += miss_latency; } else { - mshr_miss_latency[stats_cmd_idx][0/*pkt->req->getThreadNum()*/] += + mshr_miss_latency[stats_cmd_idx][0/*pkt->req->threadId()*/] += miss_latency; } - if (mshr->isCacheFill && !is_error) { + bool is_fill = !mshr->isForward && + (pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp); + + if (is_fill && !is_error) { DPRINTF(Cache, "Block for addr %x being updated in Cache\n", pkt->getAddr()); @@ -770,9 +797,10 @@ Cache<TagStore>::handleResponse(PacketPtr pkt) while (mshr->hasTargets()) { MSHR::Target *target = mshr->getTarget(); - if (target->isCpuSide()) { + switch (target->source) { + case MSHR::Target::FromCPU: Tick completion_time; - if (blk != NULL) { + if (is_fill) { satisfyCpuSideRequest(target->pkt, blk); // How many bytes past the first request is this one int transfer_offset = @@ -786,7 +814,7 @@ Cache<TagStore>::handleResponse(PacketPtr pkt) (transfer_offset ? pkt->finishTime : pkt->firstWordTime); assert(!target->pkt->req->isUncacheable()); - missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += + missLatency[target->pkt->cmdToIndex()][0/*pkt->req->threadId()*/] += completion_time - target->recvTime; } else { // not a cache fill, just forwarding response @@ -808,13 +836,27 @@ Cache<TagStore>::handleResponse(PacketPtr pkt) target->pkt->cmd = MemCmd::ReadRespWithInvalidate; } cpuSidePort->respond(target->pkt, completion_time); - } else { + break; + + case MSHR::Target::FromPrefetcher: + assert(target->pkt->cmd == MemCmd::HardPFReq); + if (blk) + blk->status |= BlkHWPrefetched; + delete target->pkt->req; + delete target->pkt; + break; + + case MSHR::Target::FromSnoop: // I don't believe that a snoop can be in an error state assert(!is_error); // response to snoop request DPRINTF(Cache, "processing deferred snoop...\n"); handleSnoop(target->pkt, blk, true, true, mshr->pendingInvalidate || pkt->isInvalidate()); + break; + + default: + panic("Illegal target->source enum %d\n", target->source); } mshr->popTarget(); @@ -825,6 +867,9 @@ Cache<TagStore>::handleResponse(PacketPtr pkt) } if (mshr->promoteDeferredTargets()) { + // avoid later read getting stale data while write miss is + // outstanding.. see comment in timingAccess() + blk->status &= ~BlkReadable; MSHRQueue *mq = mshr->queue; mq->markPending(mshr); requestMemSideBus((RequestCause)mq->index, pkt->finishTime); @@ -861,7 +906,7 @@ Cache<TagStore>::writebackBlk(BlkType *blk) { assert(blk && blk->isValid() && blk->isDirty()); - writebacks[0/*pkt->req->getThreadNum()*/]++; + writebacks[0/*pkt->req->threadId()*/]++; Request *writebackReq = new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0); @@ -878,7 +923,7 @@ template<class TagStore> typename Cache<TagStore>::BlkType* Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks) { - BlkType *blk = tags->findReplacement(addr, writebacks); + BlkType *blk = tags->findVictim(addr, writebacks); if (blk->isValid()) { Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set); @@ -889,6 +934,7 @@ Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks) assert(!blk->isWritable()); assert(repl_mshr->needsExclusive()); // too hard to replace block with transient state + // allocation failed, block not inserted return NULL; } else { DPRINTF(Cache, "replacement: replacing %x with %x: %s\n", @@ -902,8 +948,6 @@ Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks) } } - // Set tag for new block. Caller is responsible for setting status. - blk->tag = tags->extractTag(addr); return blk; } @@ -934,7 +978,10 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk, assert(!tempBlock->isValid()); blk = tempBlock; tempBlock->set = tags->extractSet(addr); + tempBlock->tag = tags->extractTag(addr); DPRINTF(Cache, "using temp block for %x\n", addr); + } else { + tags->insertBlock(addr, blk); } } else { // existing block... probably an upgrade @@ -1088,6 +1135,11 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk, pkt->makeAtomicResponse(); pkt->setDataFromBlock(blk->data, blkSize); } + } else if (is_timing && is_deferred) { + // if it's a deferred timing snoop then we've made a copy of + // the packet, and so if we're not using that copy to respond + // then we need to delete it here. + delete pkt; } // Do this last in case it deallocates block data or something @@ -1156,6 +1208,7 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt) if (pkt->isInvalidate()) { // Invalidation trumps our writeback... discard here markInService(mshr); + delete wb_pkt; } // If this was a shared writeback, there may still be @@ -1253,7 +1306,7 @@ Cache<TagStore>::getNextMSHR() if (pkt) { // Update statistic on number of prefetches issued // (hwpf_mshr_misses) - mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; + mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++; // Don't request bus, since we already have it return allocateMissBuffer(pkt, curTick, false); } @@ -1277,7 +1330,7 @@ Cache<TagStore>::getTimingPacket() PacketPtr tgt_pkt = mshr->getTarget()->pkt; PacketPtr pkt = NULL; - if (mshr->isSimpleForward()) { + if (mshr->isForwardNoResponse()) { // no response expected, just forward packet as it is assert(tags->findBlock(mshr->addr) == NULL); pkt = tgt_pkt; @@ -1285,11 +1338,10 @@ Cache<TagStore>::getTimingPacket() BlkType *blk = tags->findBlock(mshr->addr); pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive()); - mshr->isCacheFill = (pkt != NULL); + mshr->isForward = (pkt == NULL); - if (pkt == NULL) { + if (mshr->isForward) { // not a cache block request, but a response is expected - assert(!mshr->isSimpleForward()); // make copy of current packet to forward, keep current // copy for response handling pkt = new Packet(tgt_pkt); @@ -1306,6 +1358,22 @@ Cache<TagStore>::getTimingPacket() } +template<class TagStore> +Tick +Cache<TagStore>::nextMSHRReadyTime() +{ + Tick nextReady = std::min(mshrQueue.nextMSHRReadyTime(), + writeBuffer.nextMSHRReadyTime()); + + if (prefetcher) { + nextReady = std::min(nextReady, + prefetcher->nextPrefetchReadyTime()); + } + + return nextReady; +} + + /////////////// // // CpuSidePort @@ -1463,7 +1531,7 @@ Cache<TagStore>::MemSidePort::sendPacket() waitingOnRetry = !success; if (waitingOnRetry) { DPRINTF(CachePort, "now waiting on a retry\n"); - if (!mshr->isSimpleForward()) { + if (!mshr->isForwardNoResponse()) { delete pkt; } } else { @@ -1481,7 +1549,7 @@ Cache<TagStore>::MemSidePort::sendPacket() // @TODO: need to facotr in prefetch requests here somehow if (nextReady != MaxTick) { DPRINTF(CachePort, "more packets to send @ %d\n", nextReady); - sendEvent->schedule(std::max(nextReady, curTick + 1)); + schedule(sendEvent, std::max(nextReady, curTick + 1)); } else { // no more to send right now: if we're draining, we may be done if (drainEvent) { diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc index 6537f6343..9ec9c090c 100644 --- a/src/mem/cache/mshr.cc +++ b/src/mem/cache/mshr.cc @@ -64,9 +64,9 @@ MSHR::TargetList::TargetList() inline void MSHR::TargetList::add(PacketPtr pkt, Tick readyTime, - Counter order, bool cpuSide, bool markPending) + Counter order, Target::Source source, bool markPending) { - if (cpuSide) { + if (source != Target::FromSnoop) { if (pkt->needsExclusive()) { needsExclusive = true; } @@ -84,7 +84,7 @@ MSHR::TargetList::add(PacketPtr pkt, Tick readyTime, } } - push_back(Target(pkt, readyTime, order, cpuSide, markPending)); + push_back(Target(pkt, readyTime, order, source, markPending)); } @@ -141,7 +141,14 @@ print(std::ostream &os, int verbosity, const std::string &prefix) const { ConstIterator end_i = end(); for (ConstIterator i = begin(); i != end_i; ++i) { - ccprintf(os, "%s%s: ", prefix, i->isCpuSide() ? "cpu" : "mem"); + const char *s; + switch (i->source) { + case Target::FromCPU: s = "FromCPU"; + case Target::FromSnoop: s = "FromSnoop"; + case Target::FromPrefetcher: s = "FromPrefetcher"; + default: s = ""; + } + ccprintf(os, "%s%s: ", prefix, s); i->pkt->print(os, verbosity, ""); } } @@ -156,16 +163,18 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target, readyTime = whenReady; order = _order; assert(target); - isCacheFill = false; + isForward = false; _isUncacheable = target->req->isUncacheable(); inService = false; downstreamPending = false; threadNum = 0; ntargets = 1; - // Don't know of a case where we would allocate a new MSHR for a - // snoop (mem-side request), so set cpuSide to true here. assert(targets->isReset()); - targets->add(target, whenReady, _order, true, true); + // Don't know of a case where we would allocate a new MSHR for a + // snoop (mem-side request), so set source according to request here + Target::Source source = (target->cmd == MemCmd::HardPFReq) ? + Target::FromPrefetcher : Target::FromCPU; + targets->add(target, whenReady, _order, source, true); assert(deferredTargets->isReset()); pendingInvalidate = false; pendingShared = false; @@ -187,7 +196,7 @@ bool MSHR::markInService() { assert(!inService); - if (isSimpleForward()) { + if (isForwardNoResponse()) { // we just forwarded the request packet & don't expect a // response, so get rid of it assert(getNumTargets() == 1); @@ -230,17 +239,22 @@ MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) // comes back (but before this target is processed) // - the outstanding request is for a non-exclusive block and this // target requires an exclusive block + + // assume we'd never issue a prefetch when we've got an + // outstanding miss + assert(pkt->cmd != MemCmd::HardPFReq); + if (inService && (!deferredTargets->empty() || pendingInvalidate || (!targets->needsExclusive && pkt->needsExclusive()))) { // need to put on deferred list - deferredTargets->add(pkt, whenReady, _order, true, true); + deferredTargets->add(pkt, whenReady, _order, Target::FromCPU, true); } else { // No request outstanding, or still OK to append to // outstanding request: append to regular target list. Only // mark pending if current request hasn't been issued yet // (isn't in service). - targets->add(pkt, whenReady, _order, true, !inService); + targets->add(pkt, whenReady, _order, Target::FromCPU, !inService); } ++ntargets; @@ -291,7 +305,7 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order) // actual target device (typ. PhysicalMemory) will delete the // packet on reception, so we need to save a copy here PacketPtr cp_pkt = new Packet(pkt, true); - targets->add(cp_pkt, curTick, _order, false, + targets->add(cp_pkt, curTick, _order, Target::FromSnoop, downstreamPending && targets->needsExclusive); ++ntargets; @@ -403,7 +417,8 @@ MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const { ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n", prefix, addr, addr+size-1, - isCacheFill ? "Fill" : "", + isForward ? "Forward" : "", + isForwardNoResponse() ? "ForwNoResp" : "", needsExclusive() ? "Excl" : "", _isUncacheable ? "Unc" : "", inService ? "InSvc" : "", diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh index fdb0485cb..bed7012b0 100644 --- a/src/mem/cache/mshr.hh +++ b/src/mem/cache/mshr.hh @@ -55,20 +55,25 @@ class MSHR : public Packet::SenderState, public Printable class Target { public: + + enum Source { + FromCPU, + FromSnoop, + FromPrefetcher + }; + Tick recvTime; //!< Time when request was received (for stats) Tick readyTime; //!< Time when request is ready to be serviced Counter order; //!< Global order (for memory consistency mgmt) PacketPtr pkt; //!< Pending request packet. - bool cpuSide; //!< Did request come from cpu side or mem side? + Source source; //!< Did request come from cpu, memory, or prefetcher? bool markedPending; //!< Did we mark upstream MSHR //!< as downstreamPending? - bool isCpuSide() const { return cpuSide; } - Target(PacketPtr _pkt, Tick _readyTime, Counter _order, - bool _cpuSide, bool _markedPending) + Source _source, bool _markedPending) : recvTime(curTick), readyTime(_readyTime), order(_order), - pkt(_pkt), cpuSide(_cpuSide), markedPending(_markedPending) + pkt(_pkt), source(_source), markedPending(_markedPending) {} }; @@ -85,7 +90,7 @@ class MSHR : public Packet::SenderState, public Printable void resetFlags() { needsExclusive = hasUpgrade = false; } bool isReset() { return !needsExclusive && !hasUpgrade; } void add(PacketPtr pkt, Tick readyTime, Counter order, - bool cpuSide, bool markPending); + Target::Source source, bool markPending); void replaceUpgrades(); void clearDownstreamPending(); bool checkFunctional(PacketPtr pkt); @@ -118,8 +123,8 @@ class MSHR : public Packet::SenderState, public Printable /** True if the request has been sent to the bus. */ bool inService; - /** True if we will be putting the returned block in the cache */ - bool isCacheFill; + /** True if the request is just a simple forward from an upper level */ + bool isForward; /** True if we need to get an exclusive copy of the block. */ bool needsExclusive() const { return targets->needsExclusive; } @@ -200,7 +205,7 @@ public: * Returns the current number of allocated targets. * @return The current number of allocated targets. */ - int getNumTargets() { return ntargets; } + int getNumTargets() const { return ntargets; } /** * Returns a pointer to the target list. @@ -212,13 +217,17 @@ public: * Returns true if there are targets left. * @return true if there are targets */ - bool hasTargets() { return !targets->empty(); } + bool hasTargets() const { return !targets->empty(); } /** * Returns a reference to the first target. * @return A pointer to the first target. */ - Target *getTarget() { assert(hasTargets()); return &targets->front(); } + Target *getTarget() const + { + assert(hasTargets()); + return &targets->front(); + } /** * Pop first target. @@ -229,12 +238,12 @@ public: targets->pop_front(); } - bool isSimpleForward() + bool isForwardNoResponse() const { if (getNumTargets() != 1) return false; Target *tgt = getTarget(); - return tgt->isCpuSide() && !tgt->pkt->needsResponse(); + return tgt->source == Target::FromCPU && !tgt->pkt->needsResponse(); } bool promoteDeferredTargets(); diff --git a/src/mem/cache/mshr_queue.cc b/src/mem/cache/mshr_queue.cc index 45331c33d..b5c6cc7b8 100644 --- a/src/mem/cache/mshr_queue.cc +++ b/src/mem/cache/mshr_queue.cc @@ -230,7 +230,7 @@ MSHRQueue::squash(int threadNum) if (mshr->threadNum == threadNum) { while (mshr->hasTargets()) { mshr->popTarget(); - assert(0/*target->req->getThreadNum()*/ == threadNum); + assert(0/*target->req->threadId()*/ == threadNum); } assert(!mshr->hasTargets()); assert(mshr->ntargets==0); diff --git a/src/mem/cache/prefetch/base.cc b/src/mem/cache/prefetch/base.cc index fcc02ff28..365ce6727 100644 --- a/src/mem/cache/prefetch/base.cc +++ b/src/mem/cache/prefetch/base.cc @@ -33,6 +33,7 @@ * Hardware Prefetcher Definition. */ +#include "arch/isa_traits.hh" #include "base/trace.hh" #include "mem/cache/base.hh" #include "mem/cache/prefetch/base.hh" @@ -43,7 +44,7 @@ BasePrefetcher::BasePrefetcher(const BaseCacheParams *p) : size(p->prefetcher_size), pageStop(!p->prefetch_past_page), serialSquash(p->prefetch_serial_squash), cacheCheckPush(p->prefetch_cache_check_push), - only_data(p->prefetch_data_accesses_only) + onlyData(p->prefetch_data_accesses_only) { } @@ -52,6 +53,7 @@ BasePrefetcher::setCache(BaseCache *_cache) { cache = _cache; blkSize = cache->getBlockSize(); + _name = cache->name() + "-pf"; } void @@ -99,7 +101,8 @@ BasePrefetcher::regStats(const std::string &name) pfSquashed .name(name + ".prefetcher.num_hwpf_squashed_from_miss") - .desc("number of hwpf that got squashed due to a miss aborting calculation time") + .desc("number of hwpf that got squashed due to a miss " + "aborting calculation time") ; } @@ -126,60 +129,79 @@ BasePrefetcher::inMissQueue(Addr addr) PacketPtr BasePrefetcher::getPacket() { - DPRINTF(HWPrefetch, "%s:Requesting a hw_pf to issue\n", cache->name()); + DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n"); if (pf.empty()) { - DPRINTF(HWPrefetch, "%s:No HW_PF found\n", cache->name()); + DPRINTF(HWPrefetch, "No HW_PF found\n"); return NULL; } PacketPtr pkt; - bool keepTrying = false; + bool keep_trying = false; do { pkt = *pf.begin(); pf.pop_front(); if (!cacheCheckPush) { - keepTrying = cache->inCache(pkt->getAddr()); + keep_trying = cache->inCache(pkt->getAddr()); } + + if (keep_trying) { + DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n", + pkt->getAddr()); + delete pkt->req; + delete pkt; + } + if (pf.empty()) { cache->deassertMemSideBusRequest(BaseCache::Request_PF); - if (keepTrying) return NULL; //None left, all were in cache + if (keep_trying) { + return NULL; // None left, all were in cache + } } - } while (keepTrying); + } while (keep_trying); pfIssued++; + assert(pkt != NULL); + DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr()); return pkt; } -void -BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time) + +Tick +BasePrefetcher::notify(PacketPtr &pkt, Tick time) { - if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && only_data)) - { - //Calculate the blk address - Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1); + if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && onlyData)) { + // Calculate the blk address + Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); - //Check if miss is in pfq, if so remove it - std::list<PacketPtr>::iterator iter = inPrefetch(blkAddr); + // Check if miss is in pfq, if so remove it + std::list<PacketPtr>::iterator iter = inPrefetch(blk_addr); if (iter != pf.end()) { - DPRINTF(HWPrefetch, "%s:Saw a miss to a queued prefetch, removing it\n", cache->name()); + DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: " + "0x%x, removing it\n", blk_addr); pfRemovedMSHR++; + delete (*iter)->req; + delete (*iter); pf.erase(iter); if (pf.empty()) cache->deassertMemSideBusRequest(BaseCache::Request_PF); } - //Remove anything in queue with delay older than time - //since everything is inserted in time order, start from end - //and work until pf.empty() or time is earlier - //This is done to emulate Aborting the previous work on a new miss - //Needed for serial calculators like GHB + // Remove anything in queue with delay older than time + // since everything is inserted in time order, start from end + // and work until pf.empty() or time is earlier + // This is done to emulate Aborting the previous work on a new miss + // Needed for serial calculators like GHB if (serialSquash) { iter = pf.end(); iter--; while (!pf.empty() && ((*iter)->time >= time)) { pfSquashed++; - pf.pop_back(); + DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n", + (*iter)->getAddr()); + delete (*iter)->req; + delete (*iter); + pf.erase(iter); iter--; } if (pf.empty()) @@ -191,74 +213,70 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time) std::list<Tick> delays; calculatePrefetch(pkt, addresses, delays); - std::list<Addr>::iterator addr = addresses.begin(); - std::list<Tick>::iterator delay = delays.begin(); - while (addr != addresses.end()) - { - DPRINTF(HWPrefetch, "%s:Found a pf canidate, inserting into prefetch queue\n", cache->name()); - //temp calc this here... + std::list<Addr>::iterator addrIter = addresses.begin(); + std::list<Tick>::iterator delayIter = delays.begin(); + for (; addrIter != addresses.end(); ++addrIter, ++delayIter) { + Addr addr = *addrIter; + pfIdentified++; - //create a prefetch memreq - Request * prefetchReq = new Request(*addr, blkSize, 0); - PacketPtr prefetch; - prefetch = new Packet(prefetchReq, MemCmd::HardPFReq, -1); - prefetch->allocate(); - prefetch->req->setThreadContext(pkt->req->getCpuNum(), - pkt->req->getThreadNum()); - - prefetch->time = time + (*delay); //@todo ADD LATENCY HERE - //... initialize - - //Check if it is already in the cache - if (cacheCheckPush) { - if (cache->inCache(prefetch->getAddr())) { - addr++; - delay++; - continue; - } + + DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, " + "inserting into prefetch queue with delay %d time %d\n", + addr, *delayIter, time); + + // Check if it is already in the cache + if (cacheCheckPush && cache->inCache(addr)) { + DPRINTF(HWPrefetch, "Prefetch addr already in cache\n"); + continue; } - //Check if it is already in the miss_queue - if (cache->inMissQueue(prefetch->getAddr())) { - addr++; - delay++; + // Check if it is already in the miss_queue + if (cache->inMissQueue(addr)) { + DPRINTF(HWPrefetch, "Prefetch addr already in miss queue\n"); continue; } - //Check if it is already in the pf buffer - if (inPrefetch(prefetch->getAddr()) != pf.end()) { + // Check if it is already in the pf buffer + if (inPrefetch(addr) != pf.end()) { pfBufferHit++; - addr++; - delay++; + DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n"); continue; } - //We just remove the head if we are full - if (pf.size() == size) - { - DPRINTF(HWPrefetch, "%s:Inserting into prefetch queue, it was full removing oldest\n", cache->name()); + // create a prefetch memreq + Request *prefetchReq = new Request(*addrIter, blkSize, 0); + PacketPtr prefetch = + new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast); + prefetch->allocate(); + prefetch->req->setThreadContext(pkt->req->contextId(), + pkt->req->threadId()); + + prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE + + // We just remove the head if we are full + if (pf.size() == size) { pfRemovedFull++; + PacketPtr old_pkt = *pf.begin(); + DPRINTF(HWPrefetch, "Prefetch queue full, " + "removing oldest 0x%x\n", old_pkt->getAddr()); + delete old_pkt->req; + delete old_pkt; pf.pop_front(); } pf.push_back(prefetch); - - //Make sure to request the bus, with proper delay - cache->requestMemSideBus(BaseCache::Request_PF, prefetch->time); - - //Increment through the list - addr++; - delay++; } } + + return pf.empty() ? 0 : pf.front()->time; } std::list<PacketPtr>::iterator BasePrefetcher::inPrefetch(Addr address) { - //Guaranteed to only be one match, we always check before inserting + // Guaranteed to only be one match, we always check before inserting std::list<PacketPtr>::iterator iter; - for (iter=pf.begin(); iter != pf.end(); iter++) { + for (iter = pf.begin(); iter != pf.end(); iter++) { if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) { return iter; } @@ -266,4 +284,8 @@ BasePrefetcher::inPrefetch(Addr address) return pf.end(); } - +bool +BasePrefetcher::samePage(Addr a, Addr b) +{ + return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize); +} diff --git a/src/mem/cache/prefetch/base.hh b/src/mem/cache/prefetch/base.hh index 1515d8a93..fc027cb3b 100644 --- a/src/mem/cache/prefetch/base.hh +++ b/src/mem/cache/prefetch/base.hh @@ -73,30 +73,40 @@ class BasePrefetcher bool cacheCheckPush; /** Do we prefetch on only data reads, or on inst reads as well. */ - bool only_data; + bool onlyData; + + std::string _name; public: - Stats::Scalar<> pfIdentified; - Stats::Scalar<> pfMSHRHit; - Stats::Scalar<> pfCacheHit; - Stats::Scalar<> pfBufferHit; - Stats::Scalar<> pfRemovedFull; - Stats::Scalar<> pfRemovedMSHR; - Stats::Scalar<> pfIssued; - Stats::Scalar<> pfSpanPage; - Stats::Scalar<> pfSquashed; + Stats::Scalar pfIdentified; + Stats::Scalar pfMSHRHit; + Stats::Scalar pfCacheHit; + Stats::Scalar pfBufferHit; + Stats::Scalar pfRemovedFull; + Stats::Scalar pfRemovedMSHR; + Stats::Scalar pfIssued; + Stats::Scalar pfSpanPage; + Stats::Scalar pfSquashed; void regStats(const std::string &name); public: + BasePrefetcher(const BaseCacheParams *p); virtual ~BasePrefetcher() {} + const std::string name() const { return _name; } + void setCache(BaseCache *_cache); - void handleMiss(PacketPtr &pkt, Tick time); + /** + * Notify prefetcher of cache access (may be any access or just + * misses, depending on cache parameters.) + * @retval Time of next prefetch availability, or 0 if none. + */ + Tick notify(PacketPtr &pkt, Tick time); bool inCache(Addr addr); @@ -109,11 +119,21 @@ class BasePrefetcher return !pf.empty(); } + Tick nextPrefetchReadyTime() + { + return pf.empty() ? MaxTick : pf.front()->time; + } + virtual void calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses, std::list<Tick> &delays) = 0; std::list<PacketPtr>::iterator inPrefetch(Addr address); + + /** + * Utility function: are addresses a and b on the same VM page? + */ + bool samePage(Addr a, Addr b); }; diff --git a/src/mem/cache/prefetch/ghb.cc b/src/mem/cache/prefetch/ghb.cc index f5b88e1a6..f8f7de1db 100644 --- a/src/mem/cache/prefetch/ghb.cc +++ b/src/mem/cache/prefetch/ghb.cc @@ -34,39 +34,37 @@ * GHB Prefetcher implementation. */ +#include "base/trace.hh" #include "mem/cache/prefetch/ghb.hh" -#include "arch/isa_traits.hh" void GHBPrefetcher::calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses, std::list<Tick> &delays) { - Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1); - int cpuID = pkt->req->getCpuNum(); - if (!useCPUId) cpuID = 0; + if (useContextId && !pkt->req->hasContextId()) { + DPRINTF(HWPrefetch, "ignoring request with no context ID"); + return; + } + Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); + int ctx_id = useContextId ? pkt->req->contextId() : 0; + assert(ctx_id < Max_Contexts); - int new_stride = blkAddr - last_miss_addr[cpuID]; - int old_stride = last_miss_addr[cpuID] - - second_last_miss_addr[cpuID]; + int new_stride = blk_addr - lastMissAddr[ctx_id]; + int old_stride = lastMissAddr[ctx_id] - secondLastMissAddr[ctx_id]; - second_last_miss_addr[cpuID] = last_miss_addr[cpuID]; - last_miss_addr[cpuID] = blkAddr; + secondLastMissAddr[ctx_id] = lastMissAddr[ctx_id]; + lastMissAddr[ctx_id] = blk_addr; if (new_stride == old_stride) { - for (int d=1; d <= degree; d++) { - Addr newAddr = blkAddr + d * new_stride; - if (this->pageStop && - (blkAddr & ~(TheISA::VMPageSize - 1)) != - (newAddr & ~(TheISA::VMPageSize - 1))) - { - //Spanned the page, so now stop - this->pfSpanPage += degree - d + 1; + for (int d = 1; d <= degree; d++) { + Addr new_addr = blk_addr + d * new_stride; + if (pageStop && !samePage(blk_addr, new_addr)) { + // Spanned the page, so now stop + pfSpanPage += degree - d + 1; return; - } - else - { - addresses.push_back(newAddr); + } else { + addresses.push_back(new_addr); delays.push_back(latency); } } diff --git a/src/mem/cache/prefetch/ghb.hh b/src/mem/cache/prefetch/ghb.hh index 4fb692016..c85221a39 100644 --- a/src/mem/cache/prefetch/ghb.hh +++ b/src/mem/cache/prefetch/ghb.hh @@ -42,18 +42,20 @@ class GHBPrefetcher : public BasePrefetcher { protected: - Addr second_last_miss_addr[64/*MAX_CPUS*/]; - Addr last_miss_addr[64/*MAX_CPUS*/]; + static const int Max_Contexts = 64; + + Addr secondLastMissAddr[Max_Contexts]; + Addr lastMissAddr[Max_Contexts]; Tick latency; int degree; - bool useCPUId; + bool useContextId; public: GHBPrefetcher(const BaseCacheParams *p) : BasePrefetcher(p), latency(p->prefetch_latency), - degree(p->prefetch_degree), useCPUId(p->prefetch_use_cpu_id) + degree(p->prefetch_degree), useContextId(p->prefetch_use_cpu_id) { } diff --git a/src/mem/cache/prefetch/stride.cc b/src/mem/cache/prefetch/stride.cc index b116b66c7..8af4e615e 100644 --- a/src/mem/cache/prefetch/stride.cc +++ b/src/mem/cache/prefetch/stride.cc @@ -34,59 +34,97 @@ * Stride Prefetcher template instantiations. */ +#include "base/trace.hh" #include "mem/cache/prefetch/stride.hh" void StridePrefetcher::calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses, std::list<Tick> &delays) { -// Addr blkAddr = pkt->paddr & ~(Addr)(this->blkSize-1); - int cpuID = pkt->req->getCpuNum(); - if (!useCPUId) cpuID = 0; - - /* Scan Table for IAddr Match */ -/* std::list<strideEntry*>::iterator iter; - for (iter=table[cpuID].begin(); - iter !=table[cpuID].end(); - iter++) { - if ((*iter)->IAddr == pkt->pc) break; - } - - if (iter != table[cpuID].end()) { - //Hit in table - - int newStride = blkAddr - (*iter)->MAddr; - if (newStride == (*iter)->stride) { - (*iter)->confidence++; - } - else { - (*iter)->stride = newStride; - (*iter)->confidence--; - } - - (*iter)->MAddr = blkAddr; - - for (int d=1; d <= degree; d++) { - Addr newAddr = blkAddr + d * newStride; - if (this->pageStop && - (blkAddr & ~(TheISA::VMPageSize - 1)) != - (newAddr & ~(TheISA::VMPageSize - 1))) - { - //Spanned the page, so now stop - this->pfSpanPage += degree - d + 1; - return; - } - else - { - addresses.push_back(newAddr); - delays.push_back(latency); - } - } - } - else { - //Miss in table - //Find lowest confidence and replace - - } -*/ + if (!pkt->req->hasPC()) { + DPRINTF(HWPrefetch, "ignoring request with no PC"); + return; + } + + if (useContextId && !pkt->req->hasContextId()) { + DPRINTF(HWPrefetch, "ignoring request with no context ID"); + return; + } + + Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1); + int ctx_id = useContextId ? pkt->req->contextId() : 0; + Addr pc = pkt->req->getPC(); + assert(ctx_id < Max_Contexts); + std::list<StrideEntry*> &tab = table[ctx_id]; + + /* Scan Table for instAddr Match */ + std::list<StrideEntry*>::iterator iter; + for (iter = tab.begin(); iter != tab.end(); iter++) { + if ((*iter)->instAddr == pc) + break; + } + + if (iter != tab.end()) { + // Hit in table + + int new_stride = blk_addr - (*iter)->missAddr; + bool stride_match = (new_stride == (*iter)->stride); + + if (stride_match && new_stride != 0) { + if ((*iter)->confidence < Max_Conf) + (*iter)->confidence++; + } else { + (*iter)->stride = new_stride; + if ((*iter)->confidence > Min_Conf) + (*iter)->confidence = 0; + } + + DPRINTF(HWPrefetch, "hit: PC %x blk_addr %x stride %d (%s), conf %d\n", + pc, blk_addr, new_stride, stride_match ? "match" : "change", + (*iter)->confidence); + + (*iter)->missAddr = blk_addr; + + if ((*iter)->confidence <= 0) + return; + + for (int d = 1; d <= degree; d++) { + Addr new_addr = blk_addr + d * new_stride; + if (pageStop && !samePage(blk_addr, new_addr)) { + // Spanned the page, so now stop + pfSpanPage += degree - d + 1; + return; + } else { + DPRINTF(HWPrefetch, " queuing prefetch to %x @ %d\n", + new_addr, latency); + addresses.push_back(new_addr); + delays.push_back(latency); + } + } + } else { + // Miss in table + // Find lowest confidence and replace + + DPRINTF(HWPrefetch, "miss: PC %x blk_addr %x\n", pc, blk_addr); + + if (tab.size() >= 256) { //set default table size is 256 + std::list<StrideEntry*>::iterator min_pos = tab.begin(); + int min_conf = (*min_pos)->confidence; + for (iter = min_pos, ++iter; iter != tab.end(); ++iter) { + if ((*iter)->confidence < min_conf){ + min_pos = iter; + min_conf = (*iter)->confidence; + } + } + DPRINTF(HWPrefetch, " replacing PC %x\n", (*min_pos)->instAddr); + tab.erase(min_pos); + } + + StrideEntry *new_entry = new StrideEntry; + new_entry->instAddr = pc; + new_entry->missAddr = blk_addr; + new_entry->stride = 0; + new_entry->confidence = 0; + tab.push_back(new_entry); + } } diff --git a/src/mem/cache/prefetch/stride.hh b/src/mem/cache/prefetch/stride.hh index f6bdbc424..6ccd32b91 100644 --- a/src/mem/cache/prefetch/stride.hh +++ b/src/mem/cache/prefetch/stride.hh @@ -36,41 +36,41 @@ #ifndef __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__ #define __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__ +#include <limits.h> #include "mem/cache/prefetch/base.hh" class StridePrefetcher : public BasePrefetcher { protected: - class strideEntry + static const int Max_Contexts = 64; + + // These constants need to be changed with the type of the + // 'confidence' field below. + static const int Max_Conf = INT_MAX; + static const int Min_Conf = INT_MIN; + + class StrideEntry { public: - Addr IAddr; - Addr MAddr; + Addr instAddr; + Addr missAddr; int stride; - int64_t confidence; - -/* bool operator < (strideEntry a,strideEntry b) - { - if (a.confidence == b.confidence) { - return true; //?????? - } - else return a.confidence < b.confidence; - }*/ + int confidence; }; - Addr* lastMissAddr[64/*MAX_CPUS*/]; - std::list<strideEntry*> table[64/*MAX_CPUS*/]; + Addr *lastMissAddr[Max_Contexts]; + + std::list<StrideEntry*> table[Max_Contexts]; Tick latency; int degree; - bool useCPUId; - + bool useContextId; public: StridePrefetcher(const BaseCacheParams *p) : BasePrefetcher(p), latency(p->prefetch_latency), - degree(p->prefetch_degree), useCPUId(p->prefetch_use_cpu_id) + degree(p->prefetch_degree), useContextId(p->prefetch_use_cpu_id) { } diff --git a/src/mem/cache/prefetch/tagged.cc b/src/mem/cache/prefetch/tagged.cc index 6afe1c6c2..a6c2403ba 100644 --- a/src/mem/cache/prefetch/tagged.cc +++ b/src/mem/cache/prefetch/tagged.cc @@ -47,20 +47,15 @@ TaggedPrefetcher:: calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses, std::list<Tick> &delays) { - Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1); + Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1); - for (int d=1; d <= degree; d++) { - Addr newAddr = blkAddr + d*(this->blkSize); - if (this->pageStop && - (blkAddr & ~(TheISA::VMPageSize - 1)) != - (newAddr & ~(TheISA::VMPageSize - 1))) - { - //Spanned the page, so now stop - this->pfSpanPage += degree - d + 1; + for (int d = 1; d <= degree; d++) { + Addr newAddr = blkAddr + d*(blkSize); + if (pageStop && !samePage(blkAddr, newAddr)) { + // Spanned the page, so now stop + pfSpanPage += degree - d + 1; return; - } - else - { + } else { addresses.push_back(newAddr); delays.push_back(latency); } diff --git a/src/mem/cache/tags/SConscript b/src/mem/cache/tags/SConscript index 9153d97e7..7255e0b7e 100644 --- a/src/mem/cache/tags/SConscript +++ b/src/mem/cache/tags/SConscript @@ -34,13 +34,9 @@ Source('base.cc') Source('fa_lru.cc') Source('iic.cc') Source('lru.cc') -Source('split.cc') -Source('split_lifo.cc') -Source('split_lru.cc') SimObject('iic_repl/Repl.py') Source('iic_repl/gen.cc') TraceFlag('IIC') TraceFlag('IICMore') -TraceFlag('Split') diff --git a/src/mem/cache/tags/base.hh b/src/mem/cache/tags/base.hh index b7b0c7ef0..46c7186b1 100644 --- a/src/mem/cache/tags/base.hh +++ b/src/mem/cache/tags/base.hh @@ -70,19 +70,19 @@ class BaseTags */ /** Number of replacements of valid blocks per thread. */ - Stats::Vector<> replacements; + Stats::Vector replacements; /** Per cycle average of the number of tags that hold valid data. */ - Stats::Average<> tagsInUse; + Stats::Average tagsInUse; /** The total number of references to a block before it is replaced. */ - Stats::Scalar<> totalRefs; + Stats::Scalar totalRefs; /** * The number of reference counts sampled. This is different from * replacements because we sample all the valid blocks when the simulator * exits. */ - Stats::Scalar<> sampledRefs; + Stats::Scalar sampledRefs; /** * Average number of references to a block before is was replaced. @@ -91,7 +91,7 @@ class BaseTags Stats::Formula avgRefs; /** The cycle that the warmup percentage was hit. */ - Stats::Scalar<> warmupCycle; + Stats::Scalar warmupCycle; /** * @} */ diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc index 607e89a75..f92d4cb37 100644 --- a/src/mem/cache/tags/fa_lru.cc +++ b/src/mem/cache/tags/fa_lru.cc @@ -144,14 +144,6 @@ FALRU::hashLookup(Addr addr) const return NULL; } -bool -FALRU::probe(Addr addr) const -{ - Addr blkAddr = blkAlign(addr); - FALRUBlk* blk = hashLookup(blkAddr); - return blk && blk->tag == blkAddr && blk->isValid(); -} - void FALRU::invalidateBlk(FALRU::BlkType *blk) { @@ -163,7 +155,7 @@ FALRU::invalidateBlk(FALRU::BlkType *blk) } FALRUBlk* -FALRU::findBlock(Addr addr, int &lat, int *inCache) +FALRU::accessBlock(Addr addr, int &lat, int *inCache) { accesses++; int tmp_in_cache = 0; @@ -215,7 +207,7 @@ FALRU::findBlock(Addr addr) const } FALRUBlk* -FALRU::findReplacement(Addr addr, PacketList &writebacks) +FALRU::findVictim(Addr addr, PacketList &writebacks) { FALRUBlk * blk = tail; assert(blk->inCache == 0); @@ -237,6 +229,11 @@ FALRU::findReplacement(Addr addr, PacketList &writebacks) } void +FALRU::insertBlock(Addr addr, FALRU::BlkType *blk) +{ +} + +void FALRU::moveToHead(FALRUBlk *blk) { int updateMask = blk->inCache ^ cacheMask; diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh index cabcf18b4..4eab10c49 100644 --- a/src/mem/cache/tags/fa_lru.hh +++ b/src/mem/cache/tags/fa_lru.hh @@ -139,11 +139,11 @@ class FALRU : public BaseTags */ /** Hits in each cache size >= 128K. */ - Stats::Vector<> hits; + Stats::Vector hits; /** Misses in each cache size >= 128K. */ - Stats::Vector<> misses; + Stats::Vector misses; /** Total number of accesses. */ - Stats::Scalar<> accesses; + Stats::Scalar accesses; /** * @} @@ -165,29 +165,23 @@ public: void regStats(const std::string &name); /** - * Return true if the address is found in the cache. - * @param asid The address space ID. - * @param addr The address to look for. - * @return True if the address is in the cache. - */ - bool probe(Addr addr) const; - - /** * Invalidate a cache block. * @param blk The block to invalidate. */ void invalidateBlk(BlkType *blk); /** - * Find the block in the cache and update the replacement data. Returns - * the access latency and the in cache flags as a side effect + * Access block and update replacement data. May not succeed, in which case + * NULL pointer is returned. This has all the implications of a cache + * access and should only be used as such. + * Returns the access latency and inCache flags as a side effect. * @param addr The address to look for. * @param asid The address space ID. * @param lat The latency of the access. * @param inCache The FALRUBlk::inCache flags. * @return Pointer to the cache block. */ - FALRUBlk* findBlock(Addr addr, int &lat, int *inCache = 0); + FALRUBlk* accessBlock(Addr addr, int &lat, int *inCache = 0); /** * Find the block in the cache, do not update the replacement data. @@ -203,7 +197,9 @@ public: * @param writebacks List for any writebacks to be performed. * @return The block to place the replacement in. */ - FALRUBlk* findReplacement(Addr addr, PacketList & writebacks); + FALRUBlk* findVictim(Addr addr, PacketList & writebacks); + + void insertBlock(Addr addr, BlkType *blk); /** * Return the hit latency of this cache. @@ -283,31 +279,6 @@ public: { return (tag); } - - /** - * Read the data out of the internal storage of a cache block. FALRU - * currently doesn't support data storage. - * @param blk The cache block to read. - * @param data The buffer to read the data into. - * @return The data from the cache block. - */ - void readData(FALRUBlk *blk, uint8_t *data) - { - } - - /** - * Write data into the internal storage of a cache block. FALRU - * currently doesn't support data storage. - * @param blk The cache block to be written. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(FALRUBlk *blk, uint8_t *data, int size, - PacketList &writebacks) - { - } }; #endif diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc index 2825599f6..7bc2543c5 100644 --- a/src/mem/cache/tags/iic.cc +++ b/src/mem/cache/tags/iic.cc @@ -219,15 +219,9 @@ IIC::regStats(const string &name) ; } -// probe cache for presence of given block. -bool -IIC::probe(Addr addr) const -{ - return (findBlock(addr) != NULL); -} IICTag* -IIC::findBlock(Addr addr, int &lat) +IIC::accessBlock(Addr addr, int &lat) { Addr tag = extractTag(addr); unsigned set = hash(addr); @@ -303,7 +297,7 @@ IIC::findBlock(Addr addr) const IICTag* -IIC::findReplacement(Addr addr, PacketList &writebacks) +IIC::findVictim(Addr addr, PacketList &writebacks) { DPRINTF(IIC, "Finding Replacement for %x\n", addr); unsigned set = hash(addr); @@ -346,6 +340,11 @@ IIC::findReplacement(Addr addr, PacketList &writebacks) } void +IIC::insertBlock(Addr addr, BlkType* blk) +{ +} + +void IIC::freeReplacementBlock(PacketList & writebacks) { IICTag *tag_ptr; @@ -365,7 +364,7 @@ IIC::freeReplacementBlock(PacketList & writebacks) tag_ptr->refCount = 0; if (tag_ptr->isDirty()) { -/* PacketPtr writeback = +/* PacketPtr writeback = buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0), tag_ptr->req->asid, tag_ptr->xc, blkSize, tag_ptr->data, @@ -635,66 +634,6 @@ IIC::invalidateBlk(IIC::BlkType *tag_ptr) } void -IIC::readData(IICTag *blk, uint8_t *data) -{ - assert(blk->size <= trivialSize || blk->numData > 0); - int data_size = blk->size; - if (data_size > trivialSize) { - for (int i = 0; i < blk->numData; ++i){ - memcpy(data+i*subSize, - &(dataBlks[blk->data_ptr[i]][0]), - (data_size>subSize)?subSize:data_size); - data_size -= subSize; - } - } else { - memcpy(data,blk->trivialData,data_size); - } -} - -void -IIC::writeData(IICTag *blk, uint8_t *write_data, int size, - PacketList & writebacks) -{ - DPRINTF(IIC, "Writing %d bytes to %x\n", size, - blk->tag<<tagShift); - // Find the number of subblocks needed, (round up) - int num_subs = (size + (subSize -1))/subSize; - if (size <= trivialSize) { - num_subs = 0; - } - assert(num_subs <= numSub); - if (num_subs > blk->numData) { - // need to allocate more data blocks - for (int i = blk->numData; i < num_subs; ++i){ - blk->data_ptr[i] = getFreeDataBlock(writebacks); - dataReferenceCount[blk->data_ptr[i]] += 1; - } - } else if (num_subs < blk->numData){ - // can free data blocks - for (int i=num_subs; i < blk->numData; ++i){ - // decrement reference count and compare to zero - if (--dataReferenceCount[blk->data_ptr[i]] == 0) { - freeDataBlock(blk->data_ptr[i]); - } - } - } - - blk->numData = num_subs; - blk->size = size; - assert(size <= trivialSize || blk->numData > 0); - if (size > trivialSize){ - for (int i = 0; i < blk->numData; ++i){ - memcpy(&dataBlks[blk->data_ptr[i]][0], write_data + i*subSize, - (size>subSize)?subSize:size); - size -= subSize; - } - } else { - memcpy(blk->trivialData,write_data,size); - } -} - - -void IIC::cleanupRefs() { for (int i = 0; i < numTags; ++i) { diff --git a/src/mem/cache/tags/iic.hh b/src/mem/cache/tags/iic.hh index c9d080683..45c8ee801 100644 --- a/src/mem/cache/tags/iic.hh +++ b/src/mem/cache/tags/iic.hh @@ -248,20 +248,20 @@ class IIC : public BaseTags */ /** Hash hit depth of cache hits. */ - Stats::Distribution<> hitHashDepth; + Stats::Distribution hitHashDepth; /** Hash depth for cache misses. */ - Stats::Distribution<> missHashDepth; + Stats::Distribution missHashDepth; /** Count of accesses to each hash set. */ - Stats::Distribution<> setAccess; + Stats::Distribution setAccess; /** The total hash depth for every miss. */ - Stats::Scalar<> missDepthTotal; + Stats::Scalar missDepthTotal; /** The total hash depth for all hits. */ - Stats::Scalar<> hitDepthTotal; + Stats::Scalar hitDepthTotal; /** The number of hash misses. */ - Stats::Scalar<> hashMiss; + Stats::Scalar hashMiss; /** The number of hash hits. */ - Stats::Scalar<> hashHit; + Stats::Scalar hashHit; /** @} */ public: @@ -385,14 +385,6 @@ class IIC : public BaseTags } /** - * Check for the address in the tagstore. - * @param asid The address space ID. - * @param addr The address to find. - * @return true if it is found. - */ - bool probe(Addr addr) const; - - /** * Swap the position of two tags. * @param index1 The first tag location. * @param index2 The second tag location. @@ -418,14 +410,16 @@ class IIC : public BaseTags void invalidateBlk(BlkType *blk); /** - * Find the block and update the replacement data. This call also returns - * the access latency as a side effect. + * Access block and update replacement data. May not succeed, in which case + * NULL pointer is returned. This has all the implications of a cache + * access and should only be used as such. + * Returns the access latency and inCache flags as a side effect. * @param addr The address to find. * @param asid The address space ID. * @param lat The access latency. * @return A pointer to the block found, if any. */ - IICTag* findBlock(Addr addr, int &lat); + IICTag* accessBlock(Addr addr, int &lat); /** * Find the block, do not update the replacement data. @@ -441,31 +435,15 @@ class IIC : public BaseTags * @param writebacks List for any writebacks to be performed. * @return The block to place the replacement in. */ - IICTag* findReplacement(Addr addr, PacketList &writebacks); + IICTag* findVictim(Addr addr, PacketList &writebacks); - /** - * Read the data from the internal storage of the given cache block. - * @param blk The block to read the data from. - * @param data The buffer to read the data into. - * @return The cache block's data. - */ - void readData(IICTag *blk, uint8_t *data); - - /** - * Write the data into the internal storage of the given cache block. - * @param blk The block to write to. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(IICTag *blk, uint8_t *data, int size, - PacketList & writebacks); + void insertBlock(Addr addr, BlkType *blk); /** * Called at end of simulation to complete average block reference stats. */ virtual void cleanupRefs(); + private: /** * Return the hash of the address. diff --git a/src/mem/cache/tags/iic_repl/gen.hh b/src/mem/cache/tags/iic_repl/gen.hh index 22436b384..fe105d95a 100644 --- a/src/mem/cache/tags/iic_repl/gen.hh +++ b/src/mem/cache/tags/iic_repl/gen.hh @@ -162,11 +162,11 @@ class GenRepl : public Repl * @{ */ /** The number of replacements from each pool. */ - Stats::Distribution<> repl_pool; + Stats::Distribution repl_pool; /** The number of advances out of each pool. */ - Stats::Distribution<> advance_pool; + Stats::Distribution advance_pool; /** The number of demotions from each pool. */ - Stats::Distribution<> demote_pool; + Stats::Distribution demote_pool; /** * @} */ diff --git a/src/mem/cache/tags/lru.cc b/src/mem/cache/tags/lru.cc index 7f352e9c4..ff353ff6a 100644 --- a/src/mem/cache/tags/lru.cc +++ b/src/mem/cache/tags/lru.cc @@ -113,7 +113,7 @@ LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) : // allocate data storage in one big chunk dataBlks = new uint8_t[numSets*assoc*blkSize]; - blkIndex = 0; // index into blks array + blkIndex = 0; // index into blks array for (i = 0; i < numSets; ++i) { sets[i].assoc = assoc; @@ -150,21 +150,8 @@ LRU::~LRU() delete [] sets; } -// probe cache for presence of given block. -bool -LRU::probe(Addr addr) const -{ - // return(findBlock(Read, addr, asid) != 0); - Addr tag = extractTag(addr); - unsigned myset = extractSet(addr); - - LRUBlk *blk = sets[myset].findBlk(tag); - - return (blk != NULL); // true if in cache -} - LRUBlk* -LRU::findBlock(Addr addr, int &lat) +LRU::accessBlock(Addr addr, int &lat) { Addr tag = extractTag(addr); unsigned set = extractSet(addr); @@ -196,12 +183,11 @@ LRU::findBlock(Addr addr) const } LRUBlk* -LRU::findReplacement(Addr addr, PacketList &writebacks) +LRU::findVictim(Addr addr, PacketList &writebacks) { unsigned set = extractSet(addr); // grab a replacement candidate LRUBlk *blk = sets[set].blks[assoc-1]; - sets[set].moveToHead(blk); if (blk->isValid()) { replacements[0]++; totalRefs += blk->refCount; @@ -210,7 +196,14 @@ LRU::findReplacement(Addr addr, PacketList &writebacks) DPRINTF(CacheRepl, "set %x: selecting blk %x for replacement\n", set, regenerateBlkAddr(blk->tag, set)); - } else if (!blk->isTouched) { + } + return blk; +} + +void +LRU::insertBlock(Addr addr, LRU::BlkType *blk) +{ + if (!blk->isTouched) { tagsInUse++; blk->isTouched = true; if (!warmedUp && tagsInUse.value() >= warmupBound) { @@ -219,7 +212,11 @@ LRU::findReplacement(Addr addr, PacketList &writebacks) } } - return blk; + // Set tag for new block. Caller is responsible for setting status. + blk->tag = extractTag(addr); + + unsigned set = extractSet(addr); + sets[set].moveToHead(blk); } void diff --git a/src/mem/cache/tags/lru.hh b/src/mem/cache/tags/lru.hh index ea5606cde..7b6e95e84 100644 --- a/src/mem/cache/tags/lru.hh +++ b/src/mem/cache/tags/lru.hh @@ -127,7 +127,7 @@ public: * @param _assoc The associativity of the cache. * @param _hit_latency The latency in cycles for a hit. */ - LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency); + LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency); /** * Destructor @@ -154,31 +154,25 @@ public: } /** - * Search for the address in the cache. - * @param asid The address space ID. - * @param addr The address to find. - * @return True if the address is in the cache. - */ - bool probe(Addr addr) const; - - /** * Invalidate the given block. * @param blk The block to invalidate. */ void invalidateBlk(BlkType *blk); /** - * Finds the given address in the cache and update replacement data. - * Returns the access latency as a side effect. + * Access block and update replacement data. May not succeed, in which case + * NULL pointer is returned. This has all the implications of a cache + * access and should only be used as such. Returns the access latency as a side effect. * @param addr The address to find. * @param asid The address space ID. * @param lat The access latency. * @return Pointer to the cache block if found. */ - LRUBlk* findBlock(Addr addr, int &lat); + LRUBlk* accessBlock(Addr addr, int &lat); /** * Finds the given address in the cache, do not update replacement data. + * i.e. This is a no-side-effect find of a block. * @param addr The address to find. * @param asid The address space ID. * @return Pointer to the cache block if found. @@ -186,12 +180,20 @@ public: LRUBlk* findBlock(Addr addr) const; /** - * Find a replacement block for the address provided. - * @param pkt The request to a find a replacement candidate for. + * Find a block to evict for the address provided. + * @param addr The addr to a find a replacement candidate for. * @param writebacks List for any writebacks to be performed. - * @return The block to place the replacement in. + * @return The candidate block. */ - LRUBlk* findReplacement(Addr addr, PacketList &writebacks); + LRUBlk* findVictim(Addr addr, PacketList &writebacks); + + /** + * Insert the new block into the cache. For LRU this means inserting into + * the MRU position of the set. + * @param addr The address to update. + * @param blk The block to update. + */ + void insertBlock(Addr addr, BlkType *blk); /** * Generate the tag from the given address. @@ -254,33 +256,6 @@ public: } /** - * Read the data out of the internal storage of the given cache block. - * @param blk The cache block to read. - * @param data The buffer to read the data into. - * @return The cache block's data. - */ - void readData(LRUBlk *blk, uint8_t *data) - { - std::memcpy(data, blk->data, blk->size); - } - - /** - * Write data into the internal storage of the given cache block. Since in - * LRU does not store data differently this just needs to update the size. - * @param blk The cache block to write. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(LRUBlk *blk, uint8_t *data, int size, - PacketList & writebacks) - { - assert(size <= blkSize); - blk->size = size; - } - - /** * Called at end of simulation to complete average block reference stats. */ virtual void cleanupRefs(); diff --git a/src/mem/cache/tags/split.cc b/src/mem/cache/tags/split.cc deleted file mode 100644 index 0df85cc92..000000000 --- a/src/mem/cache/tags/split.cc +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Definitions of split cache tag store. - */ - -#include <string> -#include <iostream> -#include <fstream> - -#include "base/cprintf.hh" -#include "base/intmath.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "mem/cache/base.hh" -#include "mem/cache/tags/split.hh" -#include "mem/cache/tags/split_lifo.hh" -#include "mem/cache/tags/split_lru.hh" - - -using namespace std; -using namespace TheISA; - -// create and initialize a partitioned cache structure -Split::Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc, - bool _lifo, bool _two_queue, int _hit_latency) : - numSets(_numSets), blkSize(_blkSize), lifo(_lifo), hitLatency(_hit_latency) -{ - DPRINTF(Split, "new split cache!!\n"); - - DPRINTF(Split, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n", - numSets, blkSize, LRU1_assoc, hitLatency); - - lru = new SplitLRU(_numSets, _blkSize, LRU1_assoc, _hit_latency, 1); - - if (total_ways - LRU1_assoc == 0) { - lifo_net = NULL; - lru_net = NULL; - } else { - if (lifo) { - DPRINTF(Split, "Other partition is a LIFO with size %d in bytes. it gets %d ways\n", - (total_ways - LRU1_assoc)*_numSets*_blkSize, (total_ways - LRU1_assoc)); - lifo_net = new SplitLIFO(_blkSize, (total_ways - LRU1_assoc)*_numSets*_blkSize, - (total_ways - LRU1_assoc), _hit_latency, _two_queue, 2); - lru_net = NULL; - } - else { - DPRINTF(Split, "other LRU gets %d ways\n", total_ways - LRU1_assoc); - lru_net = new SplitLRU(_numSets, _blkSize, total_ways - LRU1_assoc, _hit_latency, 2); - lifo_net = NULL; - } - } - - blkMask = blkSize - 1; - - if (!isPowerOf2(total_ways)) - warn("total cache ways/columns %d should be power of 2", - total_ways); - - warmedUp = false; - /** @todo Make warmup percentage a parameter. */ - warmupBound = numSets * total_ways; - -} - -Split::~Split() -{ - delete lru; - if (lifo) - delete lifo_net; - else - delete lru_net; -} - -void -Split::regStats(const string &name) -{ - using namespace Stats; - - BaseTags::regStats(name); - - usedEvictDist.init(0,3000,40); - unusedEvictDist.init(0,3000,40); - useByCPUCycleDist.init(0,35,1); - - nic_repl - .name(name + ".nic_repl") - .desc("number of replacements in the nic partition") - .precision(0) - ; - - cpu_repl - .name(name + ".cpu_repl") - .desc("number of replacements in the cpu partition") - .precision(0) - ; - - lru->regStats(name + ".lru"); - - if (lifo && lifo_net) { - lifo_net->regStats(name + ".lifo_net"); - } else if (lru_net) { - lru_net->regStats(name + ".lru_net"); - } - - nicUsedWhenEvicted - .name(name + ".nicUsedWhenEvicted") - .desc("number of NIC blks that were used before evicted") - ; - - nicUsedTotLatency - .name(name + ".nicUsedTotLatency") - .desc("total cycles before eviction of used NIC blks") - ; - - nicUsedTotEvicted - .name(name + ".nicUsedTotEvicted") - .desc("total number of used NIC blks evicted") - ; - - nicUsedAvgLatency - .name(name + ".nicUsedAvgLatency") - .desc("avg number of cycles a used NIC blk is in cache") - .precision(0) - ; - nicUsedAvgLatency = nicUsedTotLatency / nicUsedTotEvicted; - - usedEvictDist - .name(name + ".usedEvictDist") - .desc("distribution of used NIC blk eviction times") - .flags(pdf | cdf) - ; - - nicUnusedWhenEvicted - .name(name + ".nicUnusedWhenEvicted") - .desc("number of NIC blks that were unused when evicted") - ; - - nicUnusedTotLatency - .name(name + ".nicUnusedTotLatency") - .desc("total cycles before eviction of unused NIC blks") - ; - - nicUnusedTotEvicted - .name(name + ".nicUnusedTotEvicted") - .desc("total number of unused NIC blks evicted") - ; - - nicUnusedAvgLatency - .name(name + ".nicUnusedAvgLatency") - .desc("avg number of cycles an unused NIC blk is in cache") - .precision(0) - ; - nicUnusedAvgLatency = nicUnusedTotLatency / nicUnusedTotEvicted; - - unusedEvictDist - .name(name + ".unusedEvictDist") - .desc("distribution of unused NIC blk eviction times") - .flags(pdf | cdf) - ; - - nicUseByCPUCycleTotal - .name(name + ".nicUseByCPUCycleTotal") - .desc("total latency of NIC blks til usage time") - ; - - nicBlksUsedByCPU - .name(name + ".nicBlksUsedByCPU") - .desc("total number of NIC blks used") - ; - - nicAvgUsageByCPULatency - .name(name + ".nicAvgUsageByCPULatency") - .desc("average number of cycles before a NIC blk that is used gets used") - .precision(0) - ; - nicAvgUsageByCPULatency = nicUseByCPUCycleTotal / nicBlksUsedByCPU; - - useByCPUCycleDist - .name(name + ".useByCPUCycleDist") - .desc("the distribution of cycle time in cache before NIC blk is used") - .flags(pdf | cdf) - ; - - cpuUsedBlks - .name(name + ".cpuUsedBlks") - .desc("number of cpu blks that were used before evicted") - ; - - cpuUnusedBlks - .name(name + ".cpuUnusedBlks") - .desc("number of cpu blks that were unused before evicted") - ; - - nicAvgLatency - .name(name + ".nicAvgLatency") - .desc("avg number of cycles a NIC blk is in cache before evicted") - .precision(0) - ; - nicAvgLatency = (nicUnusedTotLatency + nicUsedTotLatency) / - (nicUnusedTotEvicted + nicUsedTotEvicted); - - NR_CP_hits - .name(name + ".NR_CP_hits") - .desc("NIC requests hitting in CPU Partition") - ; - - NR_NP_hits - .name(name + ".NR_NP_hits") - .desc("NIC requests hitting in NIC Partition") - ; - - CR_CP_hits - .name(name + ".CR_CP_hits") - .desc("CPU requests hitting in CPU partition") - ; - - CR_NP_hits - .name(name + ".CR_NP_hits") - .desc("CPU requests hitting in NIC partition") - ; - -} - -// probe cache for presence of given block. -bool -Split::probe(Addr addr) const -{ - bool success = lru->probe(addr); - if (!success) { - if (lifo && lifo_net) - success = lifo_net->probe(addr); - else if (lru_net) - success = lru_net->probe(addr); - } - - return success; -} - - -SplitBlk* -Split::findBlock(Addr addr, int &lat) -{ - SplitBlk *blk = lru->findBlock(addr, lat); - if (!blk) { - if (lifo && lifo_net) { - blk = lifo_net->findBlock(addr, lat); - } else if (lru_net) { - blk = lru_net->findBlock(addr, lat); - } - } - - return blk; -} - -SplitBlk* -Split::findBlock(Addr addr) const -{ - SplitBlk *blk = lru->findBlock(addr); - if (!blk) { - if (lifo && lifo_net) { - blk = lifo_net->findBlock(addr); - } else if (lru_net) { - blk = lru_net->findBlock(addr); - } - } - - return blk; -} - -SplitBlk* -Split::findReplacement(Addr addr, PacketList &writebacks) -{ - SplitBlk *blk = NULL; - - assert(0); -#if 0 - if (pkt->nic_pkt()) { - DPRINTF(Split, "finding a replacement for nic_req\n"); - nic_repl++; - if (lifo && lifo_net) - blk = lifo_net->findReplacement(addr, writebacks); - else if (lru_net) - blk = lru_net->findReplacement(addr, writebacks); - // in this case, this is an LRU only cache, it's non partitioned - else - blk = lru->findReplacement(addr, writebacks); - } else { - DPRINTF(Split, "finding replacement for cpu_req\n"); - blk = lru->findReplacement(addr, writebacks); - cpu_repl++; - } - - Tick latency = curTick - blk->ts; - if (blk->isNIC) { - if (blk->isUsed) { - nicUsedWhenEvicted++; - usedEvictDist.sample(latency); - nicUsedTotLatency += latency; - nicUsedTotEvicted++; - } else { - nicUnusedWhenEvicted++; - unusedEvictDist.sample(latency); - nicUnusedTotLatency += latency; - nicUnusedTotEvicted++; - } - } else { - if (blk->isUsed) { - cpuUsedBlks++; - } else { - cpuUnusedBlks++; - } - } - - // blk attributes for the new blk coming IN - blk->ts = curTick; - blk->isNIC = (pkt->nic_pkt()) ? true : false; -#endif - - return blk; -} - -void -Split::invalidateBlk(Split::BlkType *blk) -{ - if (!blk) { - fatal("FIXME!\n"); -#if 0 - if (lifo && lifo_net) - blk = lifo_net->findBlock(addr); - else if (lru_net) - blk = lru_net->findBlock(addr); -#endif - - if (!blk) - return; - } - - blk->status = 0; - blk->isTouched = false; - tagsInUse--; -} - -void -Split::cleanupRefs() -{ - lru->cleanupRefs(); - if (lifo && lifo_net) - lifo_net->cleanupRefs(); - else if (lru_net) - lru_net->cleanupRefs(); - - ofstream memPrint(simout.resolve("memory_footprint.txt").c_str(), - ios::trunc); - - // this shouldn't be here but it happens at the end, which is what i want - memIter end = memHash.end(); - for (memIter iter = memHash.begin(); iter != end; ++iter) { - ccprintf(memPrint, "%8x\t%d\n", (*iter).first, (*iter).second); - } -} - -Addr -Split::regenerateBlkAddr(Addr tag, int set) const -{ - if (lifo_net) - return lifo_net->regenerateBlkAddr(tag, set); - else - return lru->regenerateBlkAddr(tag, set); -} - -Addr -Split::extractTag(Addr addr) const -{ - // need to fix this if we want to use it... old interface of - // passing in blk was too weird - assert(0); - return 0; -/* - if (blk->part == 2) { - if (lifo_net) - return lifo_net->extractTag(addr); - else if (lru_net) - return lru_net->extractTag(addr); - else - panic("this shouldn't happen"); - } else - return lru->extractTag(addr); -*/ -} - diff --git a/src/mem/cache/tags/split.hh b/src/mem/cache/tags/split.hh deleted file mode 100644 index e8954f791..000000000 --- a/src/mem/cache/tags/split.hh +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Declaration of a split/partitioned tag store. - */ - -#ifndef __SPLIT_HH__ -#define __SPLIT_HH__ - -#include <cstring> -#include <list> - -#include "mem/cache/blk.hh" // base class -#include "mem/cache/tags/split_blk.hh" -#include "mem/packet.hh" // for inlined functions -#include <assert.h> -#include "mem/cache/tags/base.hh" -#include "base/hashmap.hh" - -class BaseCache; -class SplitLRU; -class SplitLIFO; - -/** - * A cache tag store. - */ -class Split : public BaseTags -{ - public: - /** Typedef the block type used in this tag store. */ - typedef SplitBlk BlkType; - /** Typedef for a list of pointers to the local block class. */ - typedef std::list<SplitBlk*> BlkList; - protected: - /** The number of sets in the cache. */ - const int numSets; - /** The number of bytes in a block. */ - const int blkSize; - /** Whether the 2nd partition (for the nic) is LIFO or not */ - const bool lifo; - /** The hit latency. */ - const int hitLatency; - - Addr blkMask; - - /** Number of NIC requests that hit in the NIC partition */ - Stats::Scalar<> NR_NP_hits; - /** Number of NIC requests that hit in the CPU partition */ - Stats::Scalar<> NR_CP_hits; - /** Number of CPU requests that hit in the NIC partition */ - Stats::Scalar<> CR_NP_hits; - /** Number of CPU requests that hit in the CPU partition */ - Stats::Scalar<> CR_CP_hits; - /** The number of nic replacements (i.e. misses) */ - Stats::Scalar<> nic_repl; - /** The number of cpu replacements (i.e. misses) */ - Stats::Scalar<> cpu_repl; - - //For latency studies - /** the number of NIC blks that were used before evicted */ - Stats::Scalar<> nicUsedWhenEvicted; - /** the total latency of used NIC blocks in the cache */ - Stats::Scalar<> nicUsedTotLatency; - /** the total number of used NIC blocks evicted */ - Stats::Scalar<> nicUsedTotEvicted; - /** the average number of cycles a used NIC blk is in the cache */ - Stats::Formula nicUsedAvgLatency; - /** the Distribution of used NIC blk eviction times */ - Stats::Distribution<> usedEvictDist; - - /** the number of NIC blks that were unused before evicted */ - Stats::Scalar<> nicUnusedWhenEvicted; - /** the total latency of unused NIC blks in the cache */ - Stats::Scalar<> nicUnusedTotLatency; - /** the total number of unused NIC blocks evicted */ - Stats::Scalar<> nicUnusedTotEvicted; - /** the average number of cycles an unused NIC blk is in the cache */ - Stats::Formula nicUnusedAvgLatency; - /** the Distribution of unused NIC blk eviction times */ - Stats::Distribution<> unusedEvictDist; - - /** The total latency of NIC blocks to 1st usage time by CPU */ - Stats::Scalar<> nicUseByCPUCycleTotal; - /** The total number of NIC blocks used */ - Stats::Scalar<> nicBlksUsedByCPU; - /** the average number of cycles before a NIC blk that is used gets used by CPU */ - Stats::Formula nicAvgUsageByCPULatency; - /** the Distribution of cycles time before a NIC blk is used by CPU*/ - Stats::Distribution<> useByCPUCycleDist; - - /** the number of CPU blks that were used before evicted */ - Stats::Scalar<> cpuUsedBlks; - /** the number of CPU blks that were unused before evicted */ - Stats::Scalar<> cpuUnusedBlks; - - /** the avg number of cycles before a NIC blk is evicted */ - Stats::Formula nicAvgLatency; - - typedef m5::hash_map<Addr, int, m5::hash<Addr> > hash_t; - typedef hash_t::const_iterator memIter; - hash_t memHash; - - - private: - SplitLRU *lru; - SplitLRU *lru_net; - SplitLIFO *lifo_net; - - public: - /** - * Construct and initialize this tag store. - * @param _numSets The number of sets in the cache. - * @param _blkSize The number of bytes in a block. - * @param _assoc The associativity of the cache. - * @param _hit_latency The latency in cycles for a hit. - */ - Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc, - bool _lifo, bool _two_queue, int _hit_latency); - - /** - * Destructor - */ - virtual ~Split(); - - /** - * Register the stats for this object - * @param name The name to prepend to the stats name. - */ - void regStats(const std::string &name); - - /** - * Return the block size. - * @return the block size. - */ - int getBlockSize() - { - return blkSize; - } - - /** - * Return the subblock size. In the case of Split it is always the block - * size. - * @return The block size. - */ - int getSubBlockSize() - { - return blkSize; - } - - /** - * Search for the address in the cache. - * @param asid The address space ID. - * @param addr The address to find. - * @return True if the address is in the cache. - */ - bool probe(Addr addr) const; - - /** - * Invalidate the given block. - * @param blk The block to invalidate. - */ - void invalidateBlk(BlkType *blk); - - /** - * Finds the given address in the cache and update replacement data. - * Returns the access latency as a side effect. - * @param addr The address to find. - * @param asid The address space ID. - * @param lat The access latency. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr, int &lat); - - /** - * Finds the given address in the cache, do not update replacement data. - * @param addr The address to find. - * @param asid The address space ID. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr) const; - - /** - * Find a replacement block for the address provided. - * @param pkt The request to a find a replacement candidate for. - * @param writebacks List for any writebacks to be performed. - * @return The block to place the replacement in. - */ - SplitBlk* findReplacement(Addr addr, PacketList &writebacks); - - - /** - * Generate the tag from the given address. - * @param addr The address to get the tag from. - * @return The tag of the address. - */ - Addr extractTag(Addr addr) const; - - /** - * Calculate the set index from the address. - * @param addr The address to get the set from. - * @return The set index of the address. - */ - int extractSet(Addr addr) const - { - panic("should never call this!\n"); - M5_DUMMY_RETURN - } - - /** - * Get the block offset from an address. - * @param addr The address to get the offset of. - * @return The block offset. - */ - int extractBlkOffset(Addr addr) const - { - return (addr & blkMask); - } - - /** - * Align an address to the block size. - * @param addr the address to align. - * @return The block address. - */ - Addr blkAlign(Addr addr) const - { - return (addr & ~(Addr) (blkMask)); - } - - /** - * Regenerate the block address from the tag. - * @param tag The tag of the block. - * @param set The set of the block. - * @return The block address. - */ - Addr regenerateBlkAddr(Addr tag, int set) const; - - /** - * Return the hit latency. - * @return the hit latency. - */ - int getHitLatency() const - { - return hitLatency; - } - - /** - * Read the data out of the internal storage of the given cache block. - * @param blk The cache block to read. - * @param data The buffer to read the data into. - * @return The cache block's data. - */ - void readData(SplitBlk *blk, uint8_t *data) - { - std::memcpy(data, blk->data, blk->size); - } - - /** - * Write data into the internal storage of the given cache block. Since in - * Split does not store data differently this just needs to update the size. - * @param blk The cache block to write. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(SplitBlk *blk, uint8_t *data, int size, - PacketList & writebacks) - { - assert(size <= blkSize); - blk->size = size; - } - - /** - * Called at end of simulation to complete average block reference stats. - */ - virtual void cleanupRefs(); -}; - -#endif diff --git a/src/mem/cache/tags/split_blk.hh b/src/mem/cache/tags/split_blk.hh deleted file mode 100644 index d2efe08df..000000000 --- a/src/mem/cache/tags/split_blk.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Declaration of partitioned tag store cache block class. - */ - -#ifndef __SPLIT_BLK_HH__ -#define __SPLIT_BLK_HH__ - -#include "mem/cache/blk.hh" // base class - -/** - * Split cache block. - */ -class SplitBlk : public CacheBlk { - public: - /** Has this block been touched? Used to aid calculation of warmup time. */ - bool isTouched; - /** Has this block been used after being brought in? (for LIFO partition) */ - bool isUsed; - /** is this blk a NIC block? (i.e. requested by the NIC) */ - bool isNIC; - /** timestamp of the arrival of this block into the cache */ - Tick ts; - /** the previous block in the LIFO partition (brought in before than me) */ - SplitBlk *prev; - /** the next block in the LIFO partition (brought in later than me) */ - SplitBlk *next; - /** which partition this block is in */ - int part; - - SplitBlk() - : isTouched(false), isUsed(false), isNIC(false), ts(0), prev(NULL), next(NULL), - part(0) - {} -}; - -#endif - diff --git a/src/mem/cache/tags/split_lifo.cc b/src/mem/cache/tags/split_lifo.cc deleted file mode 100644 index 3bdc7cae9..000000000 --- a/src/mem/cache/tags/split_lifo.cc +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Definitions of LIFO tag store usable in a partitioned cache. - */ - -#include <string> - -#include "mem/cache/base.hh" -#include "base/intmath.hh" -#include "mem/cache/tags/split_lifo.hh" -#include "sim/core.hh" -#include "base/trace.hh" - -using namespace std; - -SplitBlk* -LIFOSet::findBlk(Addr tag) const -{ - for (SplitBlk *blk = firstIn; blk != NULL; blk = blk->next) { - if (blk->tag == tag && blk->isValid()) { - return blk; - } - } - return NULL; -} - -void -LIFOSet::moveToLastIn(SplitBlk *blk) -{ - if (blk == lastIn) - return; - - if (blk == firstIn) { - blk->next->prev = NULL; - } else { - blk->prev->next = blk->next; - blk->next->prev = blk->prev; - } - blk->next = NULL; - blk->prev = lastIn; - lastIn->next = blk; - - lastIn = blk; -} - -void -LIFOSet::moveToFirstIn(SplitBlk *blk) -{ - if (blk == firstIn) - return; - - if (blk == lastIn) { - blk->prev->next = NULL; - } else { - blk->next->prev = blk->prev; - blk->prev->next = blk->next; - } - - blk->prev = NULL; - blk->next = firstIn; - firstIn->prev = blk; - - firstIn = blk; -} - -// create and initialize a LIFO cache structure -SplitLIFO::SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool two_Queue, int _part) : - blkSize(_blkSize), size(_size), numBlks(_size/_blkSize), numSets((_size/_ways)/_blkSize), ways(_ways), - hitLatency(_hit_latency), twoQueue(two_Queue), part(_part) -{ - if (!isPowerOf2(blkSize)) - fatal("cache block size (in bytes) must be a power of 2"); - if (!(hitLatency > 0)) - fatal("access latency in cycles must be at least on cycle"); - if (_ways == 0) - fatal("if instantiating a splitLIFO, needs non-zero size!"); - - - SplitBlk *blk; - int i, j, blkIndex; - - setShift = floorLog2(blkSize); - blkMask = blkSize - 1; - setMask = numSets - 1; - tagShift = setShift + floorLog2(numSets); - - warmedUp = false; - /** @todo Make warmup percentage a parameter. */ - warmupBound = size/blkSize; - - // allocate data blocks - blks = new SplitBlk[numBlks]; - sets = new LIFOSet[numSets]; - dataBlks = new uint8_t[size]; - -/* - // these start off point to same blk - top = &(blks[0]); - head = top; -*/ - - blkIndex = 0; - for (i=0; i < numSets; ++i) { - sets[i].ways = ways; - sets[i].lastIn = &blks[blkIndex]; - sets[i].firstIn = &blks[blkIndex + ways - 1]; - - /* 3 cases: if there is 1 way, if there are 2 ways, or if there are 3+. - in the case of 1 way, last in and first out point to the same blocks, - and the next and prev pointers need to be assigned specially. and so on - */ - /* deal with the first way */ - blk = &blks[blkIndex]; - blk->prev = &blks[blkIndex + 1]; - blk->next = NULL; - blk->data = &dataBlks[blkSize*blkIndex]; - blk->size = blkSize; - blk->part = part; - blk->set = i; - ++blkIndex; - - /* if there are "middle" ways, do them here */ - if (ways > 2) { - for (j=1; j < ways-1; ++j) { - blk = &blks[blkIndex]; - blk->data = &dataBlks[blkSize*blkIndex]; - blk->prev = &blks[blkIndex+1]; - blk->next = &blks[blkIndex-1]; - blk->data = &(dataBlks[blkSize*blkIndex]); - blk->size = blkSize; - blk->part = part; - blk->set = i; - ++blkIndex; - } - } - - /* do the final way here, depending on whether the final way is the only - way or not - */ - if (ways > 1) { - blk = &blks[blkIndex]; - blk->prev = NULL; - blk->next = &blks[blkIndex - 1]; - blk->data = &dataBlks[blkSize*blkIndex]; - blk->size = blkSize; - blk->part = part; - blk->set = i; - ++blkIndex; - } else { - blk->prev = NULL; - } - } - assert(blkIndex == numBlks); -} - -SplitLIFO::~SplitLIFO() -{ - delete [] blks; - delete [] sets; - delete [] dataBlks; -} - -void -SplitLIFO::regStats(const std::string &name) -{ - BaseTags::regStats(name); - - hits - .name(name + ".hits") - .desc("number of hits on this partition") - .precision(0) - ; - - misses - .name(name + ".misses") - .desc("number of misses in this partition") - .precision(0) - ; - - invalidations - .name(name + ".invalidations") - .desc("number of invalidations in this partition") - .precision(0) - ; -} - -// probe cache for presence of given block. -bool -SplitLIFO::probe(Addr addr) const -{ - Addr tag = extractTag(addr); - unsigned myset = extractSet(addr); - - SplitBlk* blk = sets[myset].findBlk(tag); - return (blk != NULL); -} - -SplitBlk* -SplitLIFO::findBlock(Addr addr, int &lat) -{ - Addr tag = extractTag(addr); - unsigned set = extractSet(addr); - SplitBlk *blk = sets[set].findBlk(tag); - - lat = hitLatency; - - if (blk) { - DPRINTF(Split, "Found LIFO blk %#x in set %d, with tag %#x\n", - addr, set, tag); - hits++; - - if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency) - lat = blk->whenReady - curTick; - blk->refCount +=1; - - if (twoQueue) { - blk->isUsed = true; - sets[set].moveToFirstIn(blk); - } else { - sets[set].moveToLastIn(blk); - } - } - - return blk; -} - - -SplitBlk* -SplitLIFO::findBlock(Addr addr) const -{ - Addr tag = extractTag(addr); - unsigned set = extractSet(addr); - SplitBlk *blk = sets[set].findBlk(tag); - - return blk; -} - -SplitBlk* -SplitLIFO::findReplacement(Addr addr, PacketList &writebacks) -{ - unsigned set = extractSet(addr); - - SplitBlk *firstIn = sets[set].firstIn; - SplitBlk *lastIn = sets[set].lastIn; - - SplitBlk *blk; - if (twoQueue && firstIn->isUsed) { - blk = firstIn; - blk->isUsed = false; - sets[set].moveToLastIn(blk); - } else { - int withValue = sets[set].withValue; - if (withValue == ways) { - blk = lastIn; - } else { - blk = &(sets[set].firstIn[ways - ++withValue]); - } - } - - DPRINTF(Split, "just assigned %#x addr into LIFO, replacing %#x status %#x\n", - addr, regenerateBlkAddr(blk->tag, set), blk->status); - if (blk->isValid()) { - replacements[0]++; - totalRefs += blk->refCount; - ++sampledRefs; - blk->refCount = 0; - } else { - tagsInUse++; - blk->isTouched = true; - if (!warmedUp && tagsInUse.value() >= warmupBound) { - warmedUp = true; - warmupCycle = curTick; - } - } - - misses++; - - return blk; -} - -void -SplitLIFO::invalidateBlk(SplitLIFO::BlkType *blk) -{ - if (blk) { - blk->status = 0; - blk->isTouched = false; - tagsInUse--; - invalidations++; - } -} - -void -SplitLIFO::cleanupRefs() -{ - for (int i = 0; i < numBlks; ++i) { - if (blks[i].isValid()) { - totalRefs += blks[i].refCount; - ++sampledRefs; - } - } -} diff --git a/src/mem/cache/tags/split_lifo.hh b/src/mem/cache/tags/split_lifo.hh deleted file mode 100644 index 0fd5f5c3c..000000000 --- a/src/mem/cache/tags/split_lifo.hh +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Declaration of a LIFO tag store usable in a partitioned cache. - */ - -#ifndef __SPLIT_LIFO_HH__ -#define __SPLIT_LIFO_HH__ - -#include <cstring> -#include <list> - -#include "mem/cache/blk.hh" // base class -#include "mem/cache/tags/split_blk.hh" -#include "mem/packet.hh" // for inlined functions -#include "base/hashmap.hh" -#include <assert.h> -#include "mem/cache/tags/base.hh" - -class BaseCache; - -/** - * A LIFO set of cache blks - */ -class LIFOSet { - public: - /** the number of blocks in this set */ - int ways; - - /** Cache blocks in this set, maintained in LIFO order where - 0 = Last in (head) */ - SplitBlk *lastIn; - SplitBlk *firstIn; - - /** has the initial "filling" of this set finished? i.e., have you had - * 'ways' number of compulsory misses in this set yet? if withValue == ways, - * then yes. withValue is meant to be the number of blocks in the set that have - * gone through their first compulsory miss. - */ - int withValue; - - /** - * Find a block matching the tag in this set. - * @param asid The address space ID. - * @param tag the Tag you are looking for - * @return Pointer to the block, if found, NULL otherwise - */ - SplitBlk* findBlk(Addr tag) const; - - void moveToLastIn(SplitBlk *blk); - void moveToFirstIn(SplitBlk *blk); - - LIFOSet() - : ways(-1), lastIn(NULL), firstIn(NULL), withValue(0) - {} -}; - -/** - * A LIFO cache tag store. - */ -class SplitLIFO : public BaseTags -{ - public: - /** Typedef the block type used in this tag store. */ - typedef SplitBlk BlkType; - /** Typedef for a list of pointers to the local block class. */ - typedef std::list<SplitBlk*> BlkList; - protected: - /** The number of bytes in a block. */ - const int blkSize; - /** the size of the cache in bytes */ - const int size; - /** the number of blocks in the cache */ - const int numBlks; - /** the number of sets in the cache */ - const int numSets; - /** the number of ways in the cache */ - const int ways; - /** The hit latency. */ - const int hitLatency; - /** whether this is a "2 queue" replacement @sa moveToLastIn @sa moveToFirstIn */ - const bool twoQueue; - /** indicator for which partition this is */ - const int part; - - /** The cache blocks. */ - SplitBlk *blks; - /** The Cache sets */ - LIFOSet *sets; - /** The data blocks, 1 per cache block. */ - uint8_t *dataBlks; - - /** The amount to shift the address to get the set. */ - int setShift; - /** The amount to shift the address to get the tag. */ - int tagShift; - /** Mask out all bits that aren't part of the set index. */ - unsigned setMask; - /** Mask out all bits that aren't part of the block offset. */ - unsigned blkMask; - - - /** the number of hit in this partition */ - Stats::Scalar<> hits; - /** the number of blocks brought into this partition (i.e. misses) */ - Stats::Scalar<> misses; - /** the number of invalidations in this partition */ - Stats::Scalar<> invalidations; - -public: - /** - * Construct and initialize this tag store. - * @param _numSets The number of sets in the cache. - * @param _blkSize The number of bytes in a block. - * @param _assoc The associativity of the cache. - * @param _hit_latency The latency in cycles for a hit. - */ - SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool twoQueue, int _part); - - /** - * Destructor - */ - virtual ~SplitLIFO(); - - /** - * Register the statistics for this object - * @param name The name to precede the stat - */ - void regStats(const std::string &name); - - /** - * Return the block size. - * @return the block size. - */ - int getBlockSize() - { - return blkSize; - } - - /** - * Return the subblock size. In the case of LIFO it is always the block - * size. - * @return The block size. - */ - int getSubBlockSize() - { - return blkSize; - } - - /** - * Search for the address in the cache. - * @param asid The address space ID. - * @param addr The address to find. - * @return True if the address is in the cache. - */ - bool probe( Addr addr) const; - - /** - * Invalidate the given block. - * @param blk The block to invalidate. - */ - void invalidateBlk(BlkType *blk); - - /** - * Finds the given address in the cache and update replacement data. - * Returns the access latency as a side effect. - * @param addr The address to find. - * @param asid The address space ID. - * @param lat The access latency. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr, int &lat); - - /** - * Finds the given address in the cache, do not update replacement data. - * @param addr The address to find. - * @param asid The address space ID. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr) const; - - /** - * Find a replacement block for the address provided. - * @param pkt The request to a find a replacement candidate for. - * @param writebacks List for any writebacks to be performed. - * @return The block to place the replacement in. - */ - SplitBlk* findReplacement(Addr addr, PacketList &writebacks); - - /** - * Generate the tag from the given address. - * @param addr The address to get the tag from. - * @return The tag of the address. - */ - Addr extractTag(Addr addr) const - { - return (addr >> tagShift); - } - - /** - * Calculate the set index from the address. - * @param addr The address to get the set from. - * @return The set index of the address. - */ - int extractSet(Addr addr) const - { - return ((addr >> setShift) & setMask); - } - - /** - * Get the block offset from an address. - * @param addr The address to get the offset of. - * @return The block offset. - */ - int extractBlkOffset(Addr addr) const - { - return (addr & blkMask); - } - - /** - * Align an address to the block size. - * @param addr the address to align. - * @return The block address. - */ - Addr blkAlign(Addr addr) const - { - return (addr & ~(Addr)blkMask); - } - - /** - * Regenerate the block address from the tag. - * @param tag The tag of the block. - * @param set The set of the block. - * @return The block address. - */ - Addr regenerateBlkAddr(Addr tag, unsigned set) const - { - return ((tag << tagShift) | ((Addr)set << setShift)); - } - - /** - * Return the hit latency. - * @return the hit latency. - */ - int getHitLatency() const - { - return hitLatency; - } - - /** - * Read the data out of the internal storage of the given cache block. - * @param blk The cache block to read. - * @param data The buffer to read the data into. - * @return The cache block's data. - */ - void readData(SplitBlk *blk, uint8_t *data) - { - std::memcpy(data, blk->data, blk->size); - } - - /** - * Write data into the internal storage of the given cache block. Since in - * LIFO does not store data differently this just needs to update the size. - * @param blk The cache block to write. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(SplitBlk *blk, uint8_t *data, int size, - PacketList & writebacks) - { - assert(size <= blkSize); - blk->size = size; - } - - /** - * Called at end of simulation to complete average block reference stats. - */ - virtual void cleanupRefs(); -}; - -#endif diff --git a/src/mem/cache/tags/split_lru.cc b/src/mem/cache/tags/split_lru.cc deleted file mode 100644 index bcccdcb30..000000000 --- a/src/mem/cache/tags/split_lru.cc +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Definitions of LRU tag store for a partitioned cache. - */ - -#include <string> - -#include "mem/cache/base.hh" -#include "base/intmath.hh" -#include "mem/cache/tags/split_lru.hh" -#include "sim/core.hh" - -using namespace std; - -SplitBlk* -SplitCacheSet::findBlk(Addr tag) const -{ - for (int i = 0; i < assoc; ++i) { - if (blks[i]->tag == tag && blks[i]->isValid()) { - return blks[i]; - } - } - return 0; -} - - -void -SplitCacheSet::moveToHead(SplitBlk *blk) -{ - // nothing to do if blk is already head - if (blks[0] == blk) - return; - - // write 'next' block into blks[i], moving up from MRU toward LRU - // until we overwrite the block we moved to head. - - // start by setting up to write 'blk' into blks[0] - int i = 0; - SplitBlk *next = blk; - - do { - assert(i < assoc); - // swap blks[i] and next - SplitBlk *tmp = blks[i]; - blks[i] = next; - next = tmp; - ++i; - } while (next != blk); -} - - -// create and initialize a LRU/MRU cache structure -SplitLRU::SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part) : - numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency), part(_part) -{ - // Check parameters - if (blkSize < 4 || !isPowerOf2(blkSize)) { - fatal("Block size must be at least 4 and a power of 2"); - } - if (numSets <= 0 || !isPowerOf2(numSets)) { - fatal("# of sets must be non-zero and a power of 2"); - } - if (assoc <= 0) { - fatal("associativity must be greater than zero"); - } - if (hitLatency <= 0) { - fatal("access latency must be greater than zero"); - } - - SplitBlk *blk; - int i, j, blkIndex; - - blkMask = blkSize - 1; - setShift = floorLog2(blkSize); - setMask = numSets - 1; - tagShift = setShift + floorLog2(numSets); - warmedUp = false; - /** @todo Make warmup percentage a parameter. */ - warmupBound = numSets * assoc; - - sets = new SplitCacheSet[numSets]; - blks = new SplitBlk[numSets * assoc]; - // allocate data storage in one big chunk - dataBlks = new uint8_t[numSets*assoc*blkSize]; - - blkIndex = 0; // index into blks array - for (i = 0; i < numSets; ++i) { - sets[i].assoc = assoc; - - sets[i].blks = new SplitBlk*[assoc]; - - // link in the data blocks - for (j = 0; j < assoc; ++j) { - // locate next cache block - blk = &blks[blkIndex]; - blk->data = &dataBlks[blkSize*blkIndex]; - ++blkIndex; - - // invalidate new cache block - blk->status = 0; - - //EGH Fix Me : do we need to initialize blk? - - // Setting the tag to j is just to prevent long chains in the hash - // table; won't matter because the block is invalid - blk->tag = j; - blk->whenReady = 0; - blk->isTouched = false; - blk->size = blkSize; - sets[i].blks[j]=blk; - blk->set = i; - blk->part = part; - } - } -} - -SplitLRU::~SplitLRU() -{ - delete [] dataBlks; - delete [] blks; - delete [] sets; -} - -void -SplitLRU::regStats(const std::string &name) -{ - BaseTags::regStats(name); - - hits - .name(name + ".hits") - .desc("number of hits on this partition") - .precision(0) - ; - - misses - .name(name + ".misses") - .desc("number of misses in this partition") - .precision(0) - ; -} - -// probe cache for presence of given block. -bool -SplitLRU::probe(Addr addr) const -{ - // return(findBlock(Read, addr, asid) != 0); - Addr tag = extractTag(addr); - unsigned myset = extractSet(addr); - - SplitBlk *blk = sets[myset].findBlk(tag); - - return (blk != NULL); // true if in cache -} - -SplitBlk* -SplitLRU::findBlock(Addr addr, int &lat) -{ - Addr tag = extractTag(addr); - unsigned set = extractSet(addr); - SplitBlk *blk = sets[set].findBlk(tag); - lat = hitLatency; - if (blk != NULL) { - // move this block to head of the MRU list - sets[set].moveToHead(blk); - if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency){ - lat = blk->whenReady - curTick; - } - blk->refCount += 1; - hits++; - } - - return blk; -} - - -SplitBlk* -SplitLRU::findBlock(Addr addr) const -{ - Addr tag = extractTag(addr); - unsigned set = extractSet(addr); - SplitBlk *blk = sets[set].findBlk(tag); - return blk; -} - -SplitBlk* -SplitLRU::findReplacement(Addr addr, PacketList &writebacks) -{ - unsigned set = extractSet(addr); - // grab a replacement candidate - SplitBlk *blk = sets[set].blks[assoc-1]; - sets[set].moveToHead(blk); - if (blk->isValid()) { - replacements[0]++; - totalRefs += blk->refCount; - ++sampledRefs; - blk->refCount = 0; - } else if (!blk->isTouched) { - tagsInUse++; - blk->isTouched = true; - if (!warmedUp && tagsInUse.value() >= warmupBound) { - warmedUp = true; - warmupCycle = curTick; - } - } - - misses++; - - return blk; -} - -void -SplitLRU::invalidateBlk(SplitLRU::BlkType *blk) -{ - if (blk) { - blk->status = 0; - blk->isTouched = false; - tagsInUse--; - } -} - -void -SplitLRU::cleanupRefs() -{ - for (int i = 0; i < numSets*assoc; ++i) { - if (blks[i].isValid()) { - totalRefs += blks[i].refCount; - ++sampledRefs; - } - } -} diff --git a/src/mem/cache/tags/split_lru.hh b/src/mem/cache/tags/split_lru.hh deleted file mode 100644 index d41b6efa7..000000000 --- a/src/mem/cache/tags/split_lru.hh +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Lisa Hsu - */ - -/** - * @file - * Declaration of a LRU tag store for a partitioned cache. - */ - -#ifndef __SPLIT_LRU_HH__ -#define __SPLIT_LRU_HH__ - -#include <cstring> -#include <list> - -#include "mem/cache/blk.hh" // base class -#include "mem/cache/tags/split_blk.hh" -#include "mem/packet.hh" // for inlined functions -#include <assert.h> -#include "mem/cache/tags/base.hh" - -class BaseCache; - -/** - * An associative set of cache blocks. - */ - -class SplitCacheSet -{ - public: - /** The associativity of this set. */ - int assoc; - - /** Cache blocks in this set, maintained in LRU order 0 = MRU. */ - SplitBlk **blks; - - /** - * Find a block matching the tag in this set. - * @param asid The address space ID. - * @param tag The Tag to find. - * @return Pointer to the block if found. - */ - SplitBlk* findBlk(Addr tag) const; - - /** - * Move the given block to the head of the list. - * @param blk The block to move. - */ - void moveToHead(SplitBlk *blk); -}; - -/** - * A LRU cache tag store. - */ -class SplitLRU : public BaseTags -{ - public: - /** Typedef the block type used in this tag store. */ - typedef SplitBlk BlkType; - /** Typedef for a list of pointers to the local block class. */ - typedef std::list<SplitBlk*> BlkList; - protected: - /** The number of sets in the cache. */ - const int numSets; - /** The number of bytes in a block. */ - const int blkSize; - /** The associativity of the cache. */ - const int assoc; - /** The hit latency. */ - const int hitLatency; - /** indicator for which partition this is */ - const int part; - - /** The cache sets. */ - SplitCacheSet *sets; - - /** The cache blocks. */ - SplitBlk *blks; - /** The data blocks, 1 per cache block. */ - uint8_t *dataBlks; - - /** The amount to shift the address to get the set. */ - int setShift; - /** The amount to shift the address to get the tag. */ - int tagShift; - /** Mask out all bits that aren't part of the set index. */ - unsigned setMask; - /** Mask out all bits that aren't part of the block offset. */ - unsigned blkMask; - - /** number of hits in this partition */ - Stats::Scalar<> hits; - /** number of blocks brought into this partition (i.e. misses) */ - Stats::Scalar<> misses; - -public: - /** - * Construct and initialize this tag store. - * @param _numSets The number of sets in the cache. - * @param _blkSize The number of bytes in a block. - * @param _assoc The associativity of the cache. - * @param _hit_latency The latency in cycles for a hit. - */ - SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part); - - /** - * Destructor - */ - virtual ~SplitLRU(); - - /** - * Register the statistics for this object - * @param name The name to precede the stat - */ - void regStats(const std::string &name); - - /** - * Return the block size. - * @return the block size. - */ - int getBlockSize() - { - return blkSize; - } - - /** - * Return the subblock size. In the case of LRU it is always the block - * size. - * @return The block size. - */ - int getSubBlockSize() - { - return blkSize; - } - - /** - * Search for the address in the cache. - * @param asid The address space ID. - * @param addr The address to find. - * @return True if the address is in the cache. - */ - bool probe(Addr addr) const; - - /** - * Invalidate the given block. - * @param blk The block to invalidate. - */ - void invalidateBlk(BlkType *blk); - - /** - * Finds the given address in the cache and update replacement data. - * Returns the access latency as a side effect. - * @param addr The address to find. - * @param asid The address space ID. - * @param lat The access latency. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr, int &lat); - - /** - * Finds the given address in the cache, do not update replacement data. - * @param addr The address to find. - * @param asid The address space ID. - * @return Pointer to the cache block if found. - */ - SplitBlk* findBlock(Addr addr) const; - - /** - * Find a replacement block for the address provided. - * @param pkt The request to a find a replacement candidate for. - * @param writebacks List for any writebacks to be performed. - * @return The block to place the replacement in. - */ - SplitBlk* findReplacement(Addr addr, PacketList &writebacks); - - /** - * Generate the tag from the given address. - * @param addr The address to get the tag from. - * @return The tag of the address. - */ - Addr extractTag(Addr addr) const - { - return (addr >> tagShift); - } - - /** - * Calculate the set index from the address. - * @param addr The address to get the set from. - * @return The set index of the address. - */ - int extractSet(Addr addr) const - { - return ((addr >> setShift) & setMask); - } - - /** - * Get the block offset from an address. - * @param addr The address to get the offset of. - * @return The block offset. - */ - int extractBlkOffset(Addr addr) const - { - return (addr & blkMask); - } - - /** - * Align an address to the block size. - * @param addr the address to align. - * @return The block address. - */ - Addr blkAlign(Addr addr) const - { - return (addr & ~(Addr)blkMask); - } - - /** - * Regenerate the block address from the tag. - * @param tag The tag of the block. - * @param set The set of the block. - * @return The block address. - */ - Addr regenerateBlkAddr(Addr tag, unsigned set) const - { - return ((tag << tagShift) | ((Addr)set << setShift)); - } - - /** - * Return the hit latency. - * @return the hit latency. - */ - int getHitLatency() const - { - return hitLatency; - } - - /** - * Read the data out of the internal storage of the given cache block. - * @param blk The cache block to read. - * @param data The buffer to read the data into. - * @return The cache block's data. - */ - void readData(SplitBlk *blk, uint8_t *data) - { - std::memcpy(data, blk->data, blk->size); - } - - /** - * Write data into the internal storage of the given cache block. Since in - * LRU does not store data differently this just needs to update the size. - * @param blk The cache block to write. - * @param data The data to write. - * @param size The number of bytes to write. - * @param writebacks A list for any writebacks to be performed. May be - * needed when writing to a compressed block. - */ - void writeData(SplitBlk *blk, uint8_t *data, int size, - PacketList & writebacks) - { - assert(size <= blkSize); - blk->size = size; - } - - /** - * Called at end of simulation to complete average block reference stats. - */ - virtual void cleanupRefs(); -}; - -#endif diff --git a/src/mem/config/cache.hh b/src/mem/config/cache.hh index 24da04021..946ed444f 100644 --- a/src/mem/config/cache.hh +++ b/src/mem/config/cache.hh @@ -36,7 +36,4 @@ */ #define USE_CACHE_LRU 1 #define USE_CACHE_FALRU 1 -// #define USE_CACHE_SPLIT 1 -// #define USE_CACHE_SPLIT_LIFO 1 #define USE_CACHE_IIC 1 - diff --git a/src/mem/dram.cc b/src/mem/dram.cc index 75146f9ed..ff01ab1dc 100644 --- a/src/mem/dram.cc +++ b/src/mem/dram.cc @@ -366,7 +366,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) int lat=0, temp=0, current_bank=0; int current_row=0, current_device=0; - int was_miss = 0; // determines if there was an active row miss this access + int was_miss = 0; // determines if there was an active row miss this access //md_addr_t physic_address; /* linear memory address to be accessed */ Addr physic_address; /* linear memory address to be accessed */ @@ -415,7 +415,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) int SD_BEST_T_WRITE_WRITE_OBANK = 0; /* WAW, row miss/hit, another bank */ Tick time_since_last_access = curTick-time_last_access; - Tick time_last_miss = 0; // used for keeping track of times between activations (page misses) + Tick time_last_miss = 0; // used for keeping track of times between activations (page misses) //int was_idle = (curTick > busy_until); bool srow_flag = false; int timing_correction = 0; @@ -433,7 +433,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) // SDRAM does not use the active_row array in closed_page mode // TODO: handle closed page operation - } else { // DRDRAM uses the active_row array + } else { // DRDRAM uses the active_row array for( int i = 0; i < bank_max; i++ ) { if( (active_row[current_bank] != row_max)) all_precharged = 0; } @@ -923,7 +923,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) } // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2034,7 +2034,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2226,7 +2226,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) /*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)curTick, overlap, lat);debug*/ // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2468,7 +2468,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2525,7 +2525,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2593,7 +2593,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) } // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return lat; } @@ -2608,7 +2608,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt) assert(chunks >0); // if((_cpu_num < num_cpus) && (_cpu_num >= 0)) // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl; - // bank_access_profile[_cpu_num][current_bank]++; + // bank_access_profile[_cpu_num][current_bank]++; return(/* first chunk latency */act_lat + (/* remainder chunk latency */cas_lat * (chunks - 1))); } diff --git a/src/mem/dram.hh b/src/mem/dram.hh index 352ca96ae..1745fa52b 100644 --- a/src/mem/dram.hh +++ b/src/mem/dram.hh @@ -117,27 +117,27 @@ class DRAMMemory : public PhysicalMemory Tick time_last_access; - Stats::Vector<> accesses; - Stats::Vector<> bytesRequested; - Stats::Vector<> bytesSent; - Stats::Vector<> compressedAccesses; - - Stats::Vector<> cycles_nCKE; - Stats::Vector<> cycles_all_precharge_CKE; - Stats::Vector<> cycles_all_precharge_nCKE; - Stats::Vector<> cycles_bank_active_nCKE; - Stats::Vector<> cycles_avg_ACT; - Stats::Vector<> cycles_read_out; - Stats::Vector<> cycles_write_in; - Stats::Vector<> cycles_between_misses; - Stats::Vector<> other_bank_read_access_miss; - Stats::Vector<> other_bank_write_access_miss; - Stats::Scalar<> total_latency; - Stats::Scalar<> total_icache_req; - Stats::Scalar<> total_arb_latency; + Stats::Vector accesses; + Stats::Vector bytesRequested; + Stats::Vector bytesSent; + Stats::Vector compressedAccesses; + + Stats::Vector cycles_nCKE; + Stats::Vector cycles_all_precharge_CKE; + Stats::Vector cycles_all_precharge_nCKE; + Stats::Vector cycles_bank_active_nCKE; + Stats::Vector cycles_avg_ACT; + Stats::Vector cycles_read_out; + Stats::Vector cycles_write_in; + Stats::Vector cycles_between_misses; + Stats::Vector other_bank_read_access_miss; + Stats::Vector other_bank_write_access_miss; + Stats::Scalar total_latency; + Stats::Scalar total_icache_req; + Stats::Scalar total_arb_latency; Stats::Formula avg_latency; Stats::Formula avg_arb_latency; - Stats::Vector2d<> bank_access_profile; + Stats::Vector2d bank_access_profile; protected: diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc index ce2a1107e..20a1b4cd8 100644 --- a/src/mem/mem_object.cc +++ b/src/mem/mem_object.cc @@ -35,14 +35,6 @@ MemObject::MemObject(const Params *params) { } -MemObjectParams * -MemObject::makeParams(const std::string &name) -{ - MemObjectParams *params = new MemObjectParams; - params->name = name; - return params; -} - void MemObject::deletePortRefs(Port *p) { diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh index 33b56dfd4..b8bf4b939 100644 --- a/src/mem/mem_object.hh +++ b/src/mem/mem_object.hh @@ -48,17 +48,10 @@ class MemObject : public SimObject { public: typedef MemObjectParams Params; - MemObject(const Params *params); - - const Params * - params() const - { - return dynamic_cast<const Params *>(_params); - } + const Params *params() const + { return dynamic_cast<const Params *>(_params); } - protected: - // static: support for old-style constructors (call manually) - static Params *makeParams(const std::string &name); + MemObject(const Params *params); public: /** Additional function to return the Port of a memory object. */ diff --git a/src/mem/mport.cc b/src/mem/mport.cc new file mode 100644 index 000000000..72bcfc7fd --- /dev/null +++ b/src/mem/mport.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "mem/mport.hh" + +Tick +MessagePort::recvAtomic(PacketPtr pkt) +{ + if (pkt->cmd == MemCmd::MessageReq) { + // We received a message. + return recvMessage(pkt); + } else if (pkt->cmd == MemCmd::MessageResp) { + return recvResponse(pkt); + } else if (pkt->wasNacked()) { + return recvNack(pkt); + } else if (pkt->isError()) { + panic("Packet is error.\n"); + } else { + panic("Unexpected memory command %s.\n", pkt->cmd.toString()); + } +} + +void +MessagePort::sendMessageTiming(PacketPtr pkt, Tick latency) +{ + schedSendTiming(pkt, curTick + latency); +} + +Tick +MessagePort::sendMessageAtomic(PacketPtr pkt) +{ + return sendAtomic(pkt); +} diff --git a/src/cpu/o3/mips/thread_context.hh b/src/mem/mport.hh index 26b1e2e7f..5975f89f0 100644 --- a/src/cpu/o3/mips/thread_context.hh +++ b/src/mem/mport.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,44 +25,56 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Kevin Lim - * Korey Sewell + * Authors: Gabe Black */ -#include "arch/mips/types.hh" -#include "cpu/o3/thread_context.hh" +#ifndef __MEM_MPORT_HH__ +#define __MEM_MPORT_HH__ -template <class Impl> -class MipsTC : public O3ThreadContext<Impl> +#include "mem/tport.hh" + +/* + * This file defines a port class which is used for sending and receiving + * messages. These messages are atomic units which don't interact and + * should be smaller than a cache block. This class is based on + * the underpinnings of SimpleTimingPort, but it tweaks some of the external + * functions. + */ + +class MessagePort : public SimpleTimingPort { public: - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } + MessagePort(std::string pname, MemObject *_owner = NULL) : + SimpleTimingPort(pname, _owner) + {} - virtual void setNextNPC(uint64_t val) + virtual ~MessagePort() + {} + + void + recvFunctional(PacketPtr pkt) { - this->cpu->setNextNPC(val, this->thread->readTid()); + recvAtomic(pkt); } - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Mips!"); } + Tick recvAtomic(PacketPtr pkt); + + virtual Tick recvMessage(PacketPtr pkt) = 0; - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() + // Accept and ignore responses. + virtual Tick recvResponse(PacketPtr pkt) { - this->deallocate(); + return 0; + } - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation + // Since by default we're assuming everything we send is accepted, panic. + virtual Tick recvNack(PacketPtr pkt) + { + panic("Unhandled message nack.\n"); } + + void sendMessageTiming(PacketPtr pkt, Tick latency); + Tick sendMessageAtomic(PacketPtr pkt); }; + +#endif diff --git a/src/mem/packet.cc b/src/mem/packet.cc index f3bd06f36..17e58859a 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -42,6 +42,8 @@ #include "base/trace.hh" #include "mem/packet.hh" +using namespace std; + // The one downside to bitsets is that static initializers can get ugly. #define SET1(a1) (1 << (a1)) #define SET2(a1, a2) (SET1(a1) | SET1(a2)) @@ -101,12 +103,10 @@ MemCmd::commandInfo[] = /* ReadExResp */ { SET4(IsRead, NeedsExclusive, IsResponse, HasData), InvalidCmd, "ReadExResp" }, - /* LoadLockedReq */ + /* LoadLockedReq: note that we use plain ReadResp as response, so that + * we can also use ReadRespWithInvalidate when needed */ { SET4(IsRead, IsLocked, IsRequest, NeedsResponse), - LoadLockedResp, "LoadLockedReq" }, - /* LoadLockedResp */ - { SET4(IsRead, IsLocked, IsResponse, HasData), - InvalidCmd, "LoadLockedResp" }, + ReadResp, "LoadLockedReq" }, /* StoreCondReq */ { SET6(IsWrite, NeedsExclusive, IsLocked, IsRequest, NeedsResponse, HasData), @@ -120,6 +120,11 @@ MemCmd::commandInfo[] = /* SwapResp -- for Swap ldstub type operations */ { SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData), InvalidCmd, "SwapResp" }, + /* IntReq -- for interrupts */ + { SET4(IsWrite, IsRequest, NeedsResponse, HasData), + MessageReq, "MessageReq" }, + /* IntResp -- for interrupts */ + { SET2(IsWrite, IsResponse), MessageResp, "MessageResp" }, /* NetworkNackError -- nacked at network layer (not by protocol) */ { SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" }, /* InvalidDestError -- packet dest field invalid */ @@ -130,35 +135,6 @@ MemCmd::commandInfo[] = { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" } }; - -/** delete the data pointed to in the data pointer. Ok to call to matter how - * data was allocted. */ -void -Packet::deleteData() -{ - assert(staticData || dynamicData); - if (staticData) - return; - - if (arrayData) - delete [] data; - else - delete data; -} - -/** If there isn't data in the packet, allocate some. */ -void -Packet::allocate() -{ - if (data) - return; - assert(!staticData); - dynamicData = true; - arrayData = true; - data = new uint8_t[getSize()]; -} - - bool Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data) { @@ -190,7 +166,7 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data) if (isRead()) { if (func_start >= val_start && func_end <= val_end) { allocate(); - std::memcpy(getPtr<uint8_t>(), data + offset, getSize()); + memcpy(getPtr<uint8_t>(), data + offset, getSize()); makeResponse(); return true; } else { @@ -205,11 +181,12 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data) } } else if (isWrite()) { if (offset >= 0) { - std::memcpy(data + offset, getPtr<uint8_t>(), - (std::min(func_end, val_end) - func_start) + 1); - } else { // val_start > func_start - std::memcpy(data, getPtr<uint8_t>() - offset, - (std::min(func_end, val_end) - val_start) + 1); + memcpy(data + offset, getPtr<uint8_t>(), + (min(func_end, val_end) - func_start) + 1); + } else { + // val_start > func_start + memcpy(data, getPtr<uint8_t>() - offset, + (min(func_end, val_end) - val_start) + 1); } } else { panic("Don't know how to handle command %s\n", cmdString()); @@ -219,23 +196,19 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data) return false; } - void -Packet::print(std::ostream &o, const int verbosity, - const std::string &prefix) const +Packet::print(ostream &o, const int verbosity, const string &prefix) const { ccprintf(o, "%s[%x:%x] %s\n", prefix, getAddr(), getAddr() + getSize() - 1, cmdString()); } - -Packet::PrintReqState::PrintReqState(std::ostream &_os, int _verbosity) - : curPrefixPtr(new std::string("")), os(_os), verbosity(_verbosity) +Packet::PrintReqState::PrintReqState(ostream &_os, int _verbosity) + : curPrefixPtr(new string("")), os(_os), verbosity(_verbosity) { labelStack.push_back(LabelStackEntry("", curPrefixPtr)); } - Packet::PrintReqState::~PrintReqState() { labelStack.pop_back(); @@ -243,21 +216,17 @@ Packet::PrintReqState::~PrintReqState() delete curPrefixPtr; } - Packet::PrintReqState:: -LabelStackEntry::LabelStackEntry(const std::string &_label, - std::string *_prefix) +LabelStackEntry::LabelStackEntry(const string &_label, string *_prefix) : label(_label), prefix(_prefix), labelPrinted(false) { } - void -Packet::PrintReqState::pushLabel(const std::string &lbl, - const std::string &prefix) +Packet::PrintReqState::pushLabel(const string &lbl, const string &prefix) { labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr)); - curPrefixPtr = new std::string(*curPrefixPtr); + curPrefixPtr = new string(*curPrefixPtr); *curPrefixPtr += prefix; } diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 05442b369..41f599fa0 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -42,8 +42,10 @@ #include <list> #include <bitset> +#include "base/cast.hh" #include "base/compiler.hh" #include "base/fast_alloc.hh" +#include "base/flags.hh" #include "base/misc.hh" #include "base/printable.hh" #include "mem/request.hh" @@ -58,9 +60,12 @@ typedef std::list<PacketPtr> PacketList; class MemCmd { - public: + friend class Packet; - /** List of all commands associated with a packet. */ + public: + /** + * List of all commands associated with a packet. + */ enum Command { InvalidCmd, @@ -81,11 +86,12 @@ class MemCmd ReadExReq, ReadExResp, LoadLockedReq, - LoadLockedResp, StoreCondReq, StoreCondResp, SwapReq, SwapResp, + MessageReq, + MessageResp, // Error responses // @TODO these should be classified as responses rather than // requests; coding them as requests initially for backwards @@ -99,7 +105,9 @@ class MemCmd }; private: - /** List of command attributes. */ + /** + * List of command attributes. + */ enum Attribute { IsRead, //!< Data flows from responder to requester @@ -119,26 +127,31 @@ class MemCmd NUM_COMMAND_ATTRIBUTES }; - /** Structure that defines attributes and other data associated - * with a Command. */ - struct CommandInfo { - /** Set of attribute flags. */ + /** + * Structure that defines attributes and other data associated + * with a Command. + */ + struct CommandInfo + { + /// Set of attribute flags. const std::bitset<NUM_COMMAND_ATTRIBUTES> attributes; - /** Corresponding response for requests; InvalidCmd if no - * response is applicable. */ + /// Corresponding response for requests; InvalidCmd if no + /// response is applicable. const Command response; - /** String representation (for printing) */ + /// String representation (for printing) const std::string str; }; - /** Array to map Command enum to associated info. */ + /// Array to map Command enum to associated info. static const CommandInfo commandInfo[]; private: Command cmd; - bool testCmdAttrib(MemCmd::Attribute attrib) const { + bool + testCmdAttrib(MemCmd::Attribute attrib) const + { return commandInfo[cmd].attributes[attrib] != 0; } @@ -157,33 +170,22 @@ class MemCmd bool isError() const { return testCmdAttrib(IsError); } bool isPrint() const { return testCmdAttrib(IsPrint); } - const Command responseCommand() const { + const Command + responseCommand() const + { return commandInfo[cmd].response; } - /** Return the string to a cmd given by idx. */ - const std::string &toString() const { - return commandInfo[cmd].str; - } - + /// Return the string to a cmd given by idx. + const std::string &toString() const { return commandInfo[cmd].str; } int toInt() const { return (int)cmd; } - MemCmd(Command _cmd) - : cmd(_cmd) - { } - - MemCmd(int _cmd) - : cmd((Command)_cmd) - { } - - MemCmd() - : cmd(InvalidCmd) - { } - - bool operator==(MemCmd c2) { return (cmd == c2.cmd); } - bool operator!=(MemCmd c2) { return (cmd != c2.cmd); } + MemCmd(Command _cmd) : cmd(_cmd) { } + MemCmd(int _cmd) : cmd((Command)_cmd) { } + MemCmd() : cmd(InvalidCmd) { } - friend class Packet; + bool operator==(MemCmd c2) const { return (cmd == c2.cmd); } + bool operator!=(MemCmd c2) const { return (cmd != c2.cmd); } }; /** @@ -196,107 +198,118 @@ class MemCmd class Packet : public FastAlloc, public Printable { public: + typedef uint32_t FlagsType; + typedef ::Flags<FlagsType> Flags; + typedef short NodeID; + + private: + static const FlagsType PUBLIC_FLAGS = 0x00000000; + static const FlagsType PRIVATE_FLAGS = 0x00007F0F; + static const FlagsType COPY_FLAGS = 0x0000000F; + static const FlagsType SHARED = 0x00000001; + // Special control flags + /// Special timing-mode atomic snoop for multi-level coherence. + static const FlagsType EXPRESS_SNOOP = 0x00000002; + /// Does supplier have exclusive copy? + /// Useful for multi-level coherence. + static const FlagsType SUPPLY_EXCLUSIVE = 0x00000004; + // Snoop response flags + static const FlagsType MEM_INHIBIT = 0x00000008; + /// Are the 'addr' and 'size' fields valid? + static const FlagsType VALID_ADDR = 0x00000100; + static const FlagsType VALID_SIZE = 0x00000200; + /// Is the 'src' field valid? + static const FlagsType VALID_SRC = 0x00000400; + static const FlagsType VALID_DST = 0x00000800; + /// Is the data pointer set to a value that shouldn't be freed + /// when the packet is destroyed? + static const FlagsType STATIC_DATA = 0x00001000; + /// The data pointer points to a value that should be freed when + /// the packet is destroyed. + static const FlagsType DYNAMIC_DATA = 0x00002000; + /// the data pointer points to an array (thus delete []) needs to + /// be called on it rather than simply delete. + static const FlagsType ARRAY_DATA = 0x00004000; + + Flags flags; + + public: typedef MemCmd::Command Command; - /** The command field of the packet. */ + /// The command field of the packet. MemCmd cmd; - /** A pointer to the original request. */ + /// A pointer to the original request. RequestPtr req; private: - /** A pointer to the data being transfered. It can be differnt - * sizes at each level of the heirarchy so it belongs in the - * packet, not request. This may or may not be populated when a - * responder recieves the packet. If not populated it memory - * should be allocated. + /** + * A pointer to the data being transfered. It can be differnt + * sizes at each level of the heirarchy so it belongs in the + * packet, not request. This may or may not be populated when a + * responder recieves the packet. If not populated it memory should + * be allocated. */ PacketDataPtr data; - /** Is the data pointer set to a value that shouldn't be freed - * when the packet is destroyed? */ - bool staticData; - /** The data pointer points to a value that should be freed when - * the packet is destroyed. */ - bool dynamicData; - /** the data pointer points to an array (thus delete [] ) needs to - * be called on it rather than simply delete.*/ - bool arrayData; - - /** The address of the request. This address could be virtual or - * physical, depending on the system configuration. */ + /// The address of the request. This address could be virtual or + /// physical, depending on the system configuration. Addr addr; - /** The size of the request or transfer. */ + /// The size of the request or transfer. int size; - /** Device address (e.g., bus ID) of the source of the - * transaction. The source is not responsible for setting this - * field; it is set implicitly by the interconnect when the - * packet is first sent. */ - short src; + /** + * Device address (e.g., bus ID) of the source of the + * transaction. The source is not responsible for setting this + * field; it is set implicitly by the interconnect when the packet + * is first sent. + */ + NodeID src; - /** Device address (e.g., bus ID) of the destination of the - * transaction. The special value Broadcast indicates that the - * packet should be routed based on its address. This field is - * initialized in the constructor and is thus always valid - * (unlike * addr, size, and src). */ - short dest; + /** + * Device address (e.g., bus ID) of the destination of the + * transaction. The special value Broadcast indicates that the + * packet should be routed based on its address. This field is + * initialized in the constructor and is thus always valid (unlike + * addr, size, and src). + */ + NodeID dest; - /** The original value of the command field. Only valid when the + /** + * The original value of the command field. Only valid when the * current command field is an error condition; in that case, the * previous contents of the command field are copied here. This * field is *not* set on non-error responses. */ MemCmd origCmd; - /** Are the 'addr' and 'size' fields valid? */ - bool addrSizeValid; - /** Is the 'src' field valid? */ - bool srcValid; - bool destValid; - - enum Flag { - // Snoop response flags - MemInhibit, - Shared, - // Special control flags - /// Special timing-mode atomic snoop for multi-level coherence. - ExpressSnoop, - /// Does supplier have exclusive copy? - /// Useful for multi-level coherence. - SupplyExclusive, - NUM_PACKET_FLAGS - }; - - /** Status flags */ - std::bitset<NUM_PACKET_FLAGS> flags; - public: - - /** Used to calculate latencies for each packet.*/ + /// Used to calculate latencies for each packet. Tick time; - /** The time at which the packet will be fully transmitted */ + /// The time at which the packet will be fully transmitted Tick finishTime; - /** The time at which the first chunk of the packet will be transmitted */ + /// The time at which the first chunk of the packet will be transmitted Tick firstWordTime; - /** The special destination address indicating that the packet - * should be routed based on its address. */ - static const short Broadcast = -1; - - /** A virtual base opaque structure used to hold state associated - * with the packet but specific to the sending device (e.g., an - * MSHR). A pointer to this state is returned in the packet's - * response so that the sender can quickly look up the state - * needed to process it. A specific subclass would be derived - * from this to carry state specific to a particular sending - * device. */ - class SenderState : public FastAlloc { - public: + /// The special destination address indicating that the packet + /// should be routed based on its address. + static const NodeID Broadcast = -1; + + /** + * A virtual base opaque structure used to hold state associated + * with the packet but specific to the sending device (e.g., an + * MSHR). A pointer to this state is returned in the packet's + * response so that the sender can quickly look up the state + * needed to process it. A specific subclass would be derived + * from this to carry state specific to a particular sending + * device. + */ + struct SenderState + { virtual ~SenderState() {} }; @@ -304,15 +317,18 @@ class Packet : public FastAlloc, public Printable * Object used to maintain state of a PrintReq. The senderState * field of a PrintReq should always be of this type. */ - class PrintReqState : public SenderState { - /** An entry in the label stack. */ - class LabelStackEntry { - public: + class PrintReqState : public SenderState, public FastAlloc + { + private: + /** + * An entry in the label stack. + */ + struct LabelStackEntry + { const std::string label; std::string *prefix; bool labelPrinted; - LabelStackEntry(const std::string &_label, - std::string *_prefix); + LabelStackEntry(const std::string &_label, std::string *_prefix); }; typedef std::list<LabelStackEntry> LabelStack; @@ -327,35 +343,53 @@ class Packet : public FastAlloc, public Printable PrintReqState(std::ostream &os, int verbosity = 0); ~PrintReqState(); - /** Returns the current line prefix. */ + /** + * Returns the current line prefix. + */ const std::string &curPrefix() { return *curPrefixPtr; } - /** Push a label onto the label stack, and prepend the given + /** + * Push a label onto the label stack, and prepend the given * prefix string onto the current prefix. Labels will only be - * printed if an object within the label's scope is - * printed. */ + * printed if an object within the label's scope is printed. + */ void pushLabel(const std::string &lbl, const std::string &prefix = " "); - /** Pop a label off the label stack. */ + + /** + * Pop a label off the label stack. + */ void popLabel(); - /** Print all of the pending unprinted labels on the + + /** + * Print all of the pending unprinted labels on the * stack. Called by printObj(), so normally not called by - * users unless bypassing printObj(). */ + * users unless bypassing printObj(). + */ void printLabels(); - /** Print a Printable object to os, because it matched the - * address on a PrintReq. */ + + /** + * Print a Printable object to os, because it matched the + * address on a PrintReq. + */ void printObj(Printable *obj); }; - /** This packet's sender state. Devices should use dynamic_cast<> - * to cast to the state appropriate to the sender. */ + /** + * This packet's sender state. Devices should use dynamic_cast<> + * to cast to the state appropriate to the sender. The intent of + * this variable is to allow a device to attach extra information + * to a request. A response packet must return the sender state + * that was attached to the original request (even if a new packet + * is created). + */ SenderState *senderState; - /** Return the string name of the cmd field (for debugging and - * tracing). */ + /// Return the string name of the cmd field (for debugging and + /// tracing). const std::string &cmdString() const { return cmd.toString(); } - /** Return the index of this command. */ + /// Return the index of this command. inline int cmdToIndex() const { return cmd.toInt(); } bool isRead() const { return cmd.isRead(); } @@ -372,108 +406,134 @@ class Packet : public FastAlloc, public Printable bool isPrint() const { return cmd.isPrint(); } // Snoop flags - void assertMemInhibit() { flags[MemInhibit] = true; } - bool memInhibitAsserted() { return flags[MemInhibit]; } - void assertShared() { flags[Shared] = true; } - bool sharedAsserted() { return flags[Shared]; } + void assertMemInhibit() { flags.set(MEM_INHIBIT); } + bool memInhibitAsserted() { return flags.isSet(MEM_INHIBIT); } + void assertShared() { flags.set(SHARED); } + bool sharedAsserted() { return flags.isSet(SHARED); } // Special control flags - void setExpressSnoop() { flags[ExpressSnoop] = true; } - bool isExpressSnoop() { return flags[ExpressSnoop]; } - void setSupplyExclusive() { flags[SupplyExclusive] = true; } - bool isSupplyExclusive() { return flags[SupplyExclusive]; } + void setExpressSnoop() { flags.set(EXPRESS_SNOOP); } + bool isExpressSnoop() { return flags.isSet(EXPRESS_SNOOP); } + void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); } + bool isSupplyExclusive() { return flags.isSet(SUPPLY_EXCLUSIVE); } // Network error conditions... encapsulate them as methods since // their encoding keeps changing (from result field to command // field, etc.) - void setNacked() { assert(isResponse()); cmd = MemCmd::NetworkNackError; } - void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; } - bool wasNacked() { return cmd == MemCmd::NetworkNackError; } - bool hadBadAddress() { return cmd == MemCmd::BadAddressError; } + void + setNacked() + { + assert(isResponse()); + cmd = MemCmd::NetworkNackError; + } + + void + setBadAddress() + { + assert(isResponse()); + cmd = MemCmd::BadAddressError; + } + + bool wasNacked() const { return cmd == MemCmd::NetworkNackError; } + bool hadBadAddress() const { return cmd == MemCmd::BadAddressError; } void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; } - bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN } - - /** Accessor function that returns the source index of the packet. */ - short getSrc() const { assert(srcValid); return src; } - void setSrc(short _src) { src = _src; srcValid = true; } - /** Reset source field, e.g. to retransmit packet on different bus. */ - void clearSrc() { srcValid = false; } - - /** Accessor function that returns the destination index of - the packet. */ - short getDest() const { assert(destValid); return dest; } - void setDest(short _dest) { dest = _dest; destValid = true; } - - Addr getAddr() const { assert(addrSizeValid); return addr; } - int getSize() const { assert(addrSizeValid); return size; } - Addr getOffset(int blkSize) const { return addr & (Addr)(blkSize - 1); } - - /** Constructor. Note that a Request object must be constructed - * first, but the Requests's physical address and size fields - * need not be valid. The command and destination addresses - * must be supplied. */ - Packet(Request *_req, MemCmd _cmd, short _dest) - : cmd(_cmd), req(_req), - data(NULL), staticData(false), dynamicData(false), arrayData(false), - addr(_req->paddr), size(_req->size), dest(_dest), - addrSizeValid(_req->validPaddr), srcValid(false), destValid(true), - flags(0), time(curTick), senderState(NULL) + /// Accessor function to get the source index of the packet. + NodeID getSrc() const { assert(flags.isSet(VALID_SRC)); return src; } + /// Accessor function to set the source index of the packet. + void setSrc(NodeID _src) { src = _src; flags.set(VALID_SRC); } + /// Reset source field, e.g. to retransmit packet on different bus. + void clearSrc() { flags.clear(VALID_SRC); } + + /// Accessor function for the destination index of the packet. + NodeID getDest() const { assert(flags.isSet(VALID_DST)); return dest; } + /// Accessor function to set the destination index of the packet. + void setDest(NodeID _dest) { dest = _dest; flags.set(VALID_DST); } + + Addr getAddr() const { assert(flags.isSet(VALID_ADDR)); return addr; } + int getSize() const { assert(flags.isSet(VALID_SIZE)); return size; } + Addr getOffset(int blkSize) const { return getAddr() & (Addr)(blkSize - 1); } + + /** + * Constructor. Note that a Request object must be constructed + * first, but the Requests's physical address and size fields need + * not be valid. The command and destination addresses must be + * supplied. + */ + Packet(Request *_req, MemCmd _cmd, NodeID _dest) + : flags(VALID_DST), cmd(_cmd), req(_req), data(NULL), + addr(_req->paddr), size(_req->size), dest(_dest), time(curTick), + senderState(NULL) { + if (req->flags.isSet(Request::VALID_PADDR)) + flags.set(VALID_ADDR|VALID_SIZE); } - /** Alternate constructor if you are trying to create a packet with - * a request that is for a whole block, not the address from the req. - * this allows for overriding the size/addr of the req.*/ - Packet(Request *_req, MemCmd _cmd, short _dest, int _blkSize) - : cmd(_cmd), req(_req), - data(NULL), staticData(false), dynamicData(false), arrayData(false), + /** + * Alternate constructor if you are trying to create a packet with + * a request that is for a whole block, not the address from the + * req. this allows for overriding the size/addr of the req. + */ + Packet(Request *_req, MemCmd _cmd, NodeID _dest, int _blkSize) + : flags(VALID_DST), cmd(_cmd), req(_req), data(NULL), addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize), dest(_dest), - addrSizeValid(_req->validPaddr), srcValid(false), destValid(true), - flags(0), time(curTick), senderState(NULL) + time(curTick), senderState(NULL) { + if (req->flags.isSet(Request::VALID_PADDR)) + flags.set(VALID_ADDR|VALID_SIZE); } - /** Alternate constructor for copying a packet. Copy all fields + /** + * Alternate constructor for copying a packet. Copy all fields * *except* if the original packet's data was dynamic, don't copy * that, as we can't guarantee that the new packet's lifetime is * less than that of the original packet. In this case the new - * packet should allocate its own data. */ - Packet(Packet *origPkt, bool clearFlags = false) - : cmd(origPkt->cmd), req(origPkt->req), - data(origPkt->staticData ? origPkt->data : NULL), - staticData(origPkt->staticData), - dynamicData(false), arrayData(false), - addr(origPkt->addr), size(origPkt->size), - src(origPkt->src), dest(origPkt->dest), - addrSizeValid(origPkt->addrSizeValid), - srcValid(origPkt->srcValid), destValid(origPkt->destValid), - flags(clearFlags ? 0 : origPkt->flags), - time(curTick), senderState(origPkt->senderState) + * packet should allocate its own data. + */ + Packet(Packet *pkt, bool clearFlags = false) + : cmd(pkt->cmd), req(pkt->req), + data(pkt->flags.isSet(STATIC_DATA) ? pkt->data : NULL), + addr(pkt->addr), size(pkt->size), src(pkt->src), dest(pkt->dest), + time(curTick), senderState(pkt->senderState) { + if (!clearFlags) + flags.set(pkt->flags & COPY_FLAGS); + + flags.set(pkt->flags & (VALID_ADDR|VALID_SIZE|VALID_SRC|VALID_DST)); + flags.set(pkt->flags & STATIC_DATA); } - /** Destructor. */ + /** + * clean up packet variables + */ ~Packet() - { if (staticData || dynamicData) deleteData(); } - - /** Reinitialize packet address and size from the associated - * Request object, and reset other fields that may have been - * modified by a previous transaction. Typically called when a - * statically allocated Request/Packet pair is reused for - * multiple transactions. */ - void reinitFromRequest() { - assert(req->validPaddr); + { + // If this is a request packet for which there's no response, + // delete the request object here, since the requester will + // never get the chance. + if (req && isRequest() && !needsResponse()) + delete req; + deleteData(); + } + + /** + * Reinitialize packet address and size from the associated + * Request object, and reset other fields that may have been + * modified by a previous transaction. Typically called when a + * statically allocated Request/Packet pair is reused for multiple + * transactions. + */ + void + reinitFromRequest() + { + assert(req->flags.isSet(Request::VALID_PADDR)); flags = 0; addr = req->paddr; size = req->size; time = req->time; - addrSizeValid = true; - if (dynamicData) { - deleteData(); - dynamicData = false; - arrayData = false; - } + + flags.set(VALID_ADDR|VALID_SIZE); + deleteData(); } /** @@ -482,23 +542,27 @@ class Packet : public FastAlloc, public Printable * destination fields are *not* modified, as is appropriate for * atomic accesses. */ - void makeResponse() + void + makeResponse() { assert(needsResponse()); assert(isRequest()); origCmd = cmd; cmd = cmd.responseCommand(); + dest = src; - destValid = srcValid; - srcValid = false; + flags.set(VALID_DST, flags.isSet(VALID_SRC)); + flags.clear(VALID_SRC); } - void makeAtomicResponse() + void + makeAtomicResponse() { makeResponse(); } - void makeTimingResponse() + void + makeTimingResponse() { makeResponse(); } @@ -526,10 +590,9 @@ class Packet : public FastAlloc, public Printable void dataStatic(T *p) { - if(dynamicData) - dynamicData = false; + assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA)); data = (PacketDataPtr)p; - staticData = true; + flags.set(STATIC_DATA); } /** @@ -540,10 +603,9 @@ class Packet : public FastAlloc, public Printable void dataDynamicArray(T *p) { - assert(!staticData && !dynamicData); + assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA)); data = (PacketDataPtr)p; - dynamicData = true; - arrayData = true; + flags.set(DYNAMIC_DATA|ARRAY_DATA); } /** @@ -554,33 +616,39 @@ class Packet : public FastAlloc, public Printable void dataDynamic(T *p) { - assert(!staticData && !dynamicData); + assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA)); data = (PacketDataPtr)p; - dynamicData = true; - arrayData = false; + flags.set(DYNAMIC_DATA); } - /** get a pointer to the data ptr. */ + /** + * get a pointer to the data ptr. + */ template <typename T> T* getPtr() { - assert(staticData || dynamicData); + assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); return (T*)data; } - /** return the value of what is pointed to in the packet. */ + /** + * return the value of what is pointed to in the packet. + */ template <typename T> T get(); - /** set the value in the data pointer to v. */ + /** + * set the value in the data pointer to v. + */ template <typename T> void set(T v); /** * Copy data into the packet from the provided pointer. */ - void setData(uint8_t *p) + void + setData(uint8_t *p) { std::memcpy(getPtr<uint8_t>(), p, getSize()); } @@ -589,7 +657,8 @@ class Packet : public FastAlloc, public Printable * Copy data into the packet from the provided block pointer, * which is aligned to the given block size. */ - void setDataFromBlock(uint8_t *blk_data, int blkSize) + void + setDataFromBlock(uint8_t *blk_data, int blkSize) { setData(blk_data + getOffset(blkSize)); } @@ -598,7 +667,8 @@ class Packet : public FastAlloc, public Printable * Copy data from the packet to the provided block pointer, which * is aligned to the given block size. */ - void writeData(uint8_t *p) + void + writeData(uint8_t *p) { std::memcpy(p, getPtr<uint8_t>(), getSize()); } @@ -606,7 +676,8 @@ class Packet : public FastAlloc, public Printable /** * Copy data from the packet to the memory at the provided pointer. */ - void writeDataToBlock(uint8_t *blk_data, int blkSize) + void + writeDataToBlock(uint8_t *blk_data, int blkSize) { writeData(blk_data + getOffset(blkSize)); } @@ -615,10 +686,32 @@ class Packet : public FastAlloc, public Printable * delete the data pointed to in the data pointer. Ok to call to * matter how data was allocted. */ - void deleteData(); + void + deleteData() + { + if (flags.isSet(ARRAY_DATA)) + delete [] data; + else if (flags.isSet(DYNAMIC_DATA)) + delete data; + + flags.clear(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA); + data = NULL; + } /** If there isn't data in the packet, allocate some. */ - void allocate(); + void + allocate() + { + if (data) { + assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); + return; + } + + assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA)); + flags.set(DYNAMIC_DATA|ARRAY_DATA); + data = new uint8_t[getSize()]; + } + /** * Check a functional request against a memory value represented @@ -633,29 +726,32 @@ class Packet : public FastAlloc, public Printable * Check a functional request against a memory value stored in * another packet (i.e. an in-transit request or response). */ - bool checkFunctional(PacketPtr otherPkt) { - return checkFunctional(otherPkt, - otherPkt->getAddr(), otherPkt->getSize(), - otherPkt->hasData() ? - otherPkt->getPtr<uint8_t>() : NULL); + bool + checkFunctional(PacketPtr other) + { + uint8_t *data = other->hasData() ? other->getPtr<uint8_t>() : NULL; + return checkFunctional(other, other->getAddr(), other->getSize(), + data); } /** * Push label for PrintReq (safe to call unconditionally). */ - void pushLabel(const std::string &lbl) { - if (isPrint()) { - dynamic_cast<PrintReqState*>(senderState)->pushLabel(lbl); - } + void + pushLabel(const std::string &lbl) + { + if (isPrint()) + safe_cast<PrintReqState*>(senderState)->pushLabel(lbl); } /** * Pop label for PrintReq (safe to call unconditionally). */ - void popLabel() { - if (isPrint()) { - dynamic_cast<PrintReqState*>(senderState)->popLabel(); - } + void + popLabel() + { + if (isPrint()) + safe_cast<PrintReqState*>(senderState)->popLabel(); } void print(std::ostream &o, int verbosity = 0, diff --git a/src/mem/packet_access.hh b/src/mem/packet_access.hh index d1edd00aa..f70d508b2 100644 --- a/src/mem/packet_access.hh +++ b/src/mem/packet_access.hh @@ -46,7 +46,7 @@ template <typename T> inline T Packet::get() { - assert(staticData || dynamicData); + assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); assert(sizeof(T) <= size); return TheISA::gtoh(*(T*)data); } @@ -56,6 +56,7 @@ template <typename T> inline void Packet::set(T v) { + assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); assert(sizeof(T) <= size); *(T*)data = TheISA::htog(v); } diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc index 54165f293..bdcbbfec3 100644 --- a/src/mem/page_table.cc +++ b/src/mem/page_table.cc @@ -87,6 +87,44 @@ PageTable::allocate(Addr vaddr, int64_t size) } } +void +PageTable::remap(Addr vaddr, int64_t size, Addr new_vaddr) +{ + assert(pageOffset(vaddr) == 0); + assert(pageOffset(new_vaddr) == 0); + + DPRINTF(MMU, "moving pages from vaddr %08p to %08p, size = %d\n", vaddr, + new_vaddr, size); + + for (; size > 0; size -= pageSize, vaddr += pageSize, new_vaddr += pageSize) { + PTableItr iter = pTable.find(vaddr); + + assert(iter != pTable.end()); + + pTable[new_vaddr] = pTable[vaddr]; + pTable.erase(vaddr); + pTable[new_vaddr].updateVaddr(new_vaddr); + updateCache(new_vaddr, pTable[new_vaddr]); + } +} + +void +PageTable::deallocate(Addr vaddr, int64_t size) +{ + assert(pageOffset(vaddr) == 0); + + DPRINTF(MMU, "Deallocating page: %#x-%#x\n", vaddr, vaddr+ size); + + for (; size > 0; size -= pageSize, vaddr += pageSize) { + PTableItr iter = pTable.find(vaddr); + + assert(iter != pTable.end()); + + pTable.erase(vaddr); + } + +} + bool PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry) { diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh index b8b52174c..d4101c6bf 100644 --- a/src/mem/page_table.hh +++ b/src/mem/page_table.hh @@ -80,6 +80,8 @@ class PageTable Addr pageOffset(Addr a) { return (a & offsetMask); } void allocate(Addr vaddr, int64_t size); + void remap(Addr vaddr, int64_t size, Addr new_vaddr); + void deallocate(Addr vaddr, int64_t size); /** * Lookup function @@ -91,11 +93,19 @@ class PageTable /** * Translate function * @param vaddr The virtual address. - * @return Physical address from translation. + * @param paddr Physical address from translation. + * @return True if translation exists */ bool translate(Addr vaddr, Addr &paddr); /** + * Simplified translate function (just check for translation) + * @param vaddr The virtual address. + * @return True if translation exists + */ + bool translate(Addr vaddr) { Addr dummy; return translate(vaddr, dummy); } + + /** * Perform a translation on the memory request, fills in paddr * field of req. * @param req The memory request. diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 3560fc670..16ff3de6d 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -41,6 +41,7 @@ #include "arch/isa_traits.hh" #include "base/misc.hh" +#include "base/random.hh" #include "config/full_system.hh" #include "mem/packet_access.hh" #include "mem/physical.hh" @@ -51,11 +52,16 @@ using namespace std; using namespace TheISA; PhysicalMemory::PhysicalMemory(const Params *p) - : MemObject(p), pmemAddr(NULL), lat(p->latency) + : MemObject(p), pmemAddr(NULL), pagePtr(0), + lat(p->latency), lat_var(p->latency_var), + cachedSize(params()->range.size()), cachedStart(params()->range.start) { if (params()->range.size() % TheISA::PageBytes != 0) panic("Memory Size not divisible by page size\n"); + if (params()->null) + return; + int map_flags = MAP_ANON | MAP_PRIVATE; pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(), PROT_READ | PROT_WRITE, map_flags, -1, 0); @@ -68,12 +74,6 @@ PhysicalMemory::PhysicalMemory(const Params *p) //If requested, initialize all the memory to 0 if (p->zero) memset(pmemAddr, 0, p->range.size()); - - pagePtr = 0; - - cachedSize = params()->range.size(); - cachedStart = params()->range.start; - } void @@ -116,7 +116,10 @@ PhysicalMemory::deviceBlockSize() Tick PhysicalMemory::calculateLatency(PacketPtr pkt) { - return lat; + Tick latency = lat; + if (lat_var != 0) + latency += random_mt.random<Tick>(0, lat_var); + return latency; } @@ -136,16 +139,16 @@ PhysicalMemory::trackLoadLocked(PacketPtr pkt) for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { if (i->matchesContext(req)) { - DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n", - req->getCpuNum(), req->getThreadNum(), paddr); + DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", + req->contextId(), paddr); i->addr = paddr; return; } } // no record for this xc: need to allocate a new one - DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n", - req->getCpuNum(), req->getThreadNum(), paddr); + DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", + req->contextId(), paddr); lockedAddrList.push_front(LockedAddr(req)); } @@ -180,14 +183,14 @@ PhysicalMemory::checkLockedAddrList(PacketPtr pkt) // it's a store conditional, and as far as the memory // system can tell, the requesting context's lock is // still valid. - DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n", - req->getCpuNum(), req->getThreadNum(), paddr); + DPRINTF(LLSC, "StCond success: context %d addr %#x\n", + req->contextId(), paddr); success = true; } // Get rid of our record of this lock and advance to next - DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n", - i->cpuNum, i->threadNum, paddr); + DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", + i->contextId, paddr); i = lockedAddrList.erase(i); } else { @@ -252,6 +255,8 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt) uint64_t condition_val64; uint32_t condition_val32; + if (!pmemAddr) + panic("Swap only works if there is real memory (i.e. null=False)"); assert(sizeof(IntReg) >= pkt->getSize()); overwrite_mem = true; @@ -282,11 +287,13 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt) if (pkt->isLocked()) { trackLoadLocked(pkt); } - memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); + if (pmemAddr) + memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); TRACE_PACKET("Read"); } else if (pkt->isWrite()) { if (writeOK(pkt)) { - memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); + if (pmemAddr) + memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); TRACE_PACKET("Write"); } } else if (pkt->isInvalidate()) { @@ -315,11 +322,13 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt) uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); if (pkt->isRead()) { - memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); + if (pmemAddr) + memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); TRACE_PACKET("Read"); pkt->makeAtomicResponse(); } else if (pkt->isWrite()) { - memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); + if (pmemAddr) + memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); TRACE_PACKET("Write"); pkt->makeAtomicResponse(); } else if (pkt->isPrint()) { @@ -374,7 +383,7 @@ PhysicalMemory::recvStatusChange(Port::Status status) PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, PhysicalMemory *_memory) - : SimpleTimingPort(_name), memory(_memory) + : SimpleTimingPort(_name, _memory), memory(_memory) { } void @@ -443,6 +452,9 @@ PhysicalMemory::drain(Event *de) void PhysicalMemory::serialize(ostream &os) { + if (!pmemAddr) + return; + gzFile compressedMem; string filename = name() + ".physmem"; @@ -475,6 +487,9 @@ PhysicalMemory::serialize(ostream &os) void PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) { + if (!pmemAddr) + return; + gzFile compressedMem; long *tempPage; long *pmem_current; @@ -482,7 +497,6 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) uint32_t bytesRead; const int chunkSize = 16384; - string filename; UNSERIALIZE_SCALAR(filename); diff --git a/src/mem/physical.hh b/src/mem/physical.hh index c3749bd5b..d18138ecd 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -89,21 +89,18 @@ class PhysicalMemory : public MemObject static Addr mask(Addr paddr) { return (paddr & ~Addr_Mask); } - Addr addr; // locked address - int cpuNum; // locking CPU - int threadNum; // locking thread ID within CPU + Addr addr; // locked address + int contextId; // locking hw context // check for matching execution context bool matchesContext(Request *req) { - return (cpuNum == req->getCpuNum() && - threadNum == req->getThreadNum()); + return (contextId == req->contextId()); } LockedAddr(Request *req) : addr(mask(req->getPaddr())), - cpuNum(req->getCpuNum()), - threadNum(req->getThreadNum()) + contextId(req->contextId()) { } }; @@ -146,6 +143,7 @@ class PhysicalMemory : public MemObject uint8_t *pmemAddr; int pagePtr; Tick lat; + Tick lat_var; std::vector<MemoryPort*> ports; typedef std::vector<MemoryPort*>::iterator PortIterator; diff --git a/src/mem/port.cc b/src/mem/port.cc index ce3f6c74b..a666c968b 100644 --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -39,17 +39,18 @@ #include "mem/mem_object.hh" #include "mem/port.hh" -class defaultPeerPortClass: public Port +class DefaultPeerPort : public Port { protected: void blowUp() { - fatal("Unconnected port!"); + fatal("%s: Unconnected port!", peer->name()); } public: - defaultPeerPortClass() : Port("default_port") - {} + DefaultPeerPort() + : Port("default_port", NULL) + { } bool recvTiming(PacketPtr) { @@ -84,16 +85,18 @@ class defaultPeerPortClass: public Port blowUp(); } - bool isDefaultPort() { return true; } + bool isDefaultPort() const { return true; } +}; -} defaultPeerPort; +DefaultPeerPort defaultPeerPort; -Port::Port() : peer(&defaultPeerPort), owner(NULL) +Port::Port(const std::string &_name, MemObject *_owner) + : EventManager(_owner), portName(_name), peer(&defaultPeerPort), + owner(_owner) { } -Port::Port(const std::string &_name, MemObject *_owner) : - portName(_name), peer(&defaultPeerPort), owner(_owner) +Port::~Port() { } @@ -101,10 +104,18 @@ void Port::setPeer(Port *port) { DPRINTF(Config, "setting peer to %s\n", port->name()); + peer = port; } void +Port::setOwner(MemObject *_owner) +{ + eventq = _owner->queue(); + owner = _owner; +} + +void Port::removeConn() { if (peer->getOwner()) diff --git a/src/mem/port.hh b/src/mem/port.hh index f66b566ea..1d9135ae6 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -47,6 +47,7 @@ #include "base/range.hh" #include "mem/packet.hh" #include "mem/request.hh" +#include "sim/eventq.hh" /** This typedef is used to clean up the parameter list of * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared @@ -58,6 +59,7 @@ typedef std::list<Range<Addr> > AddrRangeList; typedef std::list<Range<Addr> >::iterator AddrRangeIter; +class EventQueue; class MemObject; /** @@ -71,10 +73,9 @@ class MemObject; * Send accessor functions are being called from the device the port is * associated with, and it will call the peer recv. accessor function. */ -class Port +class Port : public EventManager { - private: - + protected: /** Descriptive name (for DPRINTF output) */ mutable std::string portName; @@ -87,9 +88,6 @@ class Port MemObject *owner; public: - - Port(); - /** * Constructor. * @@ -98,12 +96,12 @@ class Port * @param _owner Pointer to the MemObject that owns this port. * Will not necessarily be set. */ - Port(const std::string &_name, MemObject *_owner = NULL); + Port(const std::string &_name, MemObject *_owner); /** Return port name (for DPRINTF). */ const std::string &name() const { return portName; } - virtual ~Port() {}; + virtual ~Port(); // mey be better to use subclasses & RTTI? /** Holds the ports status. Currently just that a range recomputation needs @@ -122,7 +120,7 @@ class Port Port *getPeer() { return peer; } /** Function to set the owner of this port. */ - void setOwner(MemObject *_owner) { owner = _owner; } + void setOwner(MemObject *_owner); /** Function to return the owner of this port. */ MemObject *getOwner() { return owner; } @@ -131,7 +129,9 @@ class Port * demise. */ void removeConn(); - virtual bool isDefaultPort() { return false; } + virtual bool isDefaultPort() const { return false; } + + bool isConnected() { return peer && !peer->isDefaultPort(); } protected: diff --git a/src/mem/request.hh b/src/mem/request.hh index cc9c6b8bf..ee62ce771 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -39,247 +39,436 @@ #ifndef __MEM_REQUEST_HH__ #define __MEM_REQUEST_HH__ +#include <cassert> + #include "base/fast_alloc.hh" +#include "base/flags.hh" +#include "base/misc.hh" #include "sim/host.hh" #include "sim/core.hh" -#include <cassert> - class Request; typedef Request* RequestPtr; +class Request : public FastAlloc +{ + friend class Packet; -/** ASI information for this request if it exsits. */ -const uint32_t ASI_BITS = 0x000FF; -/** The request is a Load locked/store conditional. */ -const uint32_t LOCKED = 0x00100; -/** The virtual address is also the physical address. */ -const uint32_t PHYSICAL = 0x00200; -/** The request is an ALPHA VPTE pal access (hw_ld). */ -const uint32_t VPTE = 0x00400; -/** Use the alternate mode bits in ALPHA. */ -const uint32_t ALTMODE = 0x00800; -/** The request is to an uncacheable address. */ -const uint32_t UNCACHEABLE = 0x01000; -/** The request should not cause a page fault. */ -const uint32_t NO_FAULT = 0x02000; -/** The request should be prefetched into the exclusive state. */ -const uint32_t PF_EXCLUSIVE = 0x10000; -/** The request should be marked as LRU. */ -const uint32_t EVICT_NEXT = 0x20000; -/** The request should ignore unaligned access faults */ -const uint32_t NO_ALIGN_FAULT = 0x40000; -/** The request was an instruction read. */ -const uint32_t INST_READ = 0x80000; -/** This request is for a memory swap. */ -const uint32_t MEM_SWAP = 0x100000; -const uint32_t MEM_SWAP_COND = 0x200000; -/** The request should ignore unaligned access faults */ -const uint32_t NO_HALF_WORD_ALIGN_FAULT = 0x400000; + public: + typedef uint32_t FlagsType; + typedef ::Flags<FlagsType> Flags; + + /** ASI information for this request if it exists. */ + static const FlagsType ASI_BITS = 0x000000FF; + /** The request is a Load locked/store conditional. */ + static const FlagsType LOCKED = 0x00000100; + /** The virtual address is also the physical address. */ + static const FlagsType PHYSICAL = 0x00000200; + /** The request is an ALPHA VPTE pal access (hw_ld). */ + static const FlagsType VPTE = 0x00000400; + /** Use the alternate mode bits in ALPHA. */ + static const FlagsType ALTMODE = 0x00000800; + /** The request is to an uncacheable address. */ + static const FlagsType UNCACHEABLE = 0x00001000; + /** The request should not cause a page fault. */ + static const FlagsType NO_FAULT = 0x00002000; + /** The request should not cause a memory access. */ + static const FlagsType NO_ACCESS = 0x00004000; + /** The request should be prefetched into the exclusive state. */ + static const FlagsType PF_EXCLUSIVE = 0x00010000; + /** The request should be marked as LRU. */ + static const FlagsType EVICT_NEXT = 0x00020000; + /** The request should ignore unaligned access faults */ + static const FlagsType NO_ALIGN_FAULT = 0x00040000; + /** The request was an instruction read. */ + static const FlagsType INST_READ = 0x00080000; + /** This request is for a memory swap. */ + static const FlagsType MEM_SWAP = 0x00100000; + static const FlagsType MEM_SWAP_COND = 0x00200000; + /** The request should ignore unaligned access faults */ + static const FlagsType NO_HALF_WORD_ALIGN_FAULT = 0x00400000; + /** This request is to a memory mapped register. */ + static const FlagsType MMAPED_IPR = 0x00800000; + private: + static const FlagsType PUBLIC_FLAGS = 0x00FF3FFF; + static const FlagsType PRIVATE_FLAGS = 0xFF000000; + + /** Whether or not the size is valid. */ + static const FlagsType VALID_SIZE = 0x01000000; + /** Whether or not paddr is valid (has been written yet). */ + static const FlagsType VALID_PADDR = 0x02000000; + /** Whether or not the vaddr & asid are valid. */ + static const FlagsType VALID_VADDR = 0x04000000; + /** Whether or not the pc is valid. */ + static const FlagsType VALID_PC = 0x10000000; + /** Whether or not the context ID is valid. */ + static const FlagsType VALID_CONTEXT_ID = 0x20000000; + static const FlagsType VALID_THREAD_ID = 0x40000000; + /** Whether or not the sc result is valid. */ + static const FlagsType VALID_EXTRA_DATA = 0x80000000; -class Request : public FastAlloc -{ private: /** * The physical address of the request. Valid only if validPaddr - * is set. */ + * is set. + */ Addr paddr; /** * The size of the request. This field must be set when vaddr or * paddr is written via setVirt() or setPhys(), so it is always - * valid as long as one of the address fields is valid. */ + * valid as long as one of the address fields is valid. + */ int size; /** Flag structure for the request. */ - uint32_t flags; + Flags flags; /** * The time this request was started. Used to calculate * latencies. This field is set to curTick any time paddr or vaddr - * is written. */ + * is written. + */ Tick time; /** The address space ID. */ int asid; - /** This request is to a memory mapped register. */ - bool mmapedIpr; - /** The virtual address of the request. */ Addr vaddr; - /** Extra data for the request, such as the return value of + /** + * Extra data for the request, such as the return value of * store conditional or the compare value for a CAS. */ uint64_t extraData; - /** The cpu number (for statistics, typically). */ - int cpuNum; - /** The requesting thread id (for statistics, typically). */ - int threadNum; + /** The context ID (for statistics, typically). */ + int _contextId; + /** The thread ID (id within this CPU) */ + int _threadId; /** program counter of initiating access; for tracing/debugging */ Addr pc; - /** Whether or not paddr is valid (has been written yet). */ - bool validPaddr; - /** Whether or not the asid & vaddr are valid. */ - bool validAsidVaddr; - /** Whether or not the sc result is valid. */ - bool validExData; - /** Whether or not the cpu number & thread ID are valid. */ - bool validCpuAndThreadNums; - /** Whether or not the pc is valid. */ - bool validPC; - public: /** Minimal constructor. No fields are initialized. */ Request() - : validPaddr(false), validAsidVaddr(false), - validExData(false), validCpuAndThreadNums(false), validPC(false) {} /** * Constructor for physical (e.g. device) requests. Initializes * just physical address, size, flags, and timestamp (to curTick). - * These fields are adequate to perform a request. */ - Request(Addr _paddr, int _size, int _flags) - : validCpuAndThreadNums(false) - { setPhys(_paddr, _size, _flags); } + * These fields are adequate to perform a request. + */ + Request(Addr paddr, int size, Flags flags) + { + setPhys(paddr, size, flags); + } - Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc, - int _cpuNum, int _threadNum) + Request(int asid, Addr vaddr, int size, Flags flags, Addr pc, + int cid, int tid) { - setThreadContext(_cpuNum, _threadNum); - setVirt(_asid, _vaddr, _size, _flags, _pc); + setThreadContext(cid, tid); + setVirt(asid, vaddr, size, flags, pc); } ~Request() {} // for FastAlloc /** - * Set up CPU and thread numbers. */ - void setThreadContext(int _cpuNum, int _threadNum) + * Set up CPU and thread numbers. + */ + void + setThreadContext(int context_id, int thread_id) { - cpuNum = _cpuNum; - threadNum = _threadNum; - validCpuAndThreadNums = true; + _contextId = context_id; + _threadId = thread_id; + flags.set(VALID_CONTEXT_ID|VALID_THREAD_ID); } /** * Set up a physical (e.g. device) request in a previously - * allocated Request object. */ - void setPhys(Addr _paddr, int _size, int _flags) + * allocated Request object. + */ + void + setPhys(Addr _paddr, int _size, Flags _flags) { + assert(_size >= 0); paddr = _paddr; size = _size; - flags = _flags; time = curTick; - validPaddr = true; - validAsidVaddr = false; - validPC = false; - validExData = false; - mmapedIpr = false; + + flags.set(VALID_PADDR|VALID_SIZE); + flags.clear(VALID_VADDR|VALID_PC|VALID_EXTRA_DATA|MMAPED_IPR); + flags.update(_flags, PUBLIC_FLAGS); } /** * Set up a virtual (e.g., CPU) request in a previously - * allocated Request object. */ - void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc) + * allocated Request object. + */ + void + setVirt(int _asid, Addr _vaddr, int _size, Flags _flags, Addr _pc) { + assert(_size >= 0); asid = _asid; vaddr = _vaddr; size = _size; - flags = _flags; pc = _pc; time = curTick; - validPaddr = false; - validAsidVaddr = true; - validPC = true; - validExData = false; - mmapedIpr = false; + + flags.set(VALID_VADDR|VALID_SIZE|VALID_PC); + flags.clear(VALID_PADDR|VALID_EXTRA_DATA|MMAPED_IPR); + flags.update(_flags, PUBLIC_FLAGS); } - /** Set just the physical address. This should only be used to + /** + * Set just the physical address. This should only be used to * record the result of a translation, and thus the vaddr must be * valid before this method is called. Otherwise, use setPhys() * to guarantee that the size and flags are also set. */ - void setPaddr(Addr _paddr) + void + setPaddr(Addr _paddr) { - assert(validAsidVaddr); + assert(flags.isSet(VALID_VADDR)); paddr = _paddr; - validPaddr = true; + flags.set(VALID_PADDR); } - /** Accessor for paddr. */ - Addr getPaddr() { assert(validPaddr); return paddr; } + /** + * Generate two requests as if this request had been split into two + * pieces. The original request can't have been translated already. + */ + void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2) + { + assert(flags.isSet(VALID_VADDR)); + assert(flags.noneSet(VALID_PADDR)); + assert(split_addr > vaddr && split_addr < vaddr + size); + req1 = new Request; + *req1 = *this; + req2 = new Request; + *req2 = *this; + req1->size = split_addr - vaddr; + req2->vaddr = split_addr; + req2->size = size - req1->size; + } + + /** + * Accessor for paddr. + */ + Addr + getPaddr() + { + assert(flags.isSet(VALID_PADDR)); + return paddr; + } + + /** + * Accessor for size. + */ + int + getSize() + { + assert(flags.isSet(VALID_SIZE)); + return size; + } - /** Accessor for size. */ - int getSize() { assert(validPaddr || validAsidVaddr); return size; } /** Accessor for time. */ - Tick getTime() { assert(validPaddr || validAsidVaddr); return time; } + Tick + getTime() + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + return time; + } + + void + setTime(Tick when) + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + time = when; + } + + /** Accessor for flags. */ + Flags + getFlags() + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + return flags & PUBLIC_FLAGS; + } + + Flags + anyFlags(Flags _flags) + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + assert(_flags.noneSet(~PUBLIC_FLAGS)); + return flags.isSet(_flags); + } + + Flags + allFlags(Flags _flags) + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + assert(_flags.noneSet(~PUBLIC_FLAGS)); + return flags.allSet(_flags); + } /** Accessor for flags. */ - uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; } - /** Accessor for paddr. */ - void setFlags(uint32_t _flags) - { assert(validPaddr || validAsidVaddr); flags = _flags; } + void + setFlags(Flags _flags) + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + assert(_flags.noneSet(~PUBLIC_FLAGS)); + flags.set(_flags); + } + + void + clearFlags(Flags _flags) + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + assert(_flags.noneSet(~PUBLIC_FLAGS)); + flags.clear(_flags); + } + + void + clearFlags() + { + assert(flags.isSet(VALID_PADDR|VALID_VADDR)); + flags.clear(PUBLIC_FLAGS); + } /** Accessor function for vaddr.*/ - Addr getVaddr() { assert(validAsidVaddr); return vaddr; } + Addr + getVaddr() + { + assert(flags.isSet(VALID_VADDR)); + return vaddr; + } /** Accessor function for asid.*/ - int getAsid() { assert(validAsidVaddr); return asid; } + int + getAsid() + { + assert(flags.isSet(VALID_VADDR)); + return asid; + } /** Accessor function for asi.*/ - uint8_t getAsi() { assert(validAsidVaddr); return flags & ASI_BITS; } + uint8_t + getAsi() + { + assert(flags.isSet(VALID_VADDR)); + return flags & ASI_BITS; + } /** Accessor function for asi.*/ - void setAsi(uint8_t a) - { assert(validAsidVaddr); flags = (flags & ~ASI_BITS) | a; } + void + setAsi(uint8_t a) + { + assert(flags.isSet(VALID_VADDR)); + flags.update(a, ASI_BITS); + } /** Accessor function for asi.*/ - bool isMmapedIpr() { assert(validPaddr); return mmapedIpr; } + bool + isMmapedIpr() + { + assert(flags.isSet(VALID_PADDR)); + return flags.isSet(MMAPED_IPR); + } /** Accessor function for asi.*/ - void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; } + void + setMmapedIpr(bool r) + { + assert(VALID_VADDR); + flags.set(MMAPED_IPR); + } /** Accessor function to check if sc result is valid. */ - bool extraDataValid() { return validExData; } + bool + extraDataValid() + { + return flags.isSet(VALID_EXTRA_DATA); + } + /** Accessor function for store conditional return value.*/ - uint64_t getExtraData() { assert(validExData); return extraData; } + uint64_t + getExtraData() const + { + assert(flags.isSet(VALID_EXTRA_DATA)); + return extraData; + } + /** Accessor function for store conditional return value.*/ - void setExtraData(uint64_t _extraData) - { extraData = _extraData; validExData = true; } + void + setExtraData(uint64_t _extraData) + { + extraData = _extraData; + flags.set(VALID_EXTRA_DATA); + } - /** Accessor function for cpu number.*/ - int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; } - /** Accessor function for thread number.*/ - int getThreadNum() { assert(validCpuAndThreadNums); return threadNum; } + bool + hasContextId() const + { + return flags.isSet(VALID_CONTEXT_ID); + } - /** Accessor function for pc.*/ - Addr getPC() { assert(validPC); return pc; } + /** Accessor function for context ID.*/ + int + contextId() const + { + assert(flags.isSet(VALID_CONTEXT_ID)); + return _contextId; + } - /** Accessor Function to Check Cacheability. */ - bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; } + /** Accessor function for thread ID. */ + int + threadId() const + { + assert(flags.isSet(VALID_THREAD_ID)); + return _threadId; + } - bool isInstRead() { return (getFlags() & INST_READ) != 0; } + bool + hasPC() const + { + return flags.isSet(VALID_PC); + } - bool isLocked() { return (getFlags() & LOCKED) != 0; } + /** Accessor function for pc.*/ + Addr + getPC() const + { + assert(flags.isSet(VALID_PC)); + return pc; + } + + /** Accessor Function to Check Cacheability. */ + bool isUncacheable() const { return flags.isSet(UNCACHEABLE); } + bool isInstRead() const { return flags.isSet(INST_READ); } + bool isLocked() const { return flags.isSet(LOCKED); } + bool isSwap() const { return flags.isSet(MEM_SWAP|MEM_SWAP_COND); } + bool isCondSwap() const { return flags.isSet(MEM_SWAP_COND); } + + bool + isMisaligned() const + { + if (flags.isSet(NO_ALIGN_FAULT)) + return false; - bool isSwap() { return (getFlags() & MEM_SWAP || - getFlags() & MEM_SWAP_COND); } + if ((vaddr & 0x1)) + return true; - bool isCondSwap() { return (getFlags() & MEM_SWAP_COND) != 0; } + if (flags.isSet(NO_HALF_WORD_ALIGN_FAULT)) + return false; - bool inline isMisaligned() {return (!(getFlags() & NO_ALIGN_FAULT) && - ((vaddr & 1) || - (!(getFlags() & NO_HALF_WORD_ALIGN_FAULT) - && (vaddr & 0x2))));} + if ((vaddr & 0x2)) + return true; - friend class Packet; + return false; + } }; #endif // __MEM_REQUEST_HH__ diff --git a/src/mem/tport.cc b/src/mem/tport.cc index 9fa27046b..f937eeb32 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -30,6 +30,21 @@ #include "mem/tport.hh" +using namespace std; + +SimpleTimingPort::SimpleTimingPort(string pname, MemObject *_owner) + : Port(pname, _owner), sendEvent(0), drainEvent(NULL), + waitingOnRetry(false) +{ + sendEvent = new EventWrapper<SimpleTimingPort, + &SimpleTimingPort::processSendEvent>(this); +} + +SimpleTimingPort::~SimpleTimingPort() +{ + delete sendEvent; +} + bool SimpleTimingPort::checkFunctional(PacketPtr pkt) { @@ -65,7 +80,6 @@ SimpleTimingPort::recvTiming(PacketPtr pkt) // code to hanldle nacks here, but I'm pretty sure it didn't work // correctly with the drain code, so that would need to be fixed // if we ever added it back. - assert(pkt->isRequest()); if (pkt->memInhibitAsserted()) { // snooper will supply based on copy of packet @@ -83,7 +97,6 @@ SimpleTimingPort::recvTiming(PacketPtr pkt) assert(pkt->isResponse()); schedSendTiming(pkt, curTick + latency); } else { - delete pkt->req; delete pkt; } @@ -104,11 +117,6 @@ SimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when) return; } - // list is non-empty and this is not the head, so event should - // already be scheduled - assert(waitingOnRetry || - (sendEvent->scheduled() && sendEvent->when() <= when)); - // list is non-empty & this belongs at the end if (when >= transmitList.back().tick) { transmitList.push_back(DeferredPacket(when, pkt)); @@ -144,7 +152,7 @@ SimpleTimingPort::sendDeferredPacket() if (success) { if (!transmitList.empty() && !sendEvent->scheduled()) { Tick time = transmitList.front().tick; - sendEvent->schedule(time <= curTick ? curTick+1 : time); + schedule(sendEvent, time <= curTick ? curTick+1 : time); } if (transmitList.empty() && drainEvent) { diff --git a/src/mem/tport.hh b/src/mem/tport.hh index d0f1be425..7dfe60b72 100644 --- a/src/mem/tport.hh +++ b/src/mem/tport.hh @@ -85,9 +85,6 @@ class SimpleTimingPort : public Port * When the event time expires it attempts to send the packet. * If it cannot, the packet sent when recvRetry() is called. **/ - typedef EventWrapper<SimpleTimingPort, &SimpleTimingPort::processSendEvent> - SendEvent; - Event *sendEvent; /** If we need to drain, keep the drain event around until we're done @@ -108,7 +105,8 @@ class SimpleTimingPort : public Port Tick deferredPacketReadyTime() { return transmitList.empty() ? MaxTick : transmitList.front().tick; } - void schedSendEvent(Tick when) + void + schedSendEvent(Tick when) { if (waitingOnRetry) { assert(!sendEvent->scheduled()); @@ -116,9 +114,9 @@ class SimpleTimingPort : public Port } if (!sendEvent->scheduled()) { - sendEvent->schedule(when); + schedule(sendEvent, when); } else if (sendEvent->when() > when) { - sendEvent->reschedule(when); + reschedule(sendEvent, when); } } @@ -154,15 +152,8 @@ class SimpleTimingPort : public Port public: - - SimpleTimingPort(std::string pname, MemObject *_owner = NULL) - : Port(pname, _owner), - sendEvent(new SendEvent(this)), - drainEvent(NULL), - waitingOnRetry(false) - {} - - ~SimpleTimingPort() { delete sendEvent; } + SimpleTimingPort(std::string pname, MemObject *_owner); + ~SimpleTimingPort(); /** Hook for draining timing accesses from the system. The * associated SimObject's drain() functions should be implemented diff --git a/src/mem/vport.cc b/src/mem/vport.cc index 6cc4d9ca9..15be45c2a 100644 --- a/src/mem/vport.cc +++ b/src/mem/vport.cc @@ -75,23 +75,18 @@ void CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) { uint8_t *dst = (uint8_t *)dest; - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); vp->readBlob(src, dst, cplen); - - tc->delVirtPort(vp); - } void CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) { uint8_t *src = (uint8_t *)source; - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); vp->writeBlob(dest, src, cplen); - - tc->delVirtPort(vp); } void @@ -99,25 +94,23 @@ CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) { int len = 0; char *start = dst; - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); do { vp->readBlob(vaddr++, (uint8_t*)dst++, 1); } while (len < maxlen && start[len++] != 0 ); - tc->delVirtPort(vp); dst[len] = 0; } void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) { - VirtualPort *vp = tc->getVirtPort(tc); + VirtualPort *vp = tc->getVirtPort(); for (ChunkGenerator gen(vaddr, strlen(src), TheISA::PageBytes); !gen.done(); gen.next()) { vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); src += gen.size(); } - tc->delVirtPort(vp); } diff --git a/src/python/SConscript b/src/python/SConscript index b39c9ea9c..a767545ec 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -34,20 +34,28 @@ Import('*') Source('swig/pyevent.cc') Source('swig/pyobject.cc') +PySource('', 'importer.py') PySource('m5', 'm5/__init__.py') PySource('m5', 'm5/SimObject.py') -PySource('m5', 'm5/attrdict.py') +PySource('m5', 'm5/config.py') PySource('m5', 'm5/convert.py') +PySource('m5', 'm5/core.py') +PySource('m5', 'm5/debug.py') PySource('m5', 'm5/event.py') PySource('m5', 'm5/main.py') -PySource('m5', 'm5/multidict.py') +PySource('m5', 'm5/options.py') PySource('m5', 'm5/params.py') PySource('m5', 'm5/proxy.py') PySource('m5', 'm5/simulate.py') PySource('m5', 'm5/smartdict.py') PySource('m5', 'm5/stats.py') PySource('m5', 'm5/ticks.py') -PySource('m5', 'm5/util.py') +PySource('m5', 'm5/trace.py') +PySource('m5.util', 'm5/util/__init__.py') +PySource('m5.util', 'm5/util/attrdict.py') +PySource('m5.util', 'm5/util/jobfile.py') +PySource('m5.util', 'm5/util/misc.py') +PySource('m5.util', 'm5/util/multidict.py') SwigSource('m5.internal', 'swig/core.i') SwigSource('m5.internal', 'swig/debug.i') diff --git a/src/python/generate.py b/src/python/generate.py deleted file mode 100644 index eead6ff5d..000000000 --- a/src/python/generate.py +++ /dev/null @@ -1,529 +0,0 @@ -# Copyright (c) 2004-2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert - -import imp -import py_compile -import sys -import zipfile - -from os.path import basename -from os.path import exists - -class DictImporter(object): - '''This importer takes a dictionary of arbitrary module names that - map to arbitrary filenames.''' - def __init__(self, modules, build_env): - self.modules = modules - self.installed = set() - self.build_env = build_env - - def __del__(self): - self.unload() - - def unload(self): - import sys - for module in self.installed: - del sys.modules[module] - self.installed = set() - - def find_module(self, fullname, path): - if fullname == '__scons': - return self - - if fullname == 'm5.objects': - return self - - if fullname.startswith('m5.internal'): - return None - - if fullname in self.modules and exists(self.modules[fullname]): - return self - - return None - - def load_module(self, fullname): - mod = imp.new_module(fullname) - sys.modules[fullname] = mod - self.installed.add(fullname) - - mod.__loader__ = self - if fullname == 'm5.objects': - mod.__path__ = fullname.split('.') - return mod - - if fullname == '__scons': - mod.__dict__['m5_build_env'] = self.build_env - return mod - - srcfile = self.modules[fullname] - if basename(srcfile) == '__init__.py': - mod.__path__ = fullname.split('.') - mod.__file__ = srcfile - - exec file(srcfile, 'r') in mod.__dict__ - - return mod - -class ordered_dict(dict): - def keys(self): - keys = super(ordered_dict, self).keys() - keys.sort() - return keys - - def values(self): - return [ self[key] for key in self.keys() ] - - def items(self): - return [ (key,self[key]) for key in self.keys() ] - - def iterkeys(self): - for key in self.keys(): - yield key - - def itervalues(self): - for value in self.values(): - yield value - - def iteritems(self): - for key,value in self.items(): - yield key, value - -class Generate(object): - def __init__(self, py_sources, sim_objects, build_env): - self.py_sources = py_sources - self.py_modules = {} - for source in py_sources: - self.py_modules[source.modpath] = source.srcpath - - importer = DictImporter(self.py_modules, build_env) - - # install the python importer so we can grab stuff from the source - # tree itself. - sys.meta_path[0:0] = [ importer ] - - import m5 - self.m5 = m5 - - # import all sim objects so we can populate the all_objects list - # make sure that we're working with a list, then let's sort it - sim_objects = list(sim_objects) - sim_objects.sort() - for simobj in sim_objects: - exec('from m5.objects import %s' % simobj) - - # we need to unload all of the currently imported modules so that they - # will be re-imported the next time the sconscript is run - importer.unload() - sys.meta_path.remove(importer) - - self.sim_objects = m5.SimObject.allClasses - self.enums = m5.params.allEnums - - self.params = {} - for name,obj in self.sim_objects.iteritems(): - for param in obj._params.local.values(): - if not hasattr(param, 'swig_decl'): - continue - pname = param.ptype_str - if pname not in self.params: - self.params[pname] = param - - def createSimObjectParam(self, target, source, env): - assert len(target) == 1 and len(source) == 1 - - hh_file = file(target[0].abspath, 'w') - name = str(source[0].get_contents()) - obj = self.sim_objects[name] - - print >>hh_file, obj.cxx_decl() - - # Generate Python file containing a dict specifying the current - # build_env flags. - def makeDefinesPyFile(self, target, source, env): - f = file(str(target[0]), 'w') - print >>f, "m5_build_env = ", source[0] - f.close() - - # Generate python file containing info about the M5 source code - def makeInfoPyFile(self, target, source, env): - f = file(str(target[0]), 'w') - for src in source: - data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) - print >>f, "%s = %s" % (src, repr(data)) - f.close() - - # Generate the __init__.py file for m5.objects - def makeObjectsInitFile(self, target, source, env): - f = file(str(target[0]), 'w') - print >>f, 'from params import *' - print >>f, 'from m5.SimObject import *' - for module in source: - print >>f, 'from %s import *' % module.get_contents() - f.close() - - def createSwigParam(self, target, source, env): - assert len(target) == 1 and len(source) == 1 - - i_file = file(target[0].abspath, 'w') - name = str(source[0].get_contents()) - param = self.params[name] - - for line in param.swig_decl(): - print >>i_file, line - - def createEnumStrings(self, target, source, env): - assert len(target) == 1 and len(source) == 1 - - cc_file = file(target[0].abspath, 'w') - name = str(source[0].get_contents()) - obj = self.enums[name] - - print >>cc_file, obj.cxx_def() - cc_file.close() - - def createEnumParam(self, target, source, env): - assert len(target) == 1 and len(source) == 1 - - hh_file = file(target[0].abspath, 'w') - name = str(source[0].get_contents()) - obj = self.enums[name] - - print >>hh_file, obj.cxx_decl() - - def buildParams(self, target, source, env): - names = [ s.get_contents() for s in source ] - objs = [ self.sim_objects[name] for name in names ] - out = file(target[0].abspath, 'w') - - ordered_objs = [] - obj_seen = set() - def order_obj(obj): - name = str(obj) - if name in obj_seen: - return - - obj_seen.add(name) - if str(obj) != 'SimObject': - order_obj(obj.__bases__[0]) - - ordered_objs.append(obj) - - for obj in objs: - order_obj(obj) - - enums = set() - predecls = [] - pd_seen = set() - - def add_pds(*pds): - for pd in pds: - if pd not in pd_seen: - predecls.append(pd) - pd_seen.add(pd) - - for obj in ordered_objs: - params = obj._params.local.values() - for param in params: - ptype = param.ptype - if issubclass(ptype, self.m5.params.Enum): - if ptype not in enums: - enums.add(ptype) - pds = param.swig_predecls() - if isinstance(pds, (list, tuple)): - add_pds(*pds) - else: - add_pds(pds) - - print >>out, '%module params' - - print >>out, '%{' - for obj in ordered_objs: - print >>out, '#include "params/%s.hh"' % obj - print >>out, '%}' - - for pd in predecls: - print >>out, pd - - enums = list(enums) - enums.sort() - for enum in enums: - print >>out, '%%include "enums/%s.hh"' % enum.__name__ - print >>out - - for obj in ordered_objs: - if obj.swig_objdecls: - for decl in obj.swig_objdecls: - print >>out, decl - continue - - code = '' - base = obj.get_base() - - code += '// stop swig from creating/wrapping default ctor/dtor\n' - code += '%%nodefault %s;\n' % obj.cxx_class - code += 'class %s ' % obj.cxx_class - if base: - code += ': public %s' % base - code += ' {};\n' - - klass = obj.cxx_class; - if hasattr(obj, 'cxx_namespace'): - new_code = 'namespace %s {\n' % obj.cxx_namespace - new_code += code - new_code += '}\n' - code = new_code - klass = '%s::%s' % (obj.cxx_namespace, klass) - - print >>out, code - - for obj in ordered_objs: - print >>out, '%%include "params/%s.hh"' % obj - - def makeSwigInit(self, target, source, env): - f = file(str(target[0]), 'w') - print >>f, 'extern "C" {' - for module in source: - print >>f, ' void init_%s();' % module.get_contents() - print >>f, '}' - print >>f, 'void init_swig() {' - for module in source: - print >>f, ' init_%s();' % module.get_contents() - print >>f, '}' - f.close() - - def compilePyFile(self, target, source, env): - '''Action function to compile a .py into a .pyc''' - py_compile.compile(str(source[0]), str(target[0])) - - def buildPyZip(self, target, source, env): - '''Action function to build the zip archive. Uses the - PyZipFile module included in the standard Python library.''' - - py_compiled = {} - for s in self.py_sources: - compname = str(s.compiled) - assert compname not in py_compiled - py_compiled[compname] = s - - zf = zipfile.ZipFile(str(target[0]), 'w') - for s in source: - zipname = str(s) - arcname = py_compiled[zipname].arcname - zf.write(zipname, arcname) - zf.close() - - def traceFlagsPy(self, target, source, env): - assert(len(target) == 1) - - f = file(str(target[0]), 'w') - - allFlags = [] - for s in source: - val = eval(s.get_contents()) - allFlags.append(val) - - print >>f, 'baseFlags = [' - for flag, compound, desc in allFlags: - if not compound: - print >>f, " '%s'," % flag - print >>f, " ]" - print >>f - - print >>f, 'compoundFlags = [' - print >>f, " 'All'," - for flag, compound, desc in allFlags: - if compound: - print >>f, " '%s'," % flag - print >>f, " ]" - print >>f - - print >>f, "allFlags = frozenset(baseFlags + compoundFlags)" - print >>f - - print >>f, 'compoundFlagMap = {' - all = tuple([flag for flag,compound,desc in allFlags if not compound]) - print >>f, " 'All' : %s," % (all, ) - for flag, compound, desc in allFlags: - if compound: - print >>f, " '%s' : %s," % (flag, compound) - print >>f, " }" - print >>f - - print >>f, 'flagDescriptions = {' - print >>f, " 'All' : 'All flags'," - for flag, compound, desc in allFlags: - print >>f, " '%s' : '%s'," % (flag, desc) - print >>f, " }" - - f.close() - - def traceFlagsCC(self, target, source, env): - assert(len(target) == 1) - - f = file(str(target[0]), 'w') - - allFlags = [] - for s in source: - val = eval(s.get_contents()) - allFlags.append(val) - - # file header - print >>f, ''' -/* - * DO NOT EDIT THIS FILE! Automatically generated - */ - -#include "base/traceflags.hh" - -using namespace Trace; - -const char *Trace::flagStrings[] = -{''' - - # The string array is used by SimpleEnumParam to map the strings - # provided by the user to enum values. - for flag, compound, desc in allFlags: - if not compound: - print >>f, ' "%s",' % flag - - print >>f, ' "All",' - for flag, compound, desc in allFlags: - if compound: - print >>f, ' "%s",' % flag - - print >>f, '};' - print >>f - print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1) - print >>f - - # - # Now define the individual compound flag arrays. There is an array - # for each compound flag listing the component base flags. - # - all = tuple([flag for flag,compound,desc in allFlags if not compound]) - print >>f, 'static const Flags AllMap[] = {' - for flag, compound, desc in allFlags: - if not compound: - print >>f, " %s," % flag - print >>f, '};' - print >>f - - for flag, compound, desc in allFlags: - if not compound: - continue - print >>f, 'static const Flags %sMap[] = {' % flag - for flag in compound: - print >>f, " %s," % flag - print >>f, " (Flags)-1" - print >>f, '};' - print >>f - - # - # Finally the compoundFlags[] array maps the compound flags - # to their individual arrays/ - # - print >>f, 'const Flags *Trace::compoundFlags[] =' - print >>f, '{' - print >>f, ' AllMap,' - for flag, compound, desc in allFlags: - if compound: - print >>f, ' %sMap,' % flag - # file trailer - print >>f, '};' - - f.close() - - def traceFlagsHH(self, target, source, env): - assert(len(target) == 1) - - f = file(str(target[0]), 'w') - - allFlags = [] - for s in source: - val = eval(s.get_contents()) - allFlags.append(val) - - # file header boilerplate - print >>f, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.py - */ - -#ifndef __BASE_TRACE_FLAGS_HH__ -#define __BASE_TRACE_FLAGS_HH__ - -namespace Trace { - -enum Flags {''' - - # Generate the enum. Base flags come first, then compound flags. - idx = 0 - for flag, compound, desc in allFlags: - if not compound: - print >>f, ' %s = %d,' % (flag, idx) - idx += 1 - - numBaseFlags = idx - print >>f, ' NumFlags = %d,' % idx - - # put a comment in here to separate base from compound flags - print >>f, ''' -// The remaining enum values are *not* valid indices for Trace::flags. -// They are "compound" flags, which correspond to sets of base -// flags, and are used by changeFlag.''' - - print >>f, ' All = %d,' % idx - idx += 1 - for flag, compound, desc in allFlags: - if compound: - print >>f, ' %s = %d,' % (flag, idx) - idx += 1 - - numCompoundFlags = idx - numBaseFlags - print >>f, ' NumCompoundFlags = %d' % numCompoundFlags - - # trailer boilerplate - print >>f, '''\ -}; // enum Flags - -// Array of strings for SimpleEnumParam -extern const char *flagStrings[]; -extern const int numFlagStrings; - -// Array of arraay pointers: for each compound flag, gives the list of -// base flags to set. Inidividual flag arrays are terminated by -1. -extern const Flags *compoundFlags[]; - -/* namespace Trace */ } - -#endif // __BASE_TRACE_FLAGS_HH__ -''' - - f.close() diff --git a/src/python/importer.py b/src/python/importer.py new file mode 100644 index 000000000..fe099fdb8 --- /dev/null +++ b/src/python/importer.py @@ -0,0 +1,80 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +# Simple importer that allows python to import data from a dict of +# code objects. The keys are the module path, and the items are the +# filename and bytecode of the file. +class CodeImporter(object): + def __init__(self): + self.modules = {} + + def add_module(self, filename, modpath, code): + if modpath in self.modules: + raise AttributeError, "%s already found in importer" + + self.modules[modpath] = (filename, code) + + def find_module(self, fullname, path): + if fullname in self.modules: + return self + + return None + + def load_module(self, fullname): + # Because the importer is created and initialized in its own + # little sandbox (in init.cc), the globals that were available + # when the importer module was loaded and CodeImporter was + # defined are not available when load_module is actually + # called. Soooo, the imports must live here. + import imp + import os + import sys + mod = imp.new_module(fullname) + sys.modules[fullname] = mod + + try: + mod.__loader__ = self + srcfile,code = self.modules[fullname] + if os.path.basename(srcfile) == '__init__.py': + mod.__path__ = fullname.split('.') + mod.__file__ = srcfile + + exec code in mod.__dict__ + except Exception: + del sys.modules[fullname] + raise + + return mod + +# Create an importer and add it to the meta_path so future imports can +# use it. There's currently nothing in the importer, but calls to +# add_module can be used to add code. +import sys +importer = CodeImporter() +add_module = importer.add_module +sys.meta_path.append(importer) diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 78df6bef1..8ef22be4e 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -27,12 +27,13 @@ # Authors: Steve Reinhardt # Nathan Binkert -import sys, types +import math +import sys +import types import proxy import m5 from util import * -from multidict import multidict # These utility functions have to come first because they're # referenced in params.py... otherwise they won't be defined when we @@ -64,6 +65,7 @@ from params import * # There are a few things we need that aren't in params.__all__ since # normal users don't need them from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector +from proxy import * noDot = False try: @@ -124,7 +126,6 @@ instanceDict = {} class MetaSimObject(type): # Attributes that can be set only at initialization time init_keywords = { 'abstract' : types.BooleanType, - 'cxx_namespace' : types.StringType, 'cxx_class' : types.StringType, 'cxx_type' : types.StringType, 'cxx_predecls' : types.ListType, @@ -191,33 +192,31 @@ class MetaSimObject(type): # the following is not true is when we define the SimObject # class itself (in which case the multidicts have no parent). if isinstance(base, MetaSimObject): + cls._base = base cls._params.parent = base._params cls._ports.parent = base._ports cls._values.parent = base._values cls._port_refs.parent = base._port_refs # mark base as having been subclassed base._instantiated = True + else: + cls._base = None # default keyword values if 'type' in cls._value_dict: - _type = cls._value_dict['type'] if 'cxx_class' not in cls._value_dict: - cls._value_dict['cxx_class'] = _type + cls._value_dict['cxx_class'] = cls._value_dict['type'] - namespace = cls._value_dict.get('cxx_namespace', None) - - _cxx_class = cls._value_dict['cxx_class'] - if 'cxx_type' not in cls._value_dict: - t = _cxx_class + '*' - if namespace: - t = '%s::%s' % (namespace, t) - cls._value_dict['cxx_type'] = t + cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class'] + if 'cxx_predecls' not in cls._value_dict: # A forward class declaration is sufficient since we are # just declaring a pointer. - decl = 'class %s;' % _cxx_class - if namespace: - decl = 'namespace %s { %s }' % (namespace, decl) + class_path = cls._value_dict['cxx_class'].split('::') + class_path.reverse() + decl = 'class %s;' % class_path[0] + for ns in class_path[1:]: + decl = 'namespace %s { %s }' % (ns, decl) cls._value_dict['cxx_predecls'] = [decl] if 'swig_predecls' not in cls._value_dict: @@ -349,12 +348,6 @@ class MetaSimObject(type): def __str__(cls): return cls.__name__ - def get_base(cls): - if str(cls) == 'SimObject': - return None - - return cls.__bases__[0].type - def cxx_decl(cls): code = "#ifndef __PARAMS__%s\n" % cls code += "#define __PARAMS__%s\n\n" % cls @@ -385,22 +378,29 @@ class MetaSimObject(type): code += "\n".join(predecls2) code += "\n\n"; - base = cls.get_base() - if base: - code += '#include "params/%s.hh"\n\n' % base + if cls._base: + code += '#include "params/%s.hh"\n\n' % cls._base.type for ptype in ptypes: if issubclass(ptype, Enum): code += '#include "enums/%s.hh"\n' % ptype.__name__ code += "\n\n" + code += cls.cxx_struct(cls._base, params) + + # close #ifndef __PARAMS__* guard + code += "\n#endif\n" + return code + + def cxx_struct(cls, base, params): + if cls == SimObject: + return '#include "sim/sim_object_params.hh"\n' + # now generate the actual param struct - code += "struct %sParams" % cls + code = "struct %sParams" % cls if base: - code += " : public %sParams" % base + code += " : public %sParams" % base.type code += "\n{\n" - if cls == SimObject: - code += " virtual ~%sParams() {}\n" % cls if not hasattr(cls, 'abstract') or not cls.abstract: if 'type' in cls.__dict__: code += " %s create();\n" % cls.cxx_type @@ -409,28 +409,9 @@ class MetaSimObject(type): code += "".join([" %s\n" % d for d in decls]) code += "};\n" - # close #ifndef __PARAMS__* guard - code += "\n#endif\n" - return code - - def cxx_type_decl(cls): - base = cls.get_base() - code = '' - - if base: - code += '#include "%s_type.h"\n' % base - - # now generate dummy code for inheritance - code += "struct %s" % cls.cxx_class - if base: - code += " : public %s" % base.cxx_class - code += "\n{};\n" - return code def swig_decl(cls): - base = cls.get_base() - code = '%%module %s\n' % cls code += '%{\n' @@ -458,8 +439,8 @@ class MetaSimObject(type): code += "\n".join(predecls2) code += "\n\n"; - if base: - code += '%%import "params/%s.i"\n\n' % base + if cls._base: + code += '%%import "params/%s.i"\n\n' % cls._base.type for ptype in ptypes: if issubclass(ptype, Enum): @@ -481,7 +462,6 @@ class SimObject(object): type = 'SimObject' abstract = True - name = Param.String("Object name") swig_objdecls = [ '%include "python/swig/sim_object.i"' ] # Initialize new instance. For objects with SimObject-valued @@ -650,8 +630,9 @@ class SimObject(object): if len(value) == 1: value[0]._maybe_set_parent(self, attr) else: + width = int(math.ceil(math.log(len(value))/math.log(10))) for i,v in enumerate(value): - v._maybe_set_parent(self, "%s%d" % (attr, i)) + v._maybe_set_parent(self, "%s%0*d" % (attr, width, i)) self._values[attr] = value @@ -687,7 +668,7 @@ class SimObject(object): match_obj = self._values[pname] if found_obj != None and found_obj != match_obj: raise AttributeError, \ - 'parent.any matched more than one: %s' % obj.path + 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path) found_obj = match_obj return found_obj, found_obj != None @@ -722,7 +703,7 @@ class SimObject(object): self._children[child].unproxy_all() def print_ini(self, ini_file): - print >>ini_file, '[' + self.path() + ']' # .ini section header + print >>ini_file, '[' + self.path() + ']' # .ini section header instanceDict[self.path()] = self @@ -749,7 +730,7 @@ class SimObject(object): if port != None: print >>ini_file, '%s=%s' % (port_name, port.ini_str()) - print >>ini_file # blank line between objects + print >>ini_file # blank line between objects for child in child_names: self._children[child].print_ini(ini_file) @@ -760,7 +741,7 @@ class SimObject(object): cc_params_struct = getattr(m5.objects.params, '%sParams' % self.type) cc_params = cc_params_struct() - cc_params.object = self + cc_params.pyobj = self cc_params.name = str(self) param_names = self._params.keys() @@ -768,7 +749,8 @@ class SimObject(object): for param in param_names: value = self._values.get(param) if value is None: - continue + m5.fatal("%s.%s without default or user set value", + self.path(), param) value = value.getValue() if isinstance(self._params[param], VectorParamDesc): diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index f21bb362e..733258acf 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -36,8 +36,31 @@ import smartdict MaxTick = 2**63 - 1 # define this here so we can use it right away if necessary -def panic(string): - print >>sys.stderr, 'panic:', string + +def errorURL(prefix, s): + try: + import zlib + hashstr = "%x" % zlib.crc32(s) + except: + hashstr = "UnableToHash" + return "For more information see: http://www.m5sim.org/%s/%s" % \ + (prefix, hashstr) + + +# panic() should be called when something happens that should never +# ever happen regardless of what the user does (i.e., an acutal m5 +# bug). +def panic(fmt, *args): + print >>sys.stderr, 'panic:', fmt % args + print >>sys.stderr, errorURL('panic',fmt) + sys.exit(1) + +# fatal() should be called when the simulation cannot continue due to +# some condition that is the user's fault (bad configuration, invalid +# arguments, etc.) and not a simulator bug. +def fatal(fmt, *args): + print >>sys.stderr, 'fatal:', fmt % args + print >>sys.stderr, errorURL('fatal',fmt) sys.exit(1) # force scalars to one-element lists for uniformity @@ -77,22 +100,23 @@ env.update(os.environ) # importing *you*). try: import internal - running_m5 = True except ImportError: - running_m5 = False + internal = None + +import defines +build_env.update(defines.buildEnv) -if running_m5: - import defines - build_env.update(defines.m5_build_env) -else: - import __scons - build_env.update(__scons.m5_build_env) +if internal: + defines.compileDate = internal.core.compileDate + for k,v in internal.core.__dict__.iteritems(): + if k.startswith('flag_'): + setattr(defines, k[5:], v) -if running_m5: from event import * from simulate import * - from main import options + from main import options, main import stats + import core import SimObject import params diff --git a/src/python/m5/config.py b/src/python/m5/config.py new file mode 100644 index 000000000..c28f6675a --- /dev/null +++ b/src/python/m5/config.py @@ -0,0 +1,50 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import os +from os.path import isdir, isfile, join as joinpath + + +confdir = os.environ.get('M5_CONFIG') + +if not confdir: + # HOME is not set when running regressions, due to use of scons + # Execute() function. + homedir = os.environ.get('HOME') + if homedir and isdir(joinpath(homedir, '.m5')): + confdir = joinpath(homedir, '.m5') + +def get(name): + if not confdir: + return None + conffile = joinpath(confdir, name) + if not isfile(conffile): + return None + + return conffile + diff --git a/src/python/m5/core.py b/src/python/m5/core.py new file mode 100644 index 000000000..1d7985be6 --- /dev/null +++ b/src/python/m5/core.py @@ -0,0 +1,40 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import internal +from internal.core import initAll, regAllStats + +def setOutputDir(dir): + internal.core.setOutputDir(dir) + +def initAll(): + internal.core.initAll() + +def regAllStats(): + internal.core.regAllStats() + diff --git a/src/python/m5/debug.py b/src/python/m5/debug.py new file mode 100644 index 000000000..cd40b8fa3 --- /dev/null +++ b/src/python/m5/debug.py @@ -0,0 +1,31 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import internal + +from internal.debug import schedBreakCycle, setRemoteGDBPort diff --git a/src/python/m5/event.py b/src/python/m5/event.py index 2d6497464..35095599d 100644 --- a/src/python/m5/event.py +++ b/src/python/m5/event.py @@ -26,17 +26,36 @@ # # Authors: Nathan Binkert -from internal.event import create -from internal.event import SimLoopExitEvent as SimExit +import m5 +import internal.event + +from internal.event import PythonEvent, SimLoopExitEvent as SimExit + +mainq = internal.event.cvar.mainEventQueue + +def create(obj, priority=None): + if priority is None: + priority = Event.Default_Pri + return PythonEvent(obj, priority) -class ProgressEvent(object): - def __init__(self, period): - self.period = int(period) - self.schedule() - def schedule(self): - create(self, m5.curTick() + self.period) +# As a reminder, priorities found in sim/eventq.hh are stuck into the +# Event class by swig +class Event(PythonEvent): + def __init__(self, priority=None): + if priority is None: + priority = Event.Default_Pri + super(Event, self).__init__(self, priority) + +class ProgressEvent(Event): + def __init__(self, eventq, period): + super(ProgressEvent, self).__init__() + self.period = int(period) + self.eventq = eventq + self.eventq.schedule(self, m5.curTick() + self.period) def __call__(self): print "Progress! Time now %fs" % (m5.curTick()/1e12) - self.schedule() + self.eventq.schedule(self, m5.curTick() + self.period) + +__all__ = [ 'create', 'Event', 'ProgressEvent', 'SimExit', 'mainq' ] diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 4bcca46d2..98019b197 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -28,14 +28,13 @@ import code import datetime -import optparse import os import socket import sys -from attrdict import attrdict -import defines -import traceflags +from util import attrdict +import config +from options import OptionParser __all__ = [ 'options', 'arguments', 'main' ] @@ -47,77 +46,11 @@ The Regents of The University of Michigan All Rights Reserved ''' -def print_list(items, indent=4): - line = ' ' * indent - for i,item in enumerate(items): - if len(line) + len(item) > 76: - print line - line = ' ' * indent - - if i < len(items) - 1: - line += '%s, ' % item - else: - line += item - print line - -# there's only one option parsing done, so make it global and add some -# helper functions to make it work well. -parser = optparse.OptionParser(usage=usage, version=version, - description=brief_copyright, - formatter=optparse.TitledHelpFormatter()) -parser.disable_interspersed_args() - -# current option group -group = None - -def set_group(*args, **kwargs): - '''set the current option group''' - global group - if not args and not kwargs: - group = None - else: - group = parser.add_option_group(*args, **kwargs) - -class splitter(object): - def __init__(self, split): - self.split = split - def __call__(self, option, opt_str, value, parser): - getattr(parser.values, option.dest).extend(value.split(self.split)) - -def add_option(*args, **kwargs): - '''add an option to the current option group, or global none set''' - - # if action=split, but allows the option arguments - # themselves to be lists separated by the split variable''' - - if kwargs.get('action', None) == 'append' and 'split' in kwargs: - split = kwargs.pop('split') - kwargs['default'] = [] - kwargs['type'] = 'string' - kwargs['action'] = 'callback' - kwargs['callback'] = splitter(split) - - if group: - return group.add_option(*args, **kwargs) - - return parser.add_option(*args, **kwargs) - -def bool_option(name, default, help): - '''add a boolean option called --name and --no-name. - Display help depending on which is the default''' - - tname = '--%s' % name - fname = '--no-%s' % name - dest = name.replace('-', '_') - if default: - thelp = optparse.SUPPRESS_HELP - fhelp = help - else: - thelp = help - fhelp = optparse.SUPPRESS_HELP - - add_option(tname, action="store_true", default=default, help=thelp) - add_option(fname, action="store_false", dest=dest, help=fhelp) +options = OptionParser(usage=usage, version=version, + description=brief_copyright) +add_option = options.add_option +set_group = options.set_group +usage = options.usage # Help options add_option('-A', "--authors", action="store_true", default=False, @@ -132,8 +65,16 @@ add_option('-N', "--release-notes", action="store_true", default=False, help="Show the release notes") # Options for configuring the base simulator -add_option('-d', "--outdir", metavar="DIR", default=".", +add_option('-d', "--outdir", metavar="DIR", default="m5out", help="Set the output directory to DIR [Default: %default]") +add_option('-r', "--redirect-stdout", action="store_true", default=False, + help="Redirect stdout (& stderr, without -e) to file") +add_option('-e', "--redirect-stderr", action="store_true", default=False, + help="Redirect stderr to file") +add_option("--stdout-file", metavar="FILE", default="simout", + help="Filename for -r redirection [Default: %default]") +add_option("--stderr-file", metavar="FILE", default="simerr", + help="Filename for -e redirection [Default: %default]") add_option('-i', "--interactive", action="store_true", default=False, help="Invoke the interactive interpreter after running the script") add_option("--pdb", action="store_true", default=False, @@ -147,13 +88,20 @@ add_option('-v', "--verbose", action="count", default=0, # Statistics options set_group("Statistics Options") -add_option("--stats-file", metavar="FILE", default="m5stats.txt", +add_option("--stats-file", metavar="FILE", default="stats.txt", help="Sets the output file for statistics [Default: %default]") +# Configuration Options +set_group("Configuration Options") +add_option("--dump-config", metavar="FILE", default="config.ini", + help="Dump configuration output file [Default: %default]") + # Debugging options set_group("Debugging Options") add_option("--debug-break", metavar="TIME[,TIME]", action='append', split=',', help="Cycle to create a breakpoint") +add_option("--remote-gdb-port", type='int', default=7000, + help="Remote gdb base port") # Tracing options set_group("Trace Options") @@ -168,39 +116,61 @@ add_option("--trace-file", metavar="FILE", default="cout", add_option("--trace-ignore", metavar="EXPR", action='append', split=':', help="Ignore EXPR sim objects") -options = attrdict() -arguments = [] +# Help options +set_group("Help Options") +add_option("--list-sim-objects", action='store_true', default=False, + help="List all built-in SimObjects, their parameters and default values") -def usage(exitcode=None): - parser.print_help() - if exitcode is not None: - sys.exit(exitcode) +def main(): + import core + import debug + import defines + import event + import info + import stats + import trace -def parse_args(): - _opts,args = parser.parse_args() - opts = attrdict(_opts.__dict__) + def check_tracing(): + if defines.TRACING_ON: + return - # setting verbose and quiet at the same time doesn't make sense - if opts.verbose > 0 and opts.quiet > 0: - usage(2) + fatal("Tracing is not enabled. Compile with TRACING_ON") - # store the verbosity in a single variable. 0 is default, - # negative numbers represent quiet and positive values indicate verbose - opts.verbose -= opts.quiet + # load the options.py config file to allow people to set their own + # default options + options_file = config.get('options.py') + if options_file: + scope = { 'options' : options } + execfile(options_file, scope) - del opts.quiet + arguments = options.parse_args() - options.update(opts) - arguments.extend(args) - return opts,args + if not os.path.isdir(options.outdir): + os.makedirs(options.outdir) -def main(): - import defines - import event - import info - import internal + # These filenames are used only if the redirect_std* options are set + stdout_file = os.path.join(options.outdir, options.stdout_file) + stderr_file = os.path.join(options.outdir, options.stderr_file) - parse_args() + # Print redirection notices here before doing any redirection + if options.redirect_stdout and not options.redirect_stderr: + print "Redirecting stdout and stderr to", stdout_file + else: + if options.redirect_stdout: + print "Redirecting stdout to", stdout_file + if options.redirect_stderr: + print "Redirecting stderr to", stderr_file + + # Now redirect stdout/stderr as desired + if options.redirect_stdout: + redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC) + os.dup2(redir_fd, sys.stdout.fileno()) + if not options.redirect_stderr: + os.dup2(redir_fd, sys.stderr.fileno()) + + if options.redirect_stderr: + redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC) + os.dup2(redir_fd, sys.stderr.fileno()) done = False @@ -208,14 +178,13 @@ def main(): done = True print 'Build information:' print - print 'compiled %s' % internal.core.cvar.compileDate; - print 'started %s' % datetime.datetime.now().ctime() - print 'executing on %s' % socket.gethostname() + print 'compiled %s' % defines.compileDate; + print "revision %s" % defines.hgRev print 'build options:' - keys = defines.m5_build_env.keys() + keys = defines.buildEnv.keys() keys.sort() for key in keys: - val = defines.m5_build_env[key] + val = defines.buildEnv[key] print ' %s = %s' % (key, val) print @@ -247,27 +216,49 @@ def main(): if options.trace_help: done = True - print "Base Flags:" - print_list(traceflags.baseFlags, indent=4) - print - print "Compound Flags:" - for flag in traceflags.compoundFlags: - if flag == 'All': - continue - print " %s:" % flag - print_list(traceflags.compoundFlagMap[flag], indent=8) + check_tracing() + trace.help() + + if options.list_sim_objects: + import SimObject + done = True + print "SimObjects:" + objects = SimObject.allClasses.keys() + objects.sort() + for name in objects: + obj = SimObject.allClasses[name] + print " %s" % obj + params = obj._params.keys() + params.sort() + for pname in params: + param = obj._params[pname] + default = getattr(param, 'default', '') + print " %s" % pname + if default: + print " default: %s" % default + print " desc: %s" % param.desc + print print if done: sys.exit(0) + # setting verbose and quiet at the same time doesn't make sense + if options.verbose > 0 and options.quiet > 0: + options.usage(2) + + verbose = options.verbose - options.quiet if options.verbose >= 0: print "M5 Simulator System" print brief_copyright print - print "M5 compiled %s" % internal.core.cvar.compileDate; - print "M5 started %s" % datetime.datetime.now().ctime() + + print "M5 compiled %s" % defines.compileDate; + print "M5 revision %s" % defines.hgRev + + print "M5 started %s" % datetime.datetime.now().strftime("%b %e %Y %X") print "M5 executing on %s" % socket.gethostname() + print "command line:", for argv in sys.argv: print argv, @@ -278,61 +269,67 @@ def main(): if arguments and not os.path.isfile(arguments[0]): print "Script %s not found" % arguments[0] - usage(2) + options.usage(2) # tell C++ about output directory - internal.core.setOutputDir(options.outdir) + core.setOutputDir(options.outdir) # update the system path with elements from the -p option sys.path[0:0] = options.path - import objects - # set stats options - internal.stats.initText(options.stats_file) + stats.initText(options.stats_file) # set debugging options + debug.setRemoteGDBPort(options.remote_gdb_port) for when in options.debug_break: - internal.debug.schedBreakCycle(int(when)) - - on_flags = [] - off_flags = [] - for flag in options.trace_flags: - off = False - if flag.startswith('-'): - flag = flag[1:] - off = True - if flag not in traceflags.allFlags: - print >>sys.stderr, "invalid trace flag '%s'" % flag - sys.exit(1) - - if off: - off_flags.append(flag) - else: - on_flags.append(flag) - - for flag in on_flags: - internal.trace.set(flag) - - for flag in off_flags: - internal.trace.clear(flag) + debug.schedBreakCycle(int(when)) + + if options.trace_flags: + check_tracing() + + on_flags = [] + off_flags = [] + for flag in options.trace_flags: + off = False + if flag.startswith('-'): + flag = flag[1:] + off = True + if flag not in trace.flags.all and flag != "All": + print >>sys.stderr, "invalid trace flag '%s'" % flag + sys.exit(1) + + if off: + off_flags.append(flag) + else: + on_flags.append(flag) + + for flag in on_flags: + trace.set(flag) + + for flag in off_flags: + trace.clear(flag) if options.trace_start: - def enable_trace(): - internal.trace.cvar.enabled = True - event.create(enable_trace, int(options.trace_start)) + check_tracing() + e = event.create(trace.enable, event.Event.Trace_Enable_Pri) + event.mainq.schedule(e, options.trace_start) else: - internal.trace.cvar.enabled = True + trace.enable() - internal.trace.output(options.trace_file) + trace.output(options.trace_file) for ignore in options.trace_ignore: - internal.trace.ignore(ignore) + check_tracing() + trace.ignore(ignore) sys.argv = arguments sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path - scope = { '__file__' : sys.argv[0], + filename = sys.argv[0] + filedata = file(filename, 'r').read() + filecode = compile(filedata, filename, 'exec') + scope = { '__file__' : filename, '__name__' : '__m5_main__' } # we want readline if we're doing anything interactive @@ -342,11 +339,24 @@ def main(): # if pdb was requested, execfile the thing under pdb, otherwise, # just do the execfile normally if options.pdb: - from pdb import Pdb - debugger = Pdb() - debugger.run('execfile("%s")' % sys.argv[0], scope) + import pdb + import traceback + + pdb = pdb.Pdb() + try: + pdb.run(filecode, scope) + except SystemExit: + print "The program exited via sys.exit(). Exit status: ", + print sys.exc_info()[1] + except: + traceback.print_exc() + print "Uncaught exception. Entering post mortem debugging" + t = sys.exc_info()[2] + while t.tb_next is not None: + t = t.tb_next + pdb.interaction(t.tb_frame,t) else: - execfile(sys.argv[0], scope) + exec filecode in scope # once the script is done if options.interactive: @@ -356,7 +366,14 @@ def main(): if __name__ == '__main__': from pprint import pprint - parse_args() + # load the options.py config file to allow people to set their own + # default options + options_file = config.get('options.py') + if options_file: + scope = { 'options' : options } + execfile(options_file, scope) + + arguments = options.parse_args() print 'opts:' pprint(options, indent=4) diff --git a/src/python/m5/options.py b/src/python/m5/options.py new file mode 100644 index 000000000..1f534a314 --- /dev/null +++ b/src/python/m5/options.py @@ -0,0 +1,142 @@ +# Copyright (c) 2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import optparse +import sys + +from optparse import * + +class nodefault(object): pass + +class splitter(object): + def __init__(self, split): + self.split = split + def __call__(self, option, opt_str, value, parser): + values = value.split(self.split) + dest = getattr(parser.values, option.dest) + if dest is None: + setattr(parser.values, option.dest, values) + else: + dest.extend(values) + +class OptionParser(dict): + def __init__(self, *args, **kwargs): + kwargs.setdefault('formatter', optparse.TitledHelpFormatter()) + self._optparse = optparse.OptionParser(*args, **kwargs) + self._optparse.disable_interspersed_args() + + self._allopts = {} + + # current option group + self._group = self._optparse + + def set_defaults(self, *args, **kwargs): + return self._optparse.set_defaults(*args, **kwargs) + + def set_group(self, *args, **kwargs): + '''set the current option group''' + if not args and not kwargs: + self._group = self._optparse + else: + self._group = self._optparse.add_option_group(*args, **kwargs) + + def add_option(self, *args, **kwargs): + '''add an option to the current option group, or global none set''' + + # if action=split, but allows the option arguments + # themselves to be lists separated by the split variable''' + + if kwargs.get('action', None) == 'append' and 'split' in kwargs: + split = kwargs.pop('split') + kwargs['default'] = [] + kwargs['type'] = 'string' + kwargs['action'] = 'callback' + kwargs['callback'] = splitter(split) + + option = self._group.add_option(*args, **kwargs) + dest = option.dest + if dest not in self._allopts: + self._allopts[dest] = option + + return option + + def bool_option(self, name, default, help): + '''add a boolean option called --name and --no-name. + Display help depending on which is the default''' + + tname = '--%s' % name + fname = '--no-%s' % name + dest = name.replace('-', '_') + if default: + thelp = optparse.SUPPRESS_HELP + fhelp = help + else: + thelp = help + fhelp = optparse.SUPPRESS_HELP + + topt = self.add_option(tname, action="store_true", default=default, + help=thelp) + fopt = self.add_option(fname, action="store_false", dest=dest, + help=fhelp) + + return topt,fopt + + def __getattr__(self, attr): + if attr.startswith('_'): + return super(OptionParser, self).__getattribute__(attr) + + if attr in self: + return self[attr] + + return super(OptionParser, self).__getattribute__(attr) + + def __setattr__(self, attr, value): + if attr.startswith('_'): + super(OptionParser, self).__setattr__(attr, value) + elif attr in self._allopts: + defaults = { attr : value } + self.set_defaults(**defaults) + if attr in self: + self[attr] = value + else: + super(OptionParser, self).__setattr__(attr, value) + + def parse_args(self): + opts,args = self._optparse.parse_args() + + for key,val in opts.__dict__.iteritems(): + if val is not None or key not in self: + self[key] = val + + return args + + def usage(self, exitcode=None): + self._optparse.print_help() + if exitcode is not None: + sys.exit(exitcode) + diff --git a/src/python/m5/params.py b/src/python/m5/params.py index 241d4ceaf..18eeac0d1 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -166,6 +166,10 @@ class ParamDesc(object): class VectorParamValue(list): __metaclass__ = MetaParamValue + def __setattr__(self, attr, value): + raise AttributeError, \ + "Not allowed to set %s on '%s'" % (attr, type(self).__name__) + def ini_str(self): return ' '.join([v.ini_str() for v in self]) @@ -323,8 +327,8 @@ class CheckedIntType(MetaParamValue): if not (hasattr(cls, 'min') and hasattr(cls, 'max')): if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): panic("CheckedInt subclass %s must define either\n" \ - " 'min' and 'max' or 'size' and 'unsigned'\n" \ - % name); + " 'min' and 'max' or 'size' and 'unsigned'\n", + name); if cls.unsigned: cls.min = 0 cls.max = 2 ** cls.size - 1 @@ -379,6 +383,13 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 class Float(ParamValue, float): cxx_type = 'double' + def __init__(self, value): + if isinstance(value, (int, long, float, NumericParamValue, Float)): + self.value = float(value) + else: + raise TypeError, "Can't convert object of type %s to Float" \ + % type(value).__name__ + def getValue(self): return float(self.value) @@ -406,7 +417,6 @@ class MemorySize32(CheckedInt): class Addr(CheckedInt): cxx_type = 'Addr' - cxx_predecls = ['#include "arch/isa_traits.hh"'] size = 64 unsigned = True def __init__(self, value): @@ -886,7 +896,7 @@ class NetworkBandwidth(float,ParamValue): class MemoryBandwidth(float,ParamValue): cxx_type = 'float' - def __new__(self, value): + def __new__(cls, value): # we want the number of ticks per byte of data val = convert.toMemoryBandwidth(value) return super(cls, MemoryBandwidth).__new__(cls, val) @@ -896,7 +906,9 @@ class MemoryBandwidth(float,ParamValue): def getValue(self): # convert to seconds per byte - value = 1.0 / float(self) + value = float(self) + if value: + value = 1.0 / float(self) # convert to ticks per byte value = ticks.fromSeconds(value) return float(value) @@ -992,6 +1004,7 @@ class PortRef(object): if self.peer and not proxy.isproxy(self.peer): print "warning: overwriting port", self, \ "value", self.peer, "with", other + self.peer.peer = None self.peer = other if proxy.isproxy(other): other.set_param_desc(PortParamDesc()) @@ -1034,6 +1047,8 @@ class PortRef(object): if self.ccConnected: # already done this return peer = self.peer + if not self.peer: # nothing to connect to + return connectPorts(self.simobj.getCCObject(), self.name, self.index, peer.simobj.getCCObject(), peer.name, peer.index) self.ccConnected = True diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py index 3d91da368..45992fe85 100644 --- a/src/python/m5/simulate.py +++ b/src/python/m5/simulate.py @@ -33,6 +33,8 @@ import sys # import the SWIG-wrapped main C++ functions import internal +import core +import stats from main import options import SimObject import ticks @@ -46,28 +48,29 @@ def instantiate(root): root.unproxy_all() - ini_file = file(os.path.join(options.outdir, 'config.ini'), 'w') - root.print_ini(ini_file) - ini_file.close() # close config.ini + if options.dump_config: + ini_file = file(os.path.join(options.outdir, options.dump_config), 'w') + root.print_ini(ini_file) + ini_file.close() # Initialize the global statistics - internal.stats.initSimStats() + stats.initSimStats() # Create the C++ sim objects and connect ports root.createCCObject() root.connectPorts() # Do a second pass to finish initializing the sim objects - internal.core.initAll() + core.initAll() # Do a third pass to initialize statistics - internal.core.regAllStats() + core.regAllStats() - # Check to make sure that the stats package is properly initialized - internal.stats.check() + # We're done registering statistics. Enable the stats package now. + stats.enable() # Reset to put the stats in a consistent state. - internal.stats.reset() + stats.reset() def doDot(root): dot = pydot.Dot() @@ -182,3 +185,5 @@ def switchCpus(cpuList): for old_cpu, new_cpu in cpuList: new_cpu.takeOverFrom(old_cpu) + +from internal.core import disableAllListeners diff --git a/src/python/m5/stats.py b/src/python/m5/stats.py index 041a3f58d..5bd9d5f6a 100644 --- a/src/python/m5/stats.py +++ b/src/python/m5/stats.py @@ -28,9 +28,6 @@ import internal -from internal.stats import dump -from internal.stats import initSimStats -from internal.stats import reset from internal.stats import StatEvent as event def initText(filename, desc=True, compat=True): @@ -44,3 +41,19 @@ def initMySQL(host, database, user='', passwd='', project='test', name='test', internal.stats.initMySQL(host, database, user, passwd, project, name, sample) + +def initSimStats(): + internal.stats.initSimStats() + +def enable(): + internal.stats.enable() + +def dump(): + # Currently prepare happens in the dump, but we should maybe move + # that out. + + #internal.stats.prepare() + internal.stats.dump() + +def reset(): + internal.stats.reset() diff --git a/src/python/m5/trace.py b/src/python/m5/trace.py new file mode 100644 index 000000000..17aa6196c --- /dev/null +++ b/src/python/m5/trace.py @@ -0,0 +1,52 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import internal +import traceflags as flags +import util + +from internal.trace import clear, output, set, ignore + +def disable(): + internal.trace.cvar.enabled = False + +def enable(): + internal.trace.cvar.enabled = True + +def help(): + print "Base Flags:" + for flag in flags.basic: + print " %s: %s" % (flag, flags.descriptions[flag]) + print + print "Compound Flags:" + for flag in flags.compound: + if flag == 'All': + continue + print " %s: %s" % (flag, flags.descriptions[flag]) + util.print_list(flags.compoundMap[flag], indent=8) + print diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py new file mode 100644 index 000000000..5c4a066c6 --- /dev/null +++ b/src/python/m5/util/__init__.py @@ -0,0 +1,45 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from attrdict import attrdict, optiondict +from misc import * +from multidict import multidict +import jobfile + +def print_list(items, indent=4): + line = ' ' * indent + for i,item in enumerate(items): + if len(line) + len(item) > 76: + print line + line = ' ' * indent + + if i < len(items) - 1: + line += '%s, ' % item + else: + line += item + print line diff --git a/src/python/m5/attrdict.py b/src/python/m5/util/attrdict.py index 4ee7f1b8c..56f67217b 100644 --- a/src/python/m5/attrdict.py +++ b/src/python/m5/util/attrdict.py @@ -26,16 +26,17 @@ # # Authors: Nathan Binkert -__all__ = [ 'attrdict' ] +__all__ = [ 'attrdict', 'multiattrdict', 'optiondict' ] class attrdict(dict): + """Wrap dict, so you can use attribute access to get/set elements""" def __getattr__(self, attr): if attr in self: return self.__getitem__(attr) return super(attrdict, self).__getattribute__(attr) def __setattr__(self, attr, value): - if attr in dir(self): + if attr in dir(self) or attr.startswith('_'): return super(attrdict, self).__setattr__(attr, value) return self.__setitem__(attr, value) @@ -44,6 +45,25 @@ class attrdict(dict): return self.__delitem__(attr) return super(attrdict, self).__delattr__(attr, value) +class multiattrdict(attrdict): + """Wrap attrdict so that nested attribute accesses automatically create + nested dictionaries.""" + def __getattr__(self, attr): + try: + return super(multiattrdict, self).__getattr__(attr) + except AttributeError: + d = optiondict() + setattr(self, attr, d) + return d + +class optiondict(attrdict): + """Modify attrdict so that a missing attribute just returns None""" + def __getattr__(self, attr): + try: + return super(optiondict, self).__getattr__(attr) + except AttributeError: + return None + if __name__ == '__main__': x = attrdict() x.y = 1 @@ -59,3 +79,9 @@ if __name__ == '__main__': del x.z print dir(x) print(x) + + x = multiattrdict() + x.y.z = 9 + print x + print x.y + print x.y.z diff --git a/src/python/m5/util/jobfile.py b/src/python/m5/util/jobfile.py new file mode 100644 index 000000000..c830895f6 --- /dev/null +++ b/src/python/m5/util/jobfile.py @@ -0,0 +1,472 @@ +# Copyright (c) 2005-2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +import sys + +from attrdict import optiondict +from misc import crossproduct + +class Data(object): + def __init__(self, name, desc, **kwargs): + self.name = name + self.desc = desc + self.__dict__.update(kwargs) + + def update(self, obj): + if not isinstance(obj, Data): + raise AttributeError, "can only update from Data object" + + for key,val in obj.__dict__.iteritems(): + if key.startswith('_') or key in ('name', 'desc'): + continue + + if key not in self.__dict__: + self.__dict__[key] = val + continue + + if not isinstance(val, dict): + if self.__dict__[key] == val: + continue + + raise AttributeError, \ + "%s specified more than once old: %s new: %s" % \ + (key, self.__dict__[key], val) + + d = self.__dict__[key] + for k,v in val.iteritems(): + if k in d: + raise AttributeError, \ + "%s specified more than once in %s" % (k, key) + d[k] = v + + if hasattr(self, 'system') and hasattr(obj, 'system'): + if self.system != obj.system: + raise AttributeError, \ + "conflicting values for system: '%s'/'%s'" % \ + (self.system, obj.system) + + def printinfo(self): + if self.name: + print 'name: %s' % self.name + if self.desc: + print 'desc: %s' % self.desc + try: + if self.system: + print 'system: %s' % self.system + except AttributeError: + pass + + def printverbose(self): + for key in self: + val = self[key] + if isinstance(val, dict): + import pprint + val = pprint.pformat(val) + print '%-20s = %s' % (key, val) + print + + def __contains__(self, attr): + if attr.startswith('_'): + return False + return attr in self.__dict__ + + def __getitem__(self, key): + if key.startswith('_'): + raise KeyError, "Key '%s' not found" % attr + return self.__dict__[key] + + def __iter__(self): + keys = self.__dict__.keys() + keys.sort() + for key in keys: + if not key.startswith('_'): + yield key + + def optiondict(self): + result = optiondict() + for key in self: + result[key] = self[key] + return result + + def __repr__(self): + d = {} + for key,value in self.__dict__.iteritems(): + if not key.startswith('_'): + d[key] = value + + return "<%s: %s>" % (type(self).__name__, d) + + def __str__(self): + return self.name + +class Job(Data): + def __init__(self, options): + super(Job, self).__init__('', '') + + config = options[0]._config + for opt in options: + if opt._config != config: + raise AttributeError, \ + "All options are not from the same Configuration" + + self._config = config + self._groups = [ opt._group for opt in options ] + self._options = options + + self.update(self._config) + for group in self._groups: + self.update(group) + + self._is_checkpoint = True + + for option in self._options: + self.update(option) + if not option._group._checkpoint: + self._is_checkpoint = False + + if option._suboption: + self.update(option._suboption) + self._is_checkpoint = False + + names = [ ] + for opt in self._options: + if opt.name: + names.append(opt.name) + self.name = ':'.join(names) + + descs = [ ] + for opt in self._options: + if opt.desc: + descs.append(opt.desc) + self.desc = ', '.join(descs) + + self._checkpoint = None + if not self._is_checkpoint: + opts = [] + for opt in options: + cpt = opt._group._checkpoint + if not cpt: + continue + if isinstance(cpt, Option): + opt = cpt.clone(suboptions=False) + else: + opt = opt.clone(suboptions=False) + + opts.append(opt) + + if opts: + self._checkpoint = Job(opts) + + def clone(self): + return Job(self._options) + + def printinfo(self): + super(Job, self).printinfo() + if self._checkpoint: + print 'checkpoint: %s' % self._checkpoint.name + print 'config: %s' % self._config.name + print 'groups: %s' % [ g.name for g in self._groups ] + print 'options: %s' % [ o.name for o in self._options ] + super(Job, self).printverbose() + +class SubOption(Data): + def __init__(self, name, desc, **kwargs): + super(SubOption, self).__init__(name, desc, **kwargs) + self._number = None + +class Option(Data): + def __init__(self, name, desc, **kwargs): + super(Option, self).__init__(name, desc, **kwargs) + self._suboptions = [] + self._suboption = None + self._number = None + + def __getattribute__(self, attr): + if attr == 'name': + name = self.__dict__[attr] + if self._suboption is not None: + name = '%s:%s' % (name, self._suboption.name) + return name + + if attr == 'desc': + desc = [ self.__dict__[attr] ] + if self._suboption is not None and self._suboption.desc: + desc.append(self._suboption.desc) + return ', '.join(desc) + + return super(Option, self).__getattribute__(attr) + + def suboption(self, name, desc, **kwargs): + subo = SubOption(name, desc, **kwargs) + subo._config = self._config + subo._group = self._group + subo._option = self + subo._number = len(self._suboptions) + self._suboptions.append(subo) + return subo + + def clone(self, suboptions=True): + option = Option(self.__dict__['name'], self.__dict__['desc']) + option.update(self) + option._group = self._group + option._config = self._config + option._number = self._number + if suboptions: + option._suboptions.extend(self._suboptions) + option._suboption = self._suboption + return option + + def subopts(self): + if not self._suboptions: + return [ self ] + + subopts = [] + for subo in self._suboptions: + option = self.clone() + option._suboption = subo + subopts.append(option) + + return subopts + + def printinfo(self): + super(Option, self).printinfo() + print 'config: %s' % self._config.name + super(Option, self).printverbose() + +class Group(Data): + def __init__(self, name, desc, **kwargs): + super(Group, self).__init__(name, desc, **kwargs) + self._options = [] + self._number = None + self._checkpoint = False + + def option(self, name, desc, **kwargs): + opt = Option(name, desc, **kwargs) + opt._config = self._config + opt._group = self + opt._number = len(self._options) + self._options.append(opt) + return opt + + def options(self): + return self._options + + def subopts(self): + subopts = [] + for opt in self._options: + for subo in opt.subopts(): + subopts.append(subo) + return subopts + + def printinfo(self): + super(Group, self).printinfo() + print 'config: %s' % self._config.name + print 'options: %s' % [ o.name for o in self._options ] + super(Group, self).printverbose() + +class Configuration(Data): + def __init__(self, name, desc, **kwargs): + super(Configuration, self).__init__(name, desc, **kwargs) + self._groups = [] + self._posfilters = [] + self._negfilters = [] + + def group(self, name, desc, **kwargs): + grp = Group(name, desc, **kwargs) + grp._config = self + grp._number = len(self._groups) + self._groups.append(grp) + return grp + + def groups(self): + return self._groups + + def checkchildren(self, kids): + for kid in kids: + if kid._config != self: + raise AttributeError, "child from the wrong configuration" + + def sortgroups(self, groups): + groups = [ (grp._number, grp) for grp in groups ] + groups.sort() + return [ grp[1] for grp in groups ] + + def options(self, groups=None, checkpoint=False): + if groups is None: + groups = self._groups + self.checkchildren(groups) + groups = self.sortgroups(groups) + if checkpoint: + groups = [ grp for grp in groups if grp._checkpoint ] + optgroups = [ g.options() for g in groups ] + else: + optgroups = [ g.subopts() for g in groups ] + if not optgroups: + return + for options in crossproduct(optgroups): + for opt in options: + cpt = opt._group._checkpoint + if not isinstance(cpt, bool) and cpt != opt: + if checkpoint: + break + else: + yield options + else: + if checkpoint: + yield options + + def addfilter(self, filt, pos=True): + import re + filt = re.compile(filt) + if pos: + self._posfilters.append(filt) + else: + self._negfilters.append(filt) + + def jobfilter(self, job): + for filt in self._negfilters: + if filt.match(job.name): + return False + + if not self._posfilters: + return True + + for filt in self._posfilters: + if filt.match(job.name): + return True + + return False + + def checkpoints(self, groups=None): + for options in self.options(groups, True): + job = Job(options) + if self.jobfilter(job): + yield job + + def jobs(self, groups=None): + for options in self.options(groups, False): + job = Job(options) + if self.jobfilter(job): + yield job + + def alljobs(self, groups=None): + for options in self.options(groups, True): + yield Job(options) + for options in self.options(groups, False): + yield Job(options) + + def find(self, jobname): + for job in self.alljobs(): + if job.name == jobname: + return job + else: + raise AttributeError, "job '%s' not found" % jobname + + def job(self, options): + self.checkchildren(options) + options = [ (opt._group._number, opt) for opt in options ] + options.sort() + options = [ opt[1] for opt in options ] + job = Job(options) + return job + + def printinfo(self): + super(Configuration, self).printinfo() + print 'groups: %s' % [ g.name for g in self._groups ] + super(Configuration, self).printverbose() + +def JobFile(jobfile): + from os.path import expanduser, isfile, join as joinpath + filename = expanduser(jobfile) + + # Can't find filename in the current path, search sys.path + if not isfile(filename): + for path in sys.path: + testname = joinpath(path, filename) + if isfile(testname): + filename = testname + break + else: + raise AttributeError, \ + "Could not find file '%s'" % jobfile + + data = {} + execfile(filename, data) + if 'conf' not in data: + raise ImportError, 'cannot import name conf from %s' % jobfile + return data['conf'] + +def main(conf=None): + usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0] + if conf is None: + usage += ' <jobfile>' + + try: + import getopt + opts, args = getopt.getopt(sys.argv[1:], '-bcv') + except getopt.GetoptError: + sys.exit(usage) + + both = False + checkpoint = False + verbose = False + for opt,arg in opts: + if opt == '-b': + both = True + checkpoint = True + if opt == '-c': + checkpoint = True + if opt == '-v': + verbose = True + + if conf is None: + if len(args) != 1: + raise AttributeError, usage + conf = JobFile(args[0]) + else: + if len(args) != 0: + raise AttributeError, usage + + if both: + jobs = conf.alljobs() + elif checkpoint: + jobs = conf.checkpoints() + else: + jobs = conf.jobs() + + for job in jobs: + if verbose: + job.printinfo() + else: + cpt = '' + if job._checkpoint: + cpt = job._checkpoint.name + print job.name, cpt + +if __name__ == '__main__': + main() diff --git a/src/python/m5/util.py b/src/python/m5/util/misc.py index 28b8b1b94..094e3ed9a 100644 --- a/src/python/m5/util.py +++ b/src/python/m5/util/misc.py @@ -56,4 +56,32 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs): else: return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] +def crossproduct(items): + if not isinstance(items, (list, tuple)): + raise AttributeError, 'crossproduct works only on sequences' + if not items: + yield None + return + + current = items[0] + remainder = items[1:] + + if not hasattr(current, '__iter__'): + current = [ current ] + + for item in current: + for rem in crossproduct(remainder): + data = [ item ] + if rem: + data += rem + yield data + +def flatten(items): + if not isinstance(items, (list, tuple)): + yield items + return + + for item in items: + for flat in flatten(item): + yield flat diff --git a/src/python/m5/multidict.py b/src/python/m5/util/multidict.py index b5cd700ef..b5cd700ef 100644 --- a/src/python/m5/multidict.py +++ b/src/python/m5/util/multidict.py diff --git a/src/python/m5/util/orderdict.py b/src/python/m5/util/orderdict.py new file mode 100644 index 000000000..3f755d299 --- /dev/null +++ b/src/python/m5/util/orderdict.py @@ -0,0 +1,80 @@ +# Copyright (c) 2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +__all__ = [ 'orderdict' ] + +class orderdict(dict): + def __init__(self, d = {}): + self._keys = d.keys() + super(orderdict, self).__init__(d) + + def __setitem__(self, key, item): + super(orderdict, self).__setitem__(key, item) + if not hasattr(self, '_keys'): + self._keys = [key,] + if key not in self._keys: + self._keys.append(key) + + def __delitem__(self, key): + super(orderdict, self).__delitem__(key) + self._keys.remove(key) + + def clear(self): + super(orderdict, self).clear() + self._keys = [] + + def items(self): + for i in self._keys: + yield i, self[i] + + def keys(self): + return self._keys + + def popitem(self): + if len(self._keys) == 0: + raise KeyError('dictionary is empty') + else: + key = self._keys[-1] + val = self[key] + del self[key] + return key, val + + def setdefault(self, key, failobj = None): + super(orderdict, self).setdefault(key, failobj) + if key not in self._keys: + self._keys.append(key) + + def update(self, d): + for key in d.keys(): + if not self.has_key(key): + self._keys.append(key) + super(orderdict, self).update(d) + + def values(self): + for i in self._keys: + yield self[i] diff --git a/src/python/swig/core.i b/src/python/swig/core.i index 770765ca4..c567bea4d 100644 --- a/src/python/swig/core.i +++ b/src/python/swig/core.i @@ -34,11 +34,27 @@ %{ #include "python/swig/pyobject.hh" +#include "base/misc.hh" +#include "base/socket.hh" #include "sim/core.hh" #include "sim/host.hh" #include "sim/startup.hh" extern const char *compileDate; + +#ifdef DEBUG +const bool flag_DEBUG = true; +#else +const bool flag_DEBUG = false; +#endif +#ifdef NDEBUG +const bool flag_NDEBUG = true; +#else +const bool flag_NDEBUG = false; +#endif +const bool flag_TRACING_ON = TRACING_ON; + +inline void disableAllListeners() { ListenSocket::disableAll(); } %} %include "stdint.i" @@ -46,11 +62,15 @@ extern const char *compileDate; %include "sim/host.hh" void setOutputDir(const std::string &dir); -void setOutputFile(const std::string &file); void SimStartup(); void doExitCleanup(); +void disableAllListeners(); +%immutable compileDate; char *compileDate; +const bool flag_DEBUG; +const bool flag_NDEBUG; +const bool flag_TRACING_ON; void setClockFrequency(Tick ticksPerSecond); @@ -63,6 +83,10 @@ void unserializeAll(const std::string &cpt_dir); void initAll(); void regAllStats(); +bool want_warn, warn_verbose; +bool want_info, info_verbose; +bool want_hack, hack_verbose; + %wrapper %{ // fix up module name to reflect the fact that it's inside the m5 package #undef SWIG_name diff --git a/src/python/swig/debug.i b/src/python/swig/debug.i index b542e9f82..1084d6936 100644 --- a/src/python/swig/debug.i +++ b/src/python/swig/debug.i @@ -31,16 +31,13 @@ %module debug %{ -// include these files when compiling debug_wrap.cc #include "sim/host.hh" +#include "sim/debug.hh" %} %include "stdint.i" %include "sim/host.hh" - -%inline %{ -extern void schedBreakCycle(Tick when); -%} +%include "sim/debug.hh" %wrapper %{ // fix up module name to reflect the fact that it's inside the m5 package diff --git a/src/python/swig/event.i b/src/python/swig/event.i index 9a2093c99..b40e59a4b 100644 --- a/src/python/swig/event.i +++ b/src/python/swig/event.i @@ -32,34 +32,65 @@ %{ #include "python/swig/pyevent.hh" - +#include "sim/host.hh" +#include "sim/eventq.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/simulate.hh" %} +#pragma SWIG nowarn=350,351 + +%extend EventQueue { + void + schedule(Event *event, Tick when) + { + // Any python event that are scheduled must have their + // internal object's refcount incremented so that the object + // sticks around while it is in the event queue. + PythonEvent *pyevent = dynamic_cast<PythonEvent *>(event); + if (pyevent) + pyevent->incref(); + $self->schedule(event, when); + } + + void + deschedule(Event *event) + { + $self->deschedule(event); + + // Now that we're removing the python object from the event + // queue, we need to decrement its reference count. + PythonEvent *pyevent = dynamic_cast<PythonEvent *>(event); + if (pyevent) + pyevent->decref(); + } +} + +%ignore EventQueue::schedule; +%ignore EventQueue::deschedule; + +%import "base/fast_alloc.hh" +%import "sim/serialize.hh" + %include "stdint.i" %include "std_string.i" %include "sim/host.hh" +%include "sim/eventq.hh" +%include "python/swig/pyevent.hh" -void create(PyObject *object, Tick when); - -class Event; -class CountedDrainEvent : public Event { - public: +struct CountedDrainEvent : public Event +{ void setCount(int _count); }; -CountedDrainEvent *createCountedDrain(); -void cleanupCountedDrain(Event *drain_event); - // minimal definition of SimExitEvent interface to wrap -class SimLoopExitEvent { +class SimLoopExitEvent : public Event +{ public: std::string getCause(); int getCode(); - SimLoopExitEvent(EventQueue *q, Tick _when, Tick _repeat, - const std::string &_cause, int c = 0); + SimLoopExitEvent(const std::string &_cause, int c, Tick _repeat = 0); }; %exception simulate { diff --git a/src/python/swig/pyevent.cc b/src/python/swig/pyevent.cc index 7f23b8874..0695ed2d3 100644 --- a/src/python/swig/pyevent.cc +++ b/src/python/swig/pyevent.cc @@ -33,21 +33,15 @@ #include "python/swig/pyevent.hh" #include "sim/async.hh" -PythonEvent::PythonEvent(PyObject *obj, Tick when, Priority priority) - : Event(&mainEventQueue, priority), object(obj) +PythonEvent::PythonEvent(PyObject *obj, Priority priority) + : Event(priority), object(obj) { if (object == NULL) panic("Passed in invalid object"); - - Py_INCREF(object); - - setFlags(AutoDelete); - schedule(when); } PythonEvent::~PythonEvent() { - Py_DECREF(object); } void @@ -66,4 +60,27 @@ PythonEvent::process() async_event = true; async_exception = true; } + + // Since the object has been removed from the event queue, its + // reference count must be decremented. + Py_DECREF(object); +} + +CountedDrainEvent * +createCountedDrain() +{ + return new CountedDrainEvent(); +} + +void +cleanupCountedDrain(Event *counted_drain) +{ + CountedDrainEvent *event = + dynamic_cast<CountedDrainEvent *>(counted_drain); + if (event == NULL) { + fatal("Called cleanupCountedDrain() on an event that was not " + "a CountedDrainEvent."); + } + assert(event->getCount() == 0); + delete event; } diff --git a/src/python/swig/pyevent.hh b/src/python/swig/pyevent.hh index 65e80e9e4..9006a0404 100644 --- a/src/python/swig/pyevent.hh +++ b/src/python/swig/pyevent.hh @@ -40,35 +40,16 @@ class PythonEvent : public Event PyObject *object; public: - PythonEvent(PyObject *obj, Tick when, Priority priority = Default_Pri); + PythonEvent(PyObject *obj, Event::Priority priority); ~PythonEvent(); + void incref() { Py_INCREF(object); } + void decref() { Py_DECREF(object); } + virtual void process(); }; -inline void -create(PyObject *object, Tick when) -{ - new PythonEvent(object, when); -} - -inline Event * -createCountedDrain() -{ - return new CountedDrainEvent(); -} - -inline void -cleanupCountedDrain(Event *counted_drain) -{ - CountedDrainEvent *event = - dynamic_cast<CountedDrainEvent *>(counted_drain); - if (event == NULL) { - fatal("Called cleanupCountedDrain() on an event that was not " - "a CountedDrainEvent."); - } - assert(event->getCount() == 0); - delete event; -} +CountedDrainEvent *createCountedDrain(); +void cleanupCountedDrain(Event *counted_drain); #endif // __PYTHON_SWIG_PYEVENT_HH__ diff --git a/src/python/swig/range.i b/src/python/swig/range.i index 40809dae4..309e6a8ba 100644 --- a/src/python/swig/range.i +++ b/src/python/swig/range.i @@ -28,6 +28,8 @@ * Authors: Nathan Binkert */ +%rename(assign) *::operator=; + %include "base/range.hh" %include "sim/host.hh" diff --git a/src/python/swig/stats.i b/src/python/swig/stats.i index d36f82dbc..284df8ff8 100644 --- a/src/python/swig/stats.i +++ b/src/python/swig/stats.i @@ -48,7 +48,8 @@ void initMySQL(std::string host, std::string database, std::string user, void StatEvent(bool dump, bool reset, Tick when = curTick, Tick repeat = 0); -void check(); +void enable(); +void prepare(); void dump(); void reset(); diff --git a/src/sim/BaseTLB.py b/src/sim/BaseTLB.py new file mode 100644 index 000000000..9aca4a97c --- /dev/null +++ b/src/sim/BaseTLB.py @@ -0,0 +1,33 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject + +class BaseTLB(SimObject): + type = 'BaseTLB' + abstract = True diff --git a/src/sim/InstTracer.py b/src/sim/InstTracer.py index f7500f1e8..9ba91a019 100644 --- a/src/sim/InstTracer.py +++ b/src/sim/InstTracer.py @@ -31,5 +31,5 @@ from m5.params import * class InstTracer(SimObject): type = 'InstTracer' - cxx_namespace = 'Trace' + cxx_class = 'Trace::InstTracer' abstract = True diff --git a/src/sim/Process.py b/src/sim/Process.py index 37a27bf3b..81108dd70 100644 --- a/src/sim/Process.py +++ b/src/sim/Process.py @@ -34,7 +34,8 @@ class Process(SimObject): type = 'Process' abstract = True input = Param.String('cin', "filename for stdin") - output = Param.String('cout', 'filename for stdout/stderr') + output = Param.String('cout', 'filename for stdout') + errout = Param.String('cerr', 'filename for stderr') system = Param.System(Parent.any, "system process will run on") max_stack_size = Param.MemorySize('64MB', 'maximum size of the stack') diff --git a/src/sim/SConscript b/src/sim/SConscript index 0b39ab8e8..750007947 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -30,6 +30,7 @@ Import('*') +SimObject('BaseTLB.py') SimObject('Root.py') SimObject('System.py') SimObject('InstTracer.py') @@ -39,7 +40,9 @@ Source('core.cc') Source('debug.cc') Source('eventq.cc') Source('faults.cc') -Source('main.cc') +Source('init.cc') +BinSource('main.cc') +Source('pseudo_inst.cc') Source('root.cc') Source('serialize.cc') Source('sim_events.cc') @@ -51,7 +54,6 @@ Source('system.cc') if env['FULL_SYSTEM']: Source('arguments.cc') - Source('pseudo_inst.cc') else: Source('tlb.cc') SimObject('Process.py') diff --git a/src/sim/System.py b/src/sim/System.py index 5712a5c03..3b0bc1e46 100644 --- a/src/sim/System.py +++ b/src/sim/System.py @@ -38,7 +38,7 @@ class System(SimObject): type = 'System' swig_objdecls = [ '%include "python/swig/system.i"' ] - physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") + physmem = Param.PhysicalMemory(Parent.any, "physical memory") mem_mode = Param.MemoryMode('atomic', "The mode the memory system is in") if build_env['FULL_SYSTEM']: abstract = True diff --git a/src/sim/async.hh b/src/sim/async.hh index 932f975d2..6dd5b8a0d 100644 --- a/src/sim/async.hh +++ b/src/sim/async.hh @@ -42,12 +42,12 @@ /// then checked in the main event loop. Defined in main.cc. /// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm. //@{ -extern volatile bool async_event; ///< Some asynchronous event has happened. -extern volatile bool async_statdump; ///< Async request to dump stats. -extern volatile bool async_statreset; ///< Async request to reset stats. -extern volatile bool async_exit; ///< Async request to exit simulator. -extern volatile bool async_io; ///< Async I/O request (SIGIO). -extern volatile bool async_alarm; ///< Async alarm event (SIGALRM). +extern volatile bool async_event; ///< Some asynchronous event has happened. +extern volatile bool async_statdump; ///< Async request to dump stats. +extern volatile bool async_statreset; ///< Async request to reset stats. +extern volatile bool async_exit; ///< Async request to exit simulator. +extern volatile bool async_io; ///< Async I/O request (SIGIO). +extern volatile bool async_alarm; ///< Async alarm event (SIGALRM). extern volatile bool async_exception; ///< Python exception. //@} diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh index 062fc4513..2519e552b 100644 --- a/src/sim/byteswap.hh +++ b/src/sim/byteswap.hh @@ -62,7 +62,7 @@ enum ByteOrder {BigEndianByteOrder, LittleEndianByteOrder}; //These functions actually perform the swapping for parameters //of various bit lengths -static inline uint64_t +inline uint64_t swap_byte64(uint64_t x) { #if defined(linux) @@ -81,7 +81,7 @@ swap_byte64(uint64_t x) #endif } -static inline uint32_t +inline uint32_t swap_byte32(uint32_t x) { #if defined(linux) @@ -95,7 +95,7 @@ swap_byte32(uint32_t x) #endif } -static inline uint16_t +inline uint16_t swap_byte16(uint16_t x) { #if defined(linux) @@ -113,7 +113,7 @@ swap_byte16(uint16_t x) // sizeof() values are known at compile time, it should inline to a // direct call to the right swap_byteNN() function. template <typename T> -static inline T swap_byte(T x) { +inline T swap_byte(T x) { if (sizeof(T) == 8) return swap_byte64((uint64_t)x); else if (sizeof(T) == 4) @@ -127,7 +127,7 @@ static inline T swap_byte(T x) { } template<> -static inline Twin64_t swap_byte<Twin64_t>(Twin64_t x) +inline Twin64_t swap_byte<Twin64_t>(Twin64_t x) { x.a = swap_byte(x.a); x.b = swap_byte(x.b); @@ -135,7 +135,7 @@ static inline Twin64_t swap_byte<Twin64_t>(Twin64_t x) } template<> -static inline Twin32_t swap_byte<Twin32_t>(Twin32_t x) +inline Twin32_t swap_byte<Twin32_t>(Twin32_t x) { x.a = swap_byte(x.a); x.b = swap_byte(x.b); @@ -144,23 +144,23 @@ static inline Twin32_t swap_byte<Twin32_t>(Twin32_t x) //The conversion functions with fixed endianness on both ends don't need to //be in a namespace -template <typename T> static inline T betole(T value) {return swap_byte(value);} -template <typename T> static inline T letobe(T value) {return swap_byte(value);} +template <typename T> inline T betole(T value) {return swap_byte(value);} +template <typename T> inline T letobe(T value) {return swap_byte(value);} //For conversions not involving the guest system, we can define the functions //conditionally based on the BYTE_ORDER macro and outside of the namespaces #if defined(_BIG_ENDIAN) || !defined(_LITTLE_ENDIAN) && BYTE_ORDER == BIG_ENDIAN const ByteOrder HostByteOrder = BigEndianByteOrder; -template <typename T> static inline T htole(T value) {return swap_byte(value);} -template <typename T> static inline T letoh(T value) {return swap_byte(value);} -template <typename T> static inline T htobe(T value) {return value;} -template <typename T> static inline T betoh(T value) {return value;} +template <typename T> inline T htole(T value) {return swap_byte(value);} +template <typename T> inline T letoh(T value) {return swap_byte(value);} +template <typename T> inline T htobe(T value) {return value;} +template <typename T> inline T betoh(T value) {return value;} #elif defined(_LITTLE_ENDIAN) || BYTE_ORDER == LITTLE_ENDIAN const ByteOrder HostByteOrder = LittleEndianByteOrder; -template <typename T> static inline T htole(T value) {return value;} -template <typename T> static inline T letoh(T value) {return value;} -template <typename T> static inline T htobe(T value) {return swap_byte(value);} -template <typename T> static inline T betoh(T value) {return swap_byte(value);} +template <typename T> inline T htole(T value) {return value;} +template <typename T> inline T letoh(T value) {return value;} +template <typename T> inline T htobe(T value) {return swap_byte(value);} +template <typename T> inline T betoh(T value) {return swap_byte(value);} #else #error Invalid Endianess #endif @@ -169,33 +169,33 @@ namespace BigEndianGuest { const bool ByteOrderDiffers = (HostByteOrder != BigEndianByteOrder); template <typename T> - static inline T gtole(T value) {return betole(value);} + inline T gtole(T value) {return betole(value);} template <typename T> - static inline T letog(T value) {return letobe(value);} + inline T letog(T value) {return letobe(value);} template <typename T> - static inline T gtobe(T value) {return value;} + inline T gtobe(T value) {return value;} template <typename T> - static inline T betog(T value) {return value;} + inline T betog(T value) {return value;} template <typename T> - static inline T htog(T value) {return htobe(value);} + inline T htog(T value) {return htobe(value);} template <typename T> - static inline T gtoh(T value) {return betoh(value);} + inline T gtoh(T value) {return betoh(value);} } namespace LittleEndianGuest { const bool ByteOrderDiffers = (HostByteOrder != LittleEndianByteOrder); template <typename T> - static inline T gtole(T value) {return value;} + inline T gtole(T value) {return value;} template <typename T> - static inline T letog(T value) {return value;} + inline T letog(T value) {return value;} template <typename T> - static inline T gtobe(T value) {return letobe(value);} + inline T gtobe(T value) {return letobe(value);} template <typename T> - static inline T betog(T value) {return betole(value);} + inline T betog(T value) {return betole(value);} template <typename T> - static inline T htog(T value) {return htole(value);} + inline T htog(T value) {return htole(value);} template <typename T> - static inline T gtoh(T value) {return letoh(value);} + inline T gtoh(T value) {return letoh(value);} } #endif // __SIM_BYTE_SWAP_HH__ diff --git a/src/sim/core.cc b/src/sim/core.cc index 75f1f384c..8342b6740 100644 --- a/src/sim/core.cc +++ b/src/sim/core.cc @@ -97,14 +97,6 @@ setOutputDir(const string &dir) simout.setDirectory(dir); } -ostream *outputStream; - -void -setOutputFile(const string &file) -{ - outputStream = simout.find(file); -} - /** * Queue of C++ callbacks to invoke on simulator exit. */ diff --git a/src/sim/core.hh b/src/sim/core.hh index fb7f921f4..50cb2ef59 100644 --- a/src/sim/core.hh +++ b/src/sim/core.hh @@ -68,11 +68,6 @@ extern Tick ps; void setClockFrequency(Tick ticksPerSecond); -/// Output stream for simulator messages (e.g., cprintf()). Also used -/// as default stream for tracing and DPRINTF() messages (unless -/// overridden with trace:file option). -extern std::ostream *outputStream; -void setOutputFile(const std::string &file); void setOutputDir(const std::string &dir); struct Callback; diff --git a/src/sim/debug.cc b/src/sim/debug.cc index b4f4cd9dc..f8a3215d0 100644 --- a/src/sim/debug.cc +++ b/src/sim/debug.cc @@ -29,51 +29,36 @@ * Steve Reinhardt */ -#include <sys/types.h> -#include <signal.h> -#include <unistd.h> +#include <Python.h> #include <string> #include <vector> +#include "base/debug.hh" #include "sim/debug.hh" #include "sim/eventq.hh" #include "sim/sim_events.hh" using namespace std; -void -debug_break() -{ -#ifndef NDEBUG - kill(getpid(), SIGTRAP); -#else - cprintf("debug_break suppressed, compiled with NDEBUG\n"); -#endif -} - // // Debug event: place a breakpoint on the process function and // schedule the event to break at a particular cycle // -class DebugBreakEvent : public Event +struct DebugBreakEvent : public Event { - public: - - DebugBreakEvent(EventQueue *q, Tick _when); - - void process(); // process event + DebugBreakEvent(); + void process(); // process event virtual const char *description() const; }; // // constructor: schedule at specified time // -DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when) - : Event(q, Debug_Break_Pri) +DebugBreakEvent::DebugBreakEvent() + : Event(Debug_Break_Pri) { setFlags(AutoDelete); - schedule(_when); } // @@ -99,12 +84,46 @@ DebugBreakEvent::description() const void schedBreakCycle(Tick when) { - new DebugBreakEvent(&mainEventQueue, when); + mainEventQueue.schedule(new DebugBreakEvent, when); + warn("need to stop all queues"); } void eventqDump() { mainEventQueue.dump(); + warn("need to dump all queues"); +} + +void +py_interact() +{ + PyObject *globals; + PyObject *locals; + + globals = PyEval_GetGlobals(); + Py_INCREF(globals); + locals = PyDict_New(); + PyRun_String("import code", Py_file_input, globals, locals); + PyRun_String("code.interact(local=globals())", Py_file_input, + globals, locals); + Py_DECREF(globals); + Py_DECREF(locals); +} + +int remote_gdb_base_port = 7000; + +int +getRemoteGDBPort() +{ + return remote_gdb_base_port; +} + +// Set remote GDB base port. 0 means disable remote GDB. +// Callable from python. +void +setRemoteGDBPort(int port) +{ + remote_gdb_base_port = port; } diff --git a/src/sim/debug.hh b/src/sim/debug.hh index 79792234b..7dafb8394 100644 --- a/src/sim/debug.hh +++ b/src/sim/debug.hh @@ -28,9 +28,15 @@ * Authors: Nathan Binkert */ -#ifndef __DEBUG_HH__ -#define __DEBUG_HH__ +#ifndef __SIM_DEBUG_HH__ +#define __SIM_DEBUG_HH__ -void debug_break(); +#include "sim/host.hh" -#endif // __DEBUG_HH__ +void schedBreakCycle(Tick when); + +int getRemoteGDBPort(); +// Remote gdb base port. 0 disables remote gdb. +void setRemoteGDBPort(int port); + +#endif // __SIM_DEBUG_HH__ diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc index 2c679be1e..d1f84fcb2 100644 --- a/src/sim/eventq.cc +++ b/src/sim/eventq.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2000-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,18 +31,17 @@ * Steve Raasch */ -#include <assert.h> - +#include <cassert> #include <iostream> #include <string> #include <vector> -#include "cpu/smt.hh" +#include "base/hashmap.hh" #include "base/misc.hh" - -#include "sim/eventq.hh" #include "base/trace.hh" +#include "cpu/smt.hh" #include "sim/core.hh" +#include "sim/eventq.hh" using namespace std; @@ -51,100 +51,183 @@ using namespace std; // Events on this queue are processed at the *beginning* of each // cycle, before the pipeline simulation is performed. // -EventQueue mainEventQueue("MainEventQueue"); +EventQueue mainEventQueue("Main Event Queue"); #ifndef NDEBUG Counter Event::instanceCounter = 0; #endif +Event::~Event() +{ + assert(!scheduled()); +} + +const std::string +Event::name() const +{ +#ifndef NDEBUG + return csprintf("Event_%d", instance); +#else + return csprintf("Event_%x", (uintptr_t)this); +#endif +} + + +Event * +Event::insertBefore(Event *event, Event *curr) +{ + // Either way, event will be the top element in the 'in bin' list + // which is the pointer we need in order to look into the list, so + // we need to insert that into the bin list. + if (!curr || *event < *curr) { + // Insert the event before the current list since it is in the future. + event->nextBin = curr; + event->nextInBin = NULL; + } else { + // Since we're on the correct list, we need to point to the next list + event->nextBin = curr->nextBin; // curr->nextBin can now become stale + + // Insert event at the top of the stack + event->nextInBin = curr; + } + + return event; +} + void EventQueue::insert(Event *event) { - if (head == NULL || event->when() < head->when() || - (event->when() == head->when() && - event->priority() <= head->priority())) { - event->next = head; - head = event; - } else { - Event *prev = head; - Event *curr = head->next; + // Deal with the head case + if (!head || *event <= *head) { + head = Event::insertBefore(event, head); + return; + } - while (curr) { - if (event->when() <= curr->when() && - (event->when() < curr->when() || - event->priority() <= curr->priority())) - break; + // Figure out either which 'in bin' list we are on, or where a new list + // needs to be inserted + Event *prev = head; + Event *curr = head->nextBin; + while (curr && *curr < *event) { + prev = curr; + curr = curr->nextBin; + } - prev = curr; - curr = curr->next; - } + // Note: this operation may render all nextBin pointers on the + // prev 'in bin' list stale (except for the top one) + prev->nextBin = Event::insertBefore(event, curr); +} + +Event * +Event::removeItem(Event *event, Event *top) +{ + Event *curr = top; + Event *next = top->nextInBin; + + // if we removed the top item, we need to handle things specially + // and just remove the top item, fixing up the next bin pointer of + // the new top item + if (event == top) { + if (!next) + return top->nextBin; + next->nextBin = top->nextBin; + return next; + } + + // Since we already checked the current element, we're going to + // keep checking event against the next element. + while (event != next) { + if (!next) + panic("event not found!"); - event->next = curr; - prev->next = event; + curr = next; + next = next->nextInBin; } + + // remove next from the 'in bin' list since it's what we're looking for + curr->nextInBin = next->nextInBin; + return top; } void EventQueue::remove(Event *event) { if (head == NULL) - return; + panic("event not found!"); - if (head == event){ - head = event->next; + // deal with an event on the head's 'in bin' list (event has the same + // time as the head) + if (*head == *event) { + head = Event::removeItem(event, head); return; } + // Find the 'in bin' list that this event belongs on Event *prev = head; - Event *curr = head->next; - while (curr && curr != event) { + Event *curr = head->nextBin; + while (curr && *curr < *event) { prev = curr; - curr = curr->next; + curr = curr->nextBin; } - if (curr == event) - prev->next = curr->next; + if (!curr || *curr != *event) + panic("event not found!"); + + // curr points to the top item of the the correct 'in bin' list, when + // we remove an item, it returns the new top item (which may be + // unchanged) + prev->nextBin = Event::removeItem(event, curr); } Event * EventQueue::serviceOne() { Event *event = head; - event->clearFlags(Event::Scheduled); - head = event->next; + Event *next = head->nextInBin; + event->flags.clear(Event::Scheduled); + + if (next) { + // update the next bin pointer since it could be stale + next->nextBin = head->nextBin; + + // pop the stack + head = next; + } else { + // this was the only element on the 'in bin' list, so get rid of + // the 'in bin' list and point to the next bin list + head = head->nextBin; + } // handle action if (!event->squashed()) { event->process(); if (event->isExitEvent()) { - assert(!event->getFlags(Event::AutoDelete)); // would be silly + assert(!event->flags.isSet(Event::AutoDelete)); // would be silly return event; } } else { - event->clearFlags(Event::Squashed); + event->flags.clear(Event::Squashed); } - if (event->getFlags(Event::AutoDelete) && !event->scheduled()) + if (event->flags.isSet(Event::AutoDelete) && !event->scheduled()) delete event; return NULL; } - void Event::serialize(std::ostream &os) { SERIALIZE_SCALAR(_when); SERIALIZE_SCALAR(_priority); - SERIALIZE_ENUM(_flags); + short _flags = flags; + SERIALIZE_SCALAR(_flags); } - void Event::unserialize(Checkpoint *cp, const string §ion) { if (scheduled()) - deschedule(); + mainEventQueue.deschedule(this); UNSERIALIZE_SCALAR(_when); UNSERIALIZE_SCALAR(_priority); @@ -152,13 +235,16 @@ Event::unserialize(Checkpoint *cp, const string §ion) // need to see if original event was in a scheduled, unsquashed // state, but don't want to restore those flags in the current // object itself (since they aren't immediately true) - UNSERIALIZE_ENUM(_flags); - bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); - _flags &= ~(Squashed | Scheduled); + short _flags; + UNSERIALIZE_SCALAR(_flags); + flags = _flags; + + bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed); + flags.clear(Squashed | Scheduled); if (wasScheduled) { DPRINTF(Config, "rescheduling at %d\n", _when); - schedule(_when); + mainEventQueue.schedule(this, _when); } } @@ -168,18 +254,25 @@ EventQueue::serialize(ostream &os) std::list<Event *> eventPtrs; int numEvents = 0; - Event *event = head; - while (event) { - if (event->getFlags(Event::AutoSerialize)) { - eventPtrs.push_back(event); - paramOut(os, csprintf("event%d", numEvents++), event->name()); + Event *nextBin = head; + while (nextBin) { + Event *nextInBin = nextBin; + + while (nextInBin) { + if (nextInBin->flags.isSet(Event::AutoSerialize)) { + eventPtrs.push_back(nextInBin); + paramOut(os, csprintf("event%d", numEvents++), + nextInBin->name()); + } + nextInBin = nextInBin->nextInBin; } - event = event->next; + + nextBin = nextBin->nextBin; } SERIALIZE_SCALAR(numEvents); - for (std::list<Event *>::iterator it=eventPtrs.begin(); + for (std::list<Event *>::iterator it = eventPtrs.begin(); it != eventPtrs.end(); ++it) { (*it)->nameOut(os); (*it)->serialize(os); @@ -203,7 +296,7 @@ EventQueue::unserialize(Checkpoint *cp, const std::string §ion) } void -EventQueue::dump() +EventQueue::dump() const { cprintf("============================================================\n"); cprintf("EventQueue Dump (cycle %d)\n", curTick); @@ -212,16 +305,63 @@ EventQueue::dump() if (empty()) cprintf("<No Events>\n"); else { - Event *event = head; - while (event) { - event->dump(); - event = event->next; + Event *nextBin = head; + while (nextBin) { + Event *nextInBin = nextBin; + while (nextInBin) { + nextInBin->dump(); + nextInBin = nextInBin->nextInBin; + } + + nextBin = nextBin->nextBin; } } cprintf("============================================================\n"); } +bool +EventQueue::debugVerify() const +{ + m5::hash_map<long, bool> map; + + Tick time = 0; + short priority = 0; + + Event *nextBin = head; + while (nextBin) { + Event *nextInBin = nextBin; + while (nextInBin) { + if (nextInBin->when() < time) { + cprintf("time goes backwards!"); + nextInBin->dump(); + return false; + } else if (nextInBin->when() == time && + nextInBin->priority() < priority) { + cprintf("priority inverted!"); + nextInBin->dump(); + return false; + } + + if (map[reinterpret_cast<long>(nextInBin)]) { + cprintf("Node already seen"); + nextInBin->dump(); + return false; + } + map[reinterpret_cast<long>(nextInBin)] = true; + + time = nextInBin->when(); + priority = nextInBin->priority(); + + nextInBin = nextInBin->nextInBin; + } + + nextBin = nextBin->nextBin; + } + + return true; +} + void dumpMainQueue() { @@ -235,7 +375,6 @@ Event::description() const return "generic"; } -#if TRACING_ON void Event::trace(const char *action) { @@ -250,23 +389,21 @@ Event::trace(const char *action) // needs to be printed. DPRINTFN("%s event %s @ %d\n", description(), action, when()); } -#endif void -Event::dump() +Event::dump() const { - cprintf("Event (%s)\n", description()); - cprintf("Flags: %#x\n", _flags); -#if TRACING_ON - cprintf("Created: %d\n", when_created); + cprintf("Event %s (%s)\n", name(), description()); + cprintf("Flags: %#x\n", flags); +#ifdef EVENTQ_DEBUG + cprintf("Created: %d\n", whenCreated); #endif if (scheduled()) { -#if TRACING_ON - cprintf("Scheduled at %d\n", when_scheduled); +#ifdef EVENTQ_DEBUG + cprintf("Scheduled at %d\n", whenScheduled); #endif cprintf("Scheduled for %d, priority %d\n", when(), _priority); - } - else { + } else { cprintf("Not Scheduled\n"); } } diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh index a454e5d64..33bb34252 100644 --- a/src/sim/eventq.hh +++ b/src/sim/eventq.hh @@ -36,45 +36,70 @@ #ifndef __SIM_EVENTQ_HH__ #define __SIM_EVENTQ_HH__ -#include <assert.h> - #include <algorithm> +#include <cassert> +#include <climits> #include <map> #include <string> #include <vector> -#include "sim/host.hh" // for Tick - #include "base/fast_alloc.hh" +#include "base/flags.hh" #include "base/misc.hh" #include "base/trace.hh" #include "sim/serialize.hh" +#include "sim/host.hh" -class EventQueue; // forward declaration - -////////////////////// -// -// Main Event Queue -// -// Events on this queue are processed at the *beginning* of each -// cycle, before the pipeline simulation is performed. -// -// defined in eventq.cc -// -////////////////////// -extern EventQueue mainEventQueue; +class EventQueue; // forward declaration +extern EventQueue mainEventQueue; /* * An item on an event queue. The action caused by a given * event is specified by deriving a subclass and overriding the * process() member function. + * + * Caution, the order of members is chosen to maximize data packing. */ class Event : public Serializable, public FastAlloc { friend class EventQueue; + protected: + typedef short FlagsType; + typedef ::Flags<FlagsType> Flags; + + static const FlagsType PublicRead = 0x003f; + static const FlagsType PublicWrite = 0x001d; + static const FlagsType Squashed = 0x0001; + static const FlagsType Scheduled = 0x0002; + static const FlagsType AutoDelete = 0x0004; + static const FlagsType AutoSerialize = 0x0008; + static const FlagsType IsExitEvent = 0x0010; + static const FlagsType IsMainQueue = 0x0020; +#ifdef EVENTQ_DEBUG + static const FlagsType Initialized = 0xf000; +#endif + private: + // The event queue is now a linked list of linked lists. The + // 'nextBin' pointer is to find the bin, where a bin is defined as + // when+priority. All events in the same bin will be stored in a + // second linked list (a stack) maintained by the 'nextInBin' + // pointer. The list will be accessed in LIFO order. The end + // result is that the insert/removal in 'nextBin' is + // linear/constant, and the lookup/removal in 'nextInBin' is + // constant/constant. Hopefully this is a significant improvement + // over the current fully linear insertion. + Event *nextBin; + Event *nextInBin; + + static Event *insertBefore(Event *event, Event *curr); + static Event *removeItem(Event *event, Event *last); + + Tick _when; //!< timestamp when event should be processed + short _priority; //!< event priority + Flags flags; #ifndef NDEBUG /// Global counter to generate unique IDs for Event instances @@ -84,54 +109,85 @@ class Event : public Serializable, public FastAlloc /// this but they're not consistent across runs making debugging /// more difficult. Thus we use a global counter value when /// debugging. - Counter instanceId; -#endif // NDEBUG + Counter instance; /// queue to which this event belongs (though it may or may not be /// scheduled on this queue yet) EventQueue *queue; +#endif - Event *next; +#ifdef EVENTQ_DEBUG + Tick whenCreated; //!< time created + Tick whenScheduled; //!< time scheduled +#endif - Tick _when; //!< timestamp when event should be processed - int _priority; //!< event priority - char _flags; + void + setWhen(Tick when, EventQueue *q) + { + _when = when; +#ifndef NDEBUG + queue = q; +#endif +#ifdef EVENTQ_DEBUG + whenScheduled = curTick; +#endif + } protected: - enum Flags { - None = 0x0, - Squashed = 0x1, - Scheduled = 0x2, - AutoDelete = 0x4, - AutoSerialize = 0x8, - IsExitEvent = 0x10 - }; + /// Accessor for flags. + Flags + getFlags() const + { + return flags & PublicRead; + } - bool getFlags(Flags f) const { return (_flags & f) == f; } - void setFlags(Flags f) { _flags |= f; } - void clearFlags(Flags f) { _flags &= ~f; } + Flags + getFlags(Flags _flags) const + { + assert(flags.noneSet(~PublicRead)); + return flags.isSet(_flags); + } - protected: - EventQueue *theQueue() const { return queue; } + Flags + allFlags(Flags _flags) const + { + assert(_flags.noneSet(~PublicRead)); + return flags.allSet(_flags); + } -#if TRACING_ON - Tick when_created; //!< Keep track of creation time For debugging - Tick when_scheduled; //!< Keep track of creation time For debugging + /// Accessor for flags. + void + setFlags(Flags _flags) + { + assert(_flags.noneSet(~PublicWrite)); + flags.set(_flags); + } - virtual void trace(const char *action); //!< trace event activity -#else - void trace(const char *) {} -#endif + void + clearFlags(Flags _flags) + { + assert(_flags.noneSet(~PublicWrite)); + flags.clear(_flags); + } - unsigned annotated_value; + void + clearFlags() + { + flags.clear(PublicWrite); + } - public: + // This function isn't really useful if TRACING_ON is not defined + virtual void trace(const char *action); //!< trace event activity + public: /// Event priorities, to provide tie-breakers for events scheduled /// at the same cycle. Most events are scheduled at the default /// priority; these values are used to control events that need to /// be ordered within a cycle. enum Priority { + /// Minimum priority + Minimum_Pri = SHRT_MIN, + /// If we enable tracing on a particular cycle, do that as the /// very first thing so we don't miss any of the events on /// that cycle (even if we enter the debugger). @@ -140,81 +196,66 @@ class Event : public Serializable, public FastAlloc /// Breakpoints should happen before anything else (except /// enabling trace output), so we don't miss any action when /// debugging. - Debug_Break_Pri = -100, + Debug_Break_Pri = -100, /// CPU switches schedule the new CPU's tick event for the /// same cycle (after unscheduling the old CPU's tick event). /// The switch needs to come before any tick events to make /// sure we don't tick both CPUs in the same cycle. - CPU_Switch_Pri = -31, + CPU_Switch_Pri = -31, /// For some reason "delayed" inter-cluster writebacks are /// scheduled before regular writebacks (which have default /// priority). Steve? - Delayed_Writeback_Pri = -1, + Delayed_Writeback_Pri = -1, /// Default is zero for historical reasons. - Default_Pri = 0, + Default_Pri = 0, /// Serailization needs to occur before tick events also, so /// that a serialize/unserialize is identical to an on-line /// CPU switch. - Serialize_Pri = 32, + Serialize_Pri = 32, /// CPU ticks must come after other associated CPU events /// (such as writebacks). - CPU_Tick_Pri = 50, + CPU_Tick_Pri = 50, /// Statistics events (dump, reset, etc.) come after /// everything else, but before exit. - Stat_Event_Pri = 90, + Stat_Event_Pri = 90, /// Progress events come at the end. Progress_Event_Pri = 95, /// If we want to exit on this cycle, it's the very last thing /// we do. - Sim_Exit_Pri = 100 + Sim_Exit_Pri = 100, + + /// Maximum priority + Maximum_Pri = SHRT_MAX }; /* * Event constructor * @param queue that the event gets scheduled on */ - Event(EventQueue *q, Priority p = Default_Pri) - : queue(q), next(NULL), _priority(p), _flags(None), -#if TRACING_ON - when_created(curTick), when_scheduled(0), -#endif - annotated_value(0) + Event(Priority p = Default_Pri) + : nextBin(NULL), nextInBin(NULL), _priority(p) { #ifndef NDEBUG - instanceId = ++instanceCounter; + instance = ++instanceCounter; + queue = NULL; #endif - } - - ~Event() {} - - virtual const std::string name() const { -#ifndef NDEBUG - return csprintf("Event_%d", instanceId); -#else - return csprintf("Event_%x", (uintptr_t)this); +#ifdef EVENTQ_DEBUG + flags.set(Initialized); + whenCreated = curTick; + whenScheduled = 0; #endif } - /// Determine if the current event is scheduled - bool scheduled() const { return getFlags(Scheduled); } - - /// Schedule the event with the current priority or default priority - void schedule(Tick t); - - /// Reschedule the event with the current priority - // always parameter means to schedule if not already scheduled - void reschedule(Tick t, bool always = false); - - /// Remove the event from the current schedule - void deschedule(); + virtual ~Event(); + virtual const std::string name() const; /// Return a C string describing the event. This string should /// *not* be dynamically allocated; just a const char array @@ -222,8 +263,9 @@ class Event : public Serializable, public FastAlloc virtual const char *description() const; /// Dump the current event data - void dump(); + void dump() const; + public: /* * This member function is invoked when the event is processed * (occurs). There is no default implementation; each subclass @@ -236,17 +278,17 @@ class Event : public Serializable, public FastAlloc */ virtual void process() = 0; - void annotate(unsigned value) { annotated_value = value; }; - unsigned annotation() { return annotated_value; } + /// Determine if the current event is scheduled + bool scheduled() const { return flags.isSet(Scheduled); } /// Squash the current event - void squash() { setFlags(Squashed); } + void squash() { flags.set(Squashed); } /// Check whether the event is squashed - bool squashed() { return getFlags(Squashed); } + bool squashed() const { return flags.isSet(Squashed); } /// See if this is a SimExitEvent (without resorting to RTTI) - bool isExitEvent() { return getFlags(IsExitEvent); } + bool isExitEvent() const { return flags.isSet(IsExitEvent); } /// Get the time that the event is scheduled Tick when() const { return _when; } @@ -254,65 +296,20 @@ class Event : public Serializable, public FastAlloc /// Get the event priority int priority() const { return _priority; } - struct priority_compare : - public std::binary_function<Event *, Event *, bool> +#ifndef SWIG + struct priority_compare + : public std::binary_function<Event *, Event *, bool> { - bool operator()(const Event *l, const Event *r) const { + bool + operator()(const Event *l, const Event *r) const + { return l->when() >= r->when() || l->priority() >= r->priority(); } }; virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -template <class T, void (T::* F)()> -void -DelayFunction(Tick when, T *object) -{ - class DelayEvent : public Event - { - private: - T *object; - - public: - DelayEvent(Tick when, T *o) - : Event(&mainEventQueue), object(o) - { setFlags(this->AutoDestroy); schedule(when); } - void process() { (object->*F)(); } - const char *description() const { return "delay"; } - }; - - new DelayEvent(when, object); -} - -template <class T, void (T::* F)()> -class EventWrapper : public Event -{ - private: - T *object; - - public: - EventWrapper(T *obj, bool del = false, - EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) - : Event(q, p), object(obj) - { - if (del) - setFlags(AutoDelete); - } - - EventWrapper(T *obj, Tick t, bool del = false, - EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) - : Event(q, p), object(obj) - { - if (del) - setFlags(AutoDelete); - schedule(t); - } - - void process() { (object->*F)(); } +#endif }; /* @@ -320,18 +317,14 @@ class EventWrapper : public Event */ class EventQueue : public Serializable { - protected: - std::string objName; - private: + std::string objName; Event *head; void insert(Event *event); void remove(Event *event); public: - - // constructor EventQueue(const std::string &n) : objName(n), head(NULL) {} @@ -339,17 +332,19 @@ class EventQueue : public Serializable virtual const std::string name() const { return objName; } // schedule the given event on this queue - void schedule(Event *ev); - void deschedule(Event *ev); - void reschedule(Event *ev); + void schedule(Event *event, Tick when); + void deschedule(Event *event); + void reschedule(Event *event, Tick when, bool always = false); - Tick nextTick() { return head->when(); } + Tick nextTick() const { return head->when(); } 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, // call the internal out-of-line version to process them all. - void serviceEvents(Tick when) { + void + serviceEvents(Tick when) + { while (!empty()) { if (nextTick() > when) break; @@ -367,76 +362,129 @@ class EventQueue : public Serializable void serviceEvents() { serviceEvents(curTick); } // return true if no events are queued - bool empty() { return head == NULL; } + bool empty() const { return head == NULL; } - void dump(); + void dump() const; Tick nextEventTime() { return empty() ? curTick : head->when(); } + bool debugVerify() const; + +#ifndef SWIG virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); +#endif }; +#ifndef SWIG +class EventManager +{ + protected: + /** A pointer to this object's event queue */ + EventQueue *eventq; -////////////////////// -// -// inline functions -// -// can't put these inside declaration due to circular dependence -// between Event and EventQueue classes. -// -////////////////////// + public: + EventManager(EventManager &em) : eventq(em.queue()) {} + EventManager(EventManager *em) : eventq(em ? em->queue() : NULL) {} + EventManager(EventQueue *eq) : eventq(eq) {} -// schedule at specified time (place on event queue specified via -// constructor) -inline void -Event::schedule(Tick t) -{ - assert(!scheduled()); -// if (t < curTick) -// warn("t is less than curTick, ensure you don't want cycles"); + EventQueue * + queue() const + { + return eventq; + } - setFlags(Scheduled); -#if TRACING_ON - when_scheduled = curTick; -#endif - _when = t; - queue->schedule(this); -} + void + schedule(Event &event, Tick when) + { + eventq->schedule(&event, when); + } -inline void -Event::deschedule() + void + deschedule(Event &event) + { + eventq->deschedule(&event); + } + + void + reschedule(Event &event, Tick when, bool always = false) + { + eventq->reschedule(&event, when, always); + } + + void + schedule(Event *event, Tick when) + { + eventq->schedule(event, when); + } + + void + deschedule(Event *event) + { + eventq->deschedule(event); + } + + void + reschedule(Event *event, Tick when, bool always = false) + { + eventq->reschedule(event, when, always); + } +}; + +template <class T, void (T::* F)()> +void +DelayFunction(EventQueue *eventq, Tick when, T *object) { - assert(scheduled()); + class DelayEvent : public Event + { + private: + T *object; + + public: + DelayEvent(T *o) + : object(o) + { this->setFlags(AutoDelete); } + void process() { (object->*F)(); } + const char *description() const { return "delay"; } + }; - clearFlags(Squashed); - clearFlags(Scheduled); - queue->deschedule(this); + eventq->schedule(new DelayEvent(object), when); } -inline void -Event::reschedule(Tick t, bool always) +template <class T, void (T::* F)()> +class EventWrapper : public Event { - assert(scheduled() || always); + private: + T *object; -#if TRACING_ON - when_scheduled = curTick; -#endif - _when = t; - - if (scheduled()) { - clearFlags(Squashed); - queue->reschedule(this); - } else { - setFlags(Scheduled); - queue->schedule(this); + public: + EventWrapper(T *obj, bool del = false, Priority p = Default_Pri) + : Event(p), object(obj) + { + if (del) + setFlags(AutoDelete); } -} + + void process() { (object->*F)(); } +}; inline void -EventQueue::schedule(Event *event) +EventQueue::schedule(Event *event, Tick when) { + assert(when >= curTick); + assert(!event->scheduled()); +#ifdef EVENTQ_DEBUG + assert((event->flags & Event::Initialized) == Event::Initialized); +#endif + + event->setWhen(when, this); insert(event); + event->flags.set(Event::Scheduled); + if (this == &mainEventQueue) + event->flags.set(Event::IsMainQueue); + else + event->flags.clear(Event::IsMainQueue); + if (DTRACE(Event)) event->trace("scheduled"); } @@ -444,20 +492,86 @@ EventQueue::schedule(Event *event) inline void EventQueue::deschedule(Event *event) { + assert(event->scheduled()); +#ifdef EVENTQ_DEBUG + assert((event->flags & Event::Initialized) == Event::Initialized); +#endif + remove(event); + + event->flags.clear(Event::Squashed); + event->flags.clear(Event::Scheduled); + + if (event->flags.isSet(Event::AutoDelete)) + delete event; + if (DTRACE(Event)) event->trace("descheduled"); } inline void -EventQueue::reschedule(Event *event) +EventQueue::reschedule(Event *event, Tick when, bool always) { - remove(event); + assert(when >= curTick); + assert(always || event->scheduled()); +#ifdef EVENTQ_DEBUG + assert((event->flags & Event::Initialized) == Event::Initialized); +#endif + + if (event->scheduled()) + remove(event); + + event->setWhen(when, this); insert(event); + event->flags.clear(Event::Squashed); + event->flags.set(Event::Scheduled); + if (this == &mainEventQueue) + event->flags.set(Event::IsMainQueue); + else + event->flags.clear(Event::IsMainQueue); + if (DTRACE(Event)) event->trace("rescheduled"); } +inline bool +operator<(const Event &l, const Event &r) +{ + return l.when() < r.when() || + (l.when() == r.when() && l.priority() < r.priority()); +} +inline bool +operator>(const Event &l, const Event &r) +{ + return l.when() > r.when() || + (l.when() == r.when() && l.priority() > r.priority()); +} + +inline bool +operator<=(const Event &l, const Event &r) +{ + return l.when() < r.when() || + (l.when() == r.when() && l.priority() <= r.priority()); +} +inline bool +operator>=(const Event &l, const Event &r) +{ + return l.when() > r.when() || + (l.when() == r.when() && l.priority() >= r.priority()); +} + +inline bool +operator==(const Event &l, const Event &r) +{ + return l.when() == r.when() && l.priority() == r.priority(); +} + +inline bool +operator!=(const Event &l, const Event &r) +{ + return l.when() != r.when() || l.priority() != r.priority(); +} +#endif #endif // __SIM_EVENTQ_HH__ diff --git a/src/sim/faults.hh b/src/sim/faults.hh index cfc6ad105..75696641b 100644 --- a/src/sim/faults.hh +++ b/src/sim/faults.hh @@ -41,7 +41,7 @@ class FaultBase; typedef RefCountingPtr<FaultBase> Fault; typedef const char * FaultName; -typedef Stats::Scalar<> FaultStat; +typedef Stats::Scalar FaultStat; // Each class has it's name statically define in _name, // and has a virtual function to access it's name. diff --git a/src/sim/host.hh b/src/sim/host.hh index 93a5fe7f2..dd29534fd 100644 --- a/src/sim/host.hh +++ b/src/sim/host.hh @@ -38,13 +38,11 @@ #define __HOST_HH__ #include <inttypes.h> -#include <limits> - /** uint64_t constant */ -#define ULL(N) ((uint64_t)N##ULL) +#define ULL(N) ((uint64_t)N##ULL) /** int64_t constant */ -#define LL(N) ((int64_t)N##LL) +#define LL(N) ((int64_t)N##LL) /** Statistics counter type. Not much excuse for not using a 64-bit * integer here, but if you're desperate and only run short @@ -58,7 +56,7 @@ typedef int64_t Counter; */ typedef int64_t Tick; -const Tick MaxTick = std::numeric_limits<Tick>::max(); +const Tick MaxTick = LL(0x7fffffffffffffff); /** * Address type diff --git a/src/sim/init.cc b/src/sim/init.cc new file mode 100644 index 000000000..66eddfb6f --- /dev/null +++ b/src/sim/init.cc @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include <Python.h> +#include <marshal.h> +#include <signal.h> + +#include <iostream> +#include <string> +#include <zlib.h> + +#include "base/cprintf.hh" +#include "base/misc.hh" +#include "sim/async.hh" +#include "sim/core.hh" +#include "sim/host.hh" +#include "sim/init.hh" + +using namespace std; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_statdump = true; +} + +void +dumprstStatsHandler(int sigtype) +{ + async_event = true; + async_statdump = true; + async_statreset = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + ccprintf(cerr, "Program aborted at cycle %d\n", curTick); +} + +/* + * M5 can do several special things when various signals are sent. + * None are mandatory. + */ +void +initSignals() +{ + // Floating point exceptions may happen on misspeculated paths, so + // ignore them + signal(SIGFPE, SIG_IGN); + + // We use SIGTRAP sometimes for debugging + signal(SIGTRAP, SIG_IGN); + + // Dump intermediate stats + signal(SIGUSR1, dumpStatsHandler); + + // Dump intermediate stats and reset them + signal(SIGUSR2, dumprstStatsHandler); + + // Exit cleanly on Interrupt (Ctrl-C) + signal(SIGINT, exitNowHandler); + + // Print out cycle number on abort + signal(SIGABRT, abortHandler); +} + +/* + * Uncompress and unmarshal the code object stored in the + * EmbeddedPyModule + */ +PyObject * +getCode(const EmbeddedPyModule *pymod) +{ + assert(pymod->zlen == pymod->code_end - pymod->code); + Bytef *marshalled = new Bytef[pymod->mlen]; + uLongf unzlen = pymod->mlen; + int ret = uncompress(marshalled, &unzlen, (const Bytef *)pymod->code, + pymod->zlen); + if (ret != Z_OK) + panic("Could not uncompress code: %s\n", zError(ret)); + assert(unzlen == pymod->mlen); + + return PyMarshal_ReadObjectFromString((char *)marshalled, pymod->mlen); +} + +// The python library is totally messed up with respect to constness, +// so make a simple macro to make life a little easier +#define PyCC(x) (const_cast<char *>(x)) + +/* + * Load and initialize all of the python parts of M5, including Swig + * and the embedded module importer. + */ +int +initM5Python() +{ + extern void initSwig(); + + // initialize SWIG modules. initSwig() is autogenerated and calls + // all of the individual swig initialization functions. + initSwig(); + + // Load the importer module + PyObject *code = getCode(&embeddedPyImporter); + PyObject *module = PyImport_ExecCodeModule(PyCC("importer"), code); + if (!module) { + PyErr_Print(); + return 1; + } + + // Load the rest of the embedded python files into the embedded + // python importer + const EmbeddedPyModule *pymod = &embeddedPyModules[0]; + while (pymod->filename) { + PyObject *code = getCode(pymod); + PyObject *result = PyObject_CallMethod(module, PyCC("add_module"), + PyCC("ssO"), pymod->filename, pymod->modpath, code); + if (!result) { + PyErr_Print(); + return 1; + } + Py_DECREF(result); + ++pymod; + } + + return 0; +} + +/* + * Start up the M5 simulator. This mostly vectors into the python + * main function. + */ +int +m5Main(int argc, char **argv) +{ + PySys_SetArgv(argc, argv); + + // We have to set things up in the special __main__ module + PyObject *module = PyImport_AddModule(PyCC("__main__")); + if (module == NULL) + panic("Could not import __main__"); + PyObject *dict = PyModule_GetDict(module); + + // import the main m5 module + PyObject *result; + result = PyRun_String("import m5", Py_file_input, dict, dict); + if (!result) { + PyErr_Print(); + return 1; + } + Py_DECREF(result); + + // Start m5 + result = PyRun_String("m5.main()", Py_file_input, dict, dict); + if (!result) { + PyErr_Print(); + return 1; + } + Py_DECREF(result); + + return 0; +} + +PyMODINIT_FUNC +initm5(void) +{ + initM5Python(); + PyImport_ImportModule(PyCC("m5")); +} diff --git a/src/mem/config/prefetch.hh b/src/sim/init.hh index d24db79da..b0f29bf30 100644 --- a/src/mem/config/prefetch.hh +++ b/src/sim/init.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,17 +25,30 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Ron Dreslinski + * Authors: Nathan Binkert */ -/** - * @file - * Central location to configure which prefetch types we want to build - * into the simulator. In the future, this should probably be - * autogenerated by some sort of configuration script. +#ifndef __SIM_INIT_HH__ +#define __SIM_INIT_HH__ + +/* + * Data structure describing an embedded python file. */ -#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no - //prefetching case unless you always want to use a - //different prefetcher -//#define USE_STRIDED 1 -//#define USE_GHB 1 +struct EmbeddedPyModule +{ + const char *filename; + const char *modpath; + const char *code; + const char *code_end; + int zlen; + int mlen; +}; + +extern const EmbeddedPyModule embeddedPyImporter; +extern const EmbeddedPyModule embeddedPyModules[]; + +void initSignals(); +int initM5Python(); +int m5Main(int argc, char **argv); + +#endif // __SIM_INIT_HH__ diff --git a/src/sim/insttracer.hh b/src/sim/insttracer.hh index 9a20c7c56..9fb5f9f22 100644 --- a/src/sim/insttracer.hh +++ b/src/sim/insttracer.hh @@ -34,7 +34,7 @@ #include "base/bigint.hh" #include "base/trace.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum +#include "cpu/inst_seq.hh" // for InstSeqNum #include "cpu/static_inst.hh" #include "sim/host.hh" #include "sim/sim_object.hh" @@ -55,6 +55,8 @@ class InstRecord // dump the record StaticInstPtr staticInst; Addr PC; + StaticInstPtr macroStaticInst; + MicroPC upc; bool misspeculating; // The remaining fields are only valid for particular instruction @@ -71,7 +73,7 @@ class InstRecord } data; enum { DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes + DataInt8 = 1, // set to equal number of bytes DataInt16 = 2, DataInt32 = 4, DataInt64 = 8, @@ -86,10 +88,13 @@ class InstRecord public: InstRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec) + const StaticInstPtr _staticInst, + Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, + MicroPC _upc = 0) : when(_when), thread(_thread), staticInst(_staticInst), PC(_pc), + macroStaticInst(_macroStaticInst), upc(_upc), misspeculating(spec) { data_status = DataInvalid; @@ -137,7 +142,9 @@ class InstTracer : public SimObject virtual InstRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) = 0; + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, + MicroPC _upc = 0) = 0; }; diff --git a/src/sim/main.cc b/src/sim/main.cc index baca556a0..d674e0cff 100644 --- a/src/sim/main.cc +++ b/src/sim/main.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,125 +29,33 @@ */ #include <Python.h> -#include <signal.h> -#include <iostream> -#include <string> - -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "config/pythonhome.hh" -#include "python/swig/init.hh" -#include "sim/async.hh" -#include "sim/host.hh" -#include "sim/core.hh" - -using namespace std; - -/// Stats signal handler. -void -dumpStatsHandler(int sigtype) -{ - async_event = true; - async_statdump = true; -} - -void -dumprstStatsHandler(int sigtype) -{ - async_event = true; - async_statdump = true; - async_statreset = true; -} - -/// Exit signal handler. -void -exitNowHandler(int sigtype) -{ - async_event = true; - async_exit = true; -} - -/// Abort signal handler. -void -abortHandler(int sigtype) -{ - ccprintf(cerr, "Program aborted at cycle %d\n", curTick); -} - -int -python_main() -{ - PyObject *module; - PyObject *dict; - PyObject *result; - - module = PyImport_AddModule(const_cast<char*>("__main__")); - if (module == NULL) - fatal("Could not import __main__"); - - dict = PyModule_GetDict(module); - - result = PyRun_String("import m5.main", Py_file_input, dict, dict); - if (!result) { - PyErr_Print(); - return 1; - } - Py_DECREF(result); - - result = PyRun_String("m5.main.main()", Py_file_input, dict, dict); - if (!result) { - PyErr_Print(); - return 1; - } - Py_DECREF(result); - - if (Py_FlushLine()) - PyErr_Clear(); - - return 0; -} +#include "sim/init.hh" +// main() is now pretty stripped down and just sets up python and then +// calls initM5Python which loads the various embedded python modules +// into the python environment and then starts things running by +// calling m5Main. int main(int argc, char **argv) { - signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths - signal(SIGTRAP, SIG_IGN); - signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats - signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats - signal(SIGINT, exitNowHandler); // dump final stats and exit - signal(SIGABRT, abortHandler); - - Py_SetProgramName(argv[0]); - - // default path to m5 python code is the currently executing - // file... Python ZipImporter will find embedded zip archive. - // The M5_ARCHIVE environment variable can be used to override this. - char *m5_archive = getenv("M5_ARCHIVE"); - string pythonpath = m5_archive ? m5_archive : argv[0]; + int ret; - char *oldpath = getenv("PYTHONPATH"); - if (oldpath != NULL) { - pythonpath += ":"; - pythonpath += oldpath; - } - - if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1) - fatal("setenv: %s\n", strerror(errno)); + // Initialize m5 special signal handling. + initSignals(); - const char *python_home = getenv("PYTHONHOME"); - if (!python_home) - python_home = PYTHONHOME; - Py_SetPythonHome(const_cast<char*>(python_home)); + Py_SetProgramName(argv[0]); // initialize embedded Python interpreter Py_Initialize(); - PySys_SetArgv(argc, argv); - // initialize SWIG modules - init_swig(); + // Initialize the embedded m5 python library + ret = initM5Python(); - int ret = python_main(); + if (ret == 0) { + // start m5 + ret = m5Main(argc, argv); + } // clean up Python intepreter. Py_Finalize(); diff --git a/src/cpu/o3/sparc/cpu.cc b/src/sim/microcode_rom.hh index 1546a2b88..be10de86b 100644 --- a/src/cpu/o3/sparc/cpu.cc +++ b/src/sim/microcode_rom.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,11 +28,25 @@ * Authors: Gabe Black */ -#include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/cpu_impl.hh" -#include "cpu/o3/sparc/dyn_inst.hh" +#ifndef __SIM_MICROCODE_ROM_HH__ +#define __SIM_MICROCODE_ROM_HH__ -// Force instantiation of SparcO3CPU for all the implementations that are -// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (sparc_impl.cc?). -template class SparcO3CPU<SparcSimpleImpl>; +/* + * This is a generic stub microcode ROM ISAs can use if they don't need + * anything more. + */ + +#include "base/misc.hh" +#include "cpu/static_inst.hh" + +class MicrocodeRom +{ + public: + StaticInstPtr + fetchMicroop(MicroPC micropc, StaticInstPtr curMacroop) + { + panic("ROM based microcode isn't implemented.\n"); + } +}; + +#endif // __SIM_MICROCODE_ROM_HH__ diff --git a/src/sim/process.cc b/src/sim/process.cc index 16037b2f4..4be97f2f6 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -46,6 +46,7 @@ #include "mem/translating_port.hh" #include "params/Process.hh" #include "params/LiveProcess.hh" +#include "sim/debug.hh" #include "sim/process.hh" #include "sim/process_impl.hh" #include "sim/stats.hh" @@ -85,12 +86,23 @@ using namespace TheISA; // current number of allocated processes int num_processes = 0; +template<class IntType> +AuxVector<IntType>::AuxVector(IntType type, IntType val) +{ + a_type = TheISA::htog(type); + a_val = TheISA::htog(val); +} + +template class AuxVector<uint32_t>; +template class AuxVector<uint64_t>; + Process::Process(ProcessParams * params) : SimObject(params), system(params->system), checkpointRestored(false), max_stack_size(params->max_stack_size) { string in = params->input; string out = params->output; + string err = params->errout; // initialize file descriptors to default: same as simulator int stdin_fd, stdout_fd, stderr_fd; @@ -111,7 +123,16 @@ Process::Process(ProcessParams * params) else stdout_fd = Process::openOutputFile(out); - stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + if (err == "stdout" || err == "cout") + stderr_fd = STDOUT_FILENO; + else if (err == "stderr" || err == "cerr") + stderr_fd = STDERR_FILENO; + else if (err == "None") + stderr_fd = -1; + else if (err == out) + stderr_fd = stdout_fd; + else + stderr_fd = Process::openOutputFile(err); M5_pid = system->allocatePID(); // initialize first 3 fds (stdin, stdout, stderr) @@ -131,7 +152,7 @@ Process::Process(ProcessParams * params) fdo = &fd_map[STDERR_FILENO]; fdo->fd = stderr_fd; - fdo->filename = "STDERR"; + fdo->filename = err; fdo->flags = O_WRONLY; fdo->mode = -1; fdo->fileOffset = 0; @@ -182,7 +203,7 @@ Process::openInputFile(const string &filename) int Process::openOutputFile(const string &filename) { - int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); + int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { perror(NULL); @@ -193,33 +214,29 @@ Process::openOutputFile(const string &filename) return fd; } - -int -Process::registerThreadContext(ThreadContext *tc) +ThreadContext * +Process::findFreeContext() { - // add to list - int myIndex = threadContexts.size(); - threadContexts.push_back(tc); - - RemoteGDB *rgdb = new RemoteGDB(system, tc); - GDBListener *gdbl = new GDBListener(rgdb, 7000 + myIndex); - gdbl->listen(); - //gdbl->accept(); - - remoteGDB.push_back(rgdb); - - // return CPU number to caller - return myIndex; + int size = contextIds.size(); + ThreadContext *tc; + for (int i = 0; i < size; ++i) { + tc = system->getThreadContext(contextIds[i]); + if (tc->status() == ThreadContext::Unallocated) { + // inactive context, free to use + return tc; + } + } + return NULL; } void Process::startup() { - if (threadContexts.empty()) - fatal("Process %s is not associated with any CPUs!\n", name()); + if (contextIds.empty()) + fatal("Process %s is not associated with any HW contexts!\n", name()); // first thread context for this process... initialize & enable - ThreadContext *tc = threadContexts[0]; + ThreadContext *tc = system->getThreadContext(contextIds[0]); // mark this context as active so it will start ticking. tc->activate(0); @@ -232,17 +249,6 @@ Process::startup() initVirtMem->setPeer(mem_port); } -void -Process::replaceThreadContext(ThreadContext *tc, int tcIndex) -{ - if (tcIndex >= threadContexts.size()) { - panic("replaceThreadContext: bad tcIndex, %d >= %d\n", - tcIndex, threadContexts.size()); - } - - threadContexts[tcIndex] = tc; -} - // map simulator fd sim_fd to target fd tgt_fd void Process::dup_fd(int sim_fd, int tgt_fd) @@ -337,7 +343,7 @@ Process::checkAndAllocNextPage(Addr vaddr) if(stack_base - stack_min > 8*1024*1024) fatal("Over max stack size for one thread\n"); pTable->allocate(stack_min, TheISA::PageBytes); - warn("Increasing stack size by one page."); + inform("Increasing stack size by one page."); }; return true; } @@ -352,6 +358,7 @@ Process::fix_file_offsets() { Process::FdMap *fdo_stderr = &fd_map[STDERR_FILENO]; string in = fdo_stdin->filename; string out = fdo_stdout->filename; + string err = fdo_stderr->filename; // initialize file descriptors to default: same as simulator int stdin_fd, stdout_fd, stderr_fd; @@ -375,11 +382,23 @@ Process::fix_file_offsets() { stdout_fd = -1; else{ stdout_fd = Process::openOutputFile(out); - if (lseek(stdin_fd, fdo_stdout->fileOffset, SEEK_SET) < 0) - panic("Unable to seek to correct in file: %s", out); + if (lseek(stdout_fd, fdo_stdout->fileOffset, SEEK_SET) < 0) + panic("Unable to seek to correct location in file: %s", out); } - stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + if (err == "stdout" || err == "cout") + stderr_fd = STDOUT_FILENO; + else if (err == "stderr" || err == "cerr") + stderr_fd = STDERR_FILENO; + else if (err == "None") + stderr_fd = -1; + else if (err == out) + stderr_fd = stdout_fd; + else { + stderr_fd = Process::openOutputFile(err); + if (lseek(stderr_fd, fdo_stderr->fileOffset, SEEK_SET) < 0) + panic("Unable to seek to correct location in file: %s", err); + } fdo_stdin->fd = stdin_fd; fdo_stdout->fd = stdout_fd; @@ -597,17 +616,18 @@ LiveProcess::argsInit(int intSize, int pageSize) copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); - assert(NumArgumentRegs >= 2); - threadContexts[0]->setIntReg(ArgumentReg[0], argc); - threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); - threadContexts[0]->setIntReg(StackPointerReg, stack_min); + ThreadContext *tc = system->getThreadContext(contextIds[0]); + + setSyscallArg(tc, 0, argc); + setSyscallArg(tc, 1, argv_array_base); + tc->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); - threadContexts[0]->setPC(prog_entry); - threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + tc->setPC(prog_entry); + tc->setNextPC(prog_entry + sizeof(MachInst)); #if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc - threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + tc->setNextNPC(prog_entry + (2 * sizeof(MachInst))); #endif num_processes++; @@ -643,18 +663,17 @@ LiveProcess::create(LiveProcessParams * params) "executable as a static binary and try again.\n"); #if THE_ISA == ALPHA_ISA - if (objFile->hasTLS()) - fatal("Object file has a TLS section and single threaded TLS is not\n" - " currently supported for Alpha! Please recompile your " - "executable with \n a non-TLS toolchain.\n"); - if (objFile->getArch() != ObjectFile::Alpha) fatal("Object file architecture does not match compiled ISA (Alpha)."); + switch (objFile->getOpSys()) { case ObjectFile::Tru64: process = new AlphaTru64Process(params, objFile); break; + case ObjectFile::UnknownOpSys: + warn("Unknown operating system; assuming Linux."); + // fall through case ObjectFile::Linux: process = new AlphaLinuxProcess(params, objFile); break; @@ -663,9 +682,13 @@ LiveProcess::create(LiveProcessParams * params) fatal("Unknown/unsupported operating system."); } #elif THE_ISA == SPARC_ISA - if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32) + if (objFile->getArch() != ObjectFile::SPARC64 && + objFile->getArch() != ObjectFile::SPARC32) fatal("Object file architecture does not match compiled ISA (SPARC)."); switch (objFile->getOpSys()) { + case ObjectFile::UnknownOpSys: + warn("Unknown operating system; assuming Linux."); + // fall through case ObjectFile::Linux: if (objFile->getArch() == ObjectFile::SPARC64) { process = new Sparc64LinuxProcess(params, objFile); @@ -678,16 +701,26 @@ LiveProcess::create(LiveProcessParams * params) case ObjectFile::Solaris: process = new SparcSolarisProcess(params, objFile); break; + default: fatal("Unknown/unsupported operating system."); } #elif THE_ISA == X86_ISA - if (objFile->getArch() != ObjectFile::X86) + if (objFile->getArch() != ObjectFile::X86_64 && + objFile->getArch() != ObjectFile::I386) fatal("Object file architecture does not match compiled ISA (x86)."); switch (objFile->getOpSys()) { + case ObjectFile::UnknownOpSys: + warn("Unknown operating system; assuming Linux."); + // fall through case ObjectFile::Linux: - process = new X86LinuxProcess(params, objFile); + if (objFile->getArch() == ObjectFile::X86_64) { + process = new X86_64LinuxProcess(params, objFile); + } else { + process = new I386LinuxProcess(params, objFile); + } break; + default: fatal("Unknown/unsupported operating system."); } @@ -695,6 +728,9 @@ LiveProcess::create(LiveProcessParams * params) if (objFile->getArch() != ObjectFile::Mips) fatal("Object file architecture does not match compiled ISA (MIPS)."); switch (objFile->getOpSys()) { + case ObjectFile::UnknownOpSys: + warn("Unknown operating system; assuming Linux."); + // fall through case ObjectFile::Linux: process = new MipsLinuxProcess(params, objFile); break; @@ -706,6 +742,9 @@ LiveProcess::create(LiveProcessParams * params) if (objFile->getArch() != ObjectFile::Arm) fatal("Object file architecture does not match compiled ISA (ARM)."); switch (objFile->getOpSys()) { + case ObjectFile::UnknownOpSys: + warn("Unknown operating system; assuming Linux."); + // fall through case ObjectFile::Linux: process = new ArmLinuxProcess(params, objFile); break; diff --git a/src/sim/process.hh b/src/sim/process.hh index 29d6e5aae..527209467 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -44,9 +44,11 @@ #include <string> #include <vector> +#include "arch/types.hh" #include "base/statistics.hh" #include "sim/host.hh" #include "sim/sim_object.hh" +#include "sim/syscallreturn.hh" class GDBListener; class PageTable; @@ -61,6 +63,18 @@ namespace TheISA class RemoteGDB; } +template<class IntType> +struct AuxVector +{ + IntType a_type; + IntType a_val; + + AuxVector() + {} + + AuxVector(IntType type, IntType val); +}; + class Process : public SimObject { public: @@ -77,7 +91,7 @@ class Process : public SimObject bool checkpointRestored; // thread contexts associated with this process - std::vector<ThreadContext *> threadContexts; + std::vector<int> contextIds; // remote gdb objects std::vector<TheISA::RemoteGDB *> remoteGDB; @@ -85,7 +99,7 @@ class Process : public SimObject bool breakpoint(); // number of CPUs (esxec contexts, really) assigned to this process. - unsigned int numCpus() { return threadContexts.size(); } + unsigned int numCpus() { return contextIds.size(); } // record of blocked context struct WaitRec @@ -95,17 +109,17 @@ class Process : public SimObject WaitRec(Addr chan, ThreadContext *ctx) : waitChan(chan), waitingContext(ctx) - { } + { } }; // list of all blocked contexts std::list<WaitRec> waitList; - Addr brk_point; // top of the data segment + Addr brk_point; // top of the data segment - Addr stack_base; // stack segment base (highest address) - unsigned stack_size; // initial stack size - Addr stack_min; // lowest address accessed on the stack + Addr stack_base; // stack segment base (highest address) + unsigned stack_size; // initial stack size + Addr stack_min; // lowest address accessed on the stack // The maximum size allowed for the stack. Addr max_stack_size; @@ -121,9 +135,9 @@ class Process : public SimObject Addr nxm_start; Addr nxm_end; - std::string prog_fname; // file name + std::string prog_fname; // file name - Stats::Scalar<> num_syscalls; // number of syscalls executed + Stats::Scalar num_syscalls; // number of syscalls executed protected: @@ -187,12 +201,15 @@ class Process : public SimObject // override of virtual SimObject method: register statistics virtual void regStats(); - // register a thread context for this process. - // returns tc's cpu number (index into threadContexts[]) - int registerThreadContext(ThreadContext *tc); - + // After getting registered with system object, tell process which + // system-wide context id it is assigned. + void assignThreadContext(int context_id) + { + contextIds.push_back(context_id); + } - void replaceThreadContext(ThreadContext *tc, int tcIndex); + // Find a free context to use + ThreadContext * findFreeContext(); // map simulator fd sim_fd to target fd tgt_fd void dup_fd(int sim_fd, int tgt_fd); @@ -303,7 +320,14 @@ class LiveProcess : public Process return full + filename; } + std::string getcwd() const { return cwd; } + virtual void syscall(int64_t callnum, ThreadContext *tc); + virtual TheISA::IntReg getSyscallArg(ThreadContext *tc, int i) = 0; + virtual void setSyscallArg(ThreadContext *tc, + int i, TheISA::IntReg val) = 0; + virtual void setSyscallReturn(ThreadContext *tc, + SyscallReturn return_value) = 0; virtual SyscallDesc* getDesc(int callnum) = 0; diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index 157d39e93..3c2a27f54 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -35,275 +35,291 @@ #include <fstream> #include <string> +#include "arch/kernel_stats.hh" #include "arch/vtophys.hh" -#include "base/annotate.hh" +#include "base/debug.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "cpu/quiesce_event.hh" -#include "arch/kernel_stats.hh" +#include "params/BaseCPU.hh" #include "sim/pseudo_inst.hh" #include "sim/serialize.hh" +#include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/stat_control.hh" #include "sim/stats.hh" #include "sim/system.hh" -#include "sim/debug.hh" +#if FULL_SYSTEM #include "sim/vptr.hh" +#endif using namespace std; using namespace Stats; using namespace TheISA; -namespace PseudoInst +namespace PseudoInst { + +#if FULL_SYSTEM + +void +arm(ThreadContext *tc) { - void - arm(ThreadContext *tc) - { - if (tc->getKernelStats()) - tc->getKernelStats()->arm(); - } + if (tc->getKernelStats()) + tc->getKernelStats()->arm(); +} - void - quiesce(ThreadContext *tc) - { - if (!tc->getCpuPtr()->params->do_quiesce) - return; +void +quiesce(ThreadContext *tc) +{ + if (!tc->getCpuPtr()->params()->do_quiesce) + return; - DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); + DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); +} - void - quiesceNs(ThreadContext *tc, uint64_t ns) - { - if (!tc->getCpuPtr()->params->do_quiesce || ns == 0) - return; +void +quiesceNs(ThreadContext *tc, uint64_t ns) +{ + if (!tc->getCpuPtr()->params()->do_quiesce || ns == 0) + return; - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); - Tick resume = curTick + Clock::Int::ns * ns; + Tick resume = curTick + Clock::Int::ns * ns; - quiesceEvent->reschedule(resume, true); + mainEventQueue.reschedule(quiesceEvent, resume, true); - DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", - tc->getCpuPtr()->name(), ns, resume); + DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", + tc->getCpuPtr()->name(), ns, resume); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); +} - void - quiesceCycles(ThreadContext *tc, uint64_t cycles) - { - if (!tc->getCpuPtr()->params->do_quiesce || cycles == 0) - return; +void +quiesceCycles(ThreadContext *tc, uint64_t cycles) +{ + if (!tc->getCpuPtr()->params()->do_quiesce || cycles == 0) + return; - EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); - Tick resume = curTick + tc->getCpuPtr()->ticks(cycles); + Tick resume = curTick + tc->getCpuPtr()->ticks(cycles); - quiesceEvent->reschedule(resume, true); + mainEventQueue.reschedule(quiesceEvent, resume, true); - DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", - tc->getCpuPtr()->name(), cycles, resume); + DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", + tc->getCpuPtr()->name(), cycles, resume); - tc->suspend(); - if (tc->getKernelStats()) - tc->getKernelStats()->quiesce(); - } + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); +} - uint64_t - quiesceTime(ThreadContext *tc) - { - return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns; - } +uint64_t +quiesceTime(ThreadContext *tc) +{ + return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns; +} - void - m5exit_old(ThreadContext *tc) - { - exitSimLoop("m5_exit_old instruction encountered"); - } +#endif - void - m5exit(ThreadContext *tc, Tick delay) - { - Tick when = curTick + delay * Clock::Int::ns; - schedExitSimLoop("m5_exit instruction encountered", when); - } +uint64_t +rpns(ThreadContext *tc) +{ + return curTick / Clock::Int::ns; +} + +void +wakeCPU(ThreadContext *tc, uint64_t cpuid) +{ + System *sys = tc->getSystemPtr(); + ThreadContext *other_tc = sys->threadContexts[cpuid]; + if (other_tc->status() == ThreadContext::Suspended) + other_tc->activate(); +} - void - loadsymbol(ThreadContext *tc) - { - const string &filename = tc->getCpuPtr()->system->params()->symbolfile; - if (filename.empty()) { - return; - } +void +m5exit(ThreadContext *tc, Tick delay) +{ + Tick when = curTick + delay * Clock::Int::ns; + Event *event = new SimLoopExitEvent("m5_exit instruction encountered", 0); + mainEventQueue.schedule(event, when); +} + +#if FULL_SYSTEM + +void +loadsymbol(ThreadContext *tc) +{ + const string &filename = tc->getCpuPtr()->system->params()->symbolfile; + if (filename.empty()) { + return; + } - std::string buffer; - ifstream file(filename.c_str()); + std::string buffer; + ifstream file(filename.c_str()); - if (!file) - fatal("file error: Can't open symbol table file %s\n", filename); + if (!file) + fatal("file error: Can't open symbol table file %s\n", filename); - while (!file.eof()) { - getline(file, buffer); + while (!file.eof()) { + getline(file, buffer); - if (buffer.empty()) - continue; + if (buffer.empty()) + continue; - int idx = buffer.find(' '); - if (idx == string::npos) - continue; + int idx = buffer.find(' '); + if (idx == string::npos) + continue; - string address = "0x" + buffer.substr(0, idx); - eat_white(address); - if (address.empty()) - continue; + string address = "0x" + buffer.substr(0, idx); + eat_white(address); + if (address.empty()) + continue; - // Skip over letter and space - string symbol = buffer.substr(idx + 3); - eat_white(symbol); - if (symbol.empty()) - continue; + // Skip over letter and space + string symbol = buffer.substr(idx + 3); + eat_white(symbol); + if (symbol.empty()) + continue; - Addr addr; - if (!to_number(address, addr)) - continue; + Addr addr; + if (!to_number(address, addr)) + continue; - if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) - continue; + if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) + continue; - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - } - file.close(); + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); } + file.close(); +} - void - resetstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; +void +addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) +{ + char symb[100]; + CopyStringOut(tc, symb, symbolAddr, 100); + std::string symbol(symb); + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + debugSymbolTable->insert(addr,symbol); +} - Stats::StatEvent(false, true, when, repeat); - } +#endif - void - dumpstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; +void +resetstats(ThreadContext *tc, Tick delay, Tick period) +{ + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - Stats::StatEvent(true, false, when, repeat); - } + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; - void - addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) - { - char symb[100]; - CopyStringOut(tc, symb, symbolAddr, 100); - std::string symbol(symb); + Stats::StatEvent(false, true, when, repeat); +} - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); +void +dumpstats(ThreadContext *tc, Tick delay, Tick period) +{ + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); - } - void - anBegin(ThreadContext *tc, uint64_t cur) - { - Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur & - 0xFFFFFFFF, 0,0); - } + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; - void - anWait(ThreadContext *tc, uint64_t cur, uint64_t wait) - { - Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur & - 0xFFFFFFFF, wait >> 32, wait & 0xFFFFFFFF); - } + Stats::StatEvent(true, false, when, repeat); +} +void +dumpresetstats(ThreadContext *tc, Tick delay, Tick period) +{ + if (!tc->getCpuPtr()->params()->do_statistics_insts) + return; - void - dumpresetstats(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_statistics_insts) - return; + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + Stats::StatEvent(true, true, when, repeat); +} - Stats::StatEvent(true, true, when, repeat); - } +void +m5checkpoint(ThreadContext *tc, Tick delay, Tick period) +{ + if (!tc->getCpuPtr()->params()->do_checkpoint_insts) + return; - void - m5checkpoint(ThreadContext *tc, Tick delay, Tick period) - { - if (!tc->getCpuPtr()->params->do_checkpoint_insts) - return; + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; + Event *event = new SimLoopExitEvent("checkpoint", 0, repeat); + mainEventQueue.schedule(event, when); +} - schedExitSimLoop("checkpoint", when, repeat); - } +#if FULL_SYSTEM - uint64_t - readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) - { - const string &file = tc->getSystemPtr()->params()->readfile; - if (file.empty()) { - return ULL(0); - } - - uint64_t result = 0; - - int fd = ::open(file.c_str(), O_RDONLY, 0); - if (fd < 0) - panic("could not open file %s\n", file); - - if (::lseek(fd, offset, SEEK_SET) < 0) - panic("could not seek: %s", strerror(errno)); - - char *buf = new char[len]; - char *p = buf; - while (len > 0) { - int bytes = ::read(fd, p, len); - if (bytes <= 0) - break; - - p += bytes; - result += bytes; - len -= bytes; - } - - close(fd); - CopyIn(tc, vaddr, buf, result); - delete [] buf; - return result; +uint64_t +readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) +{ + const string &file = tc->getSystemPtr()->params()->readfile; + if (file.empty()) { + return ULL(0); } - void debugbreak(ThreadContext *tc) - { - debug_break(); - } + uint64_t result = 0; - void switchcpu(ThreadContext *tc) - { - exitSimLoop("switchcpu"); + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); + + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); + + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; + + p += bytes; + result += bytes; + len -= bytes; } + + close(fd); + CopyIn(tc, vaddr, buf, result); + delete [] buf; + return result; } + +#endif + +void +debugbreak(ThreadContext *tc) +{ + debug_break(); +} + +void +switchcpu(ThreadContext *tc) +{ + exitSimLoop("switchcpu"); +} + +/* namespace PseudoInst */ } diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh index 93021abad..30996fc3b 100644 --- a/src/sim/pseudo_inst.hh +++ b/src/sim/pseudo_inst.hh @@ -33,31 +33,35 @@ class ThreadContext; //We need the "Tick" and "Addr" data types from here #include "sim/host.hh" -namespace PseudoInst -{ - /** - * @todo these externs are only here for a hack in fullCPU::takeOver... - */ - extern bool doStatisticsInsts; - extern bool doCheckpointInsts; - extern bool doQuiesce; +namespace PseudoInst { - void arm(ThreadContext *tc); - void quiesce(ThreadContext *tc); - void quiesceNs(ThreadContext *tc, uint64_t ns); - void quiesceCycles(ThreadContext *tc, uint64_t cycles); - uint64_t quiesceTime(ThreadContext *tc); - void m5exit(ThreadContext *tc, Tick delay); - void m5exit_old(ThreadContext *tc); - void loadsymbol(ThreadContext *xc); - void resetstats(ThreadContext *tc, Tick delay, Tick period); - void dumpstats(ThreadContext *tc, Tick delay, Tick period); - void dumpresetstats(ThreadContext *tc, Tick delay, Tick period); - void m5checkpoint(ThreadContext *tc, Tick delay, Tick period); - uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset); - void debugbreak(ThreadContext *tc); - void switchcpu(ThreadContext *tc); - void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr); - void anBegin(ThreadContext *tc, uint64_t cur); - void anWait(ThreadContext *tc, uint64_t cur, uint64_t wait); -} +/** + * @todo these externs are only here for a hack in fullCPU::takeOver... + */ +extern bool doStatisticsInsts; +extern bool doCheckpointInsts; +extern bool doQuiesce; + +#if FULL_SYSTEM +void arm(ThreadContext *tc); +void quiesce(ThreadContext *tc); +void quiesceNs(ThreadContext *tc, uint64_t ns); +void quiesceCycles(ThreadContext *tc, uint64_t cycles); +uint64_t quiesceTime(ThreadContext *tc); +uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, + uint64_t offset); +void loadsymbol(ThreadContext *xc); +void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr); +#endif + +uint64_t rpns(ThreadContext *tc); +void wakeCPU(ThreadContext *tc, uint64_t cpuid); +void m5exit(ThreadContext *tc, Tick delay); +void resetstats(ThreadContext *tc, Tick delay, Tick period); +void dumpstats(ThreadContext *tc, Tick delay, Tick period); +void dumpresetstats(ThreadContext *tc, Tick delay, Tick period); +void m5checkpoint(ThreadContext *tc, Tick delay, Tick period); +void debugbreak(ThreadContext *tc); +void switchcpu(ThreadContext *tc); + +/* namespace PseudoInst */ } diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc index a0d17f489..481b9af3b 100644 --- a/src/sim/serialize.cc +++ b/src/sim/serialize.cc @@ -321,23 +321,23 @@ objParamIn(Checkpoint *cp, const std::string §ion, } -#define INSTANTIATE_PARAM_TEMPLATES(type) \ -template void \ -paramOut(ostream &os, const std::string &name, type const ¶m); \ -template void \ -paramIn(Checkpoint *cp, const std::string §ion, \ - const std::string &name, type & param); \ -template void \ -arrayParamOut(ostream &os, const std::string &name, \ - type const *param, int size); \ -template void \ -arrayParamIn(Checkpoint *cp, const std::string §ion, \ +#define INSTANTIATE_PARAM_TEMPLATES(type) \ +template void \ +paramOut(ostream &os, const std::string &name, type const ¶m); \ +template void \ +paramIn(Checkpoint *cp, const std::string §ion, \ + const std::string &name, type & param); \ +template void \ +arrayParamOut(ostream &os, const std::string &name, \ + type const *param, int size); \ +template void \ +arrayParamIn(Checkpoint *cp, const std::string §ion, \ const std::string &name, type *param, int size); \ -template void \ -arrayParamOut(ostream &os, const std::string &name, \ - const std::vector<type> ¶m); \ -template void \ -arrayParamIn(Checkpoint *cp, const std::string §ion, \ +template void \ +arrayParamOut(ostream &os, const std::string &name, \ + const std::vector<type> ¶m); \ +template void \ +arrayParamIn(Checkpoint *cp, const std::string §ion, \ const std::string &name, std::vector<type> ¶m); INSTANTIATE_PARAM_TEMPLATES(signed char) @@ -351,6 +351,8 @@ INSTANTIATE_PARAM_TEMPLATES(unsigned long) INSTANTIATE_PARAM_TEMPLATES(signed long long) INSTANTIATE_PARAM_TEMPLATES(unsigned long long) INSTANTIATE_PARAM_TEMPLATES(bool) +INSTANTIATE_PARAM_TEMPLATES(float) +INSTANTIATE_PARAM_TEMPLATES(double) INSTANTIATE_PARAM_TEMPLATES(string) @@ -394,6 +396,24 @@ Globals::unserialize(Checkpoint *cp) mainEventQueue.unserialize(cp, "MainEventQueue"); } +Serializable::Serializable() +{ +} + +Serializable::~Serializable() +{ +} + +void +Serializable::serialize(std::ostream &os) +{ +} + +void +Serializable::unserialize(Checkpoint *cp, const std::string §ion) +{ +} + void Serializable::serializeAll(const std::string &cpt_dir) { @@ -405,6 +425,8 @@ Serializable::serializeAll(const std::string &cpt_dir) string cpt_file = dir + Checkpoint::baseFilename; ofstream outstream(cpt_file.c_str()); time_t t = time(NULL); + if (!outstream.is_open()) + fatal("Unable to open file %s for writing\n", cpt_file.c_str()); outstream << "// checkpoint generated: " << ctime(&t); globals.serialize(outstream); diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index e72eedb30..c33633065 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -82,33 +82,33 @@ objParamIn(Checkpoint *cp, const std::string §ion, // These macros are streamlined to use in serialize/unserialize // functions. It's assumed that serialize() has a parameter 'os' for // the ostream, and unserialize() has parameters 'cp' and 'section'. -#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar) +#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar) -#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar) +#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar) // ENUMs are like SCALARs, but we cast them to ints on the way out -#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar) +#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar) -#define UNSERIALIZE_ENUM(scalar) \ - do { \ - int tmp; \ - paramIn(cp, section, #scalar, tmp); \ - scalar = (typeof(scalar))tmp; \ +#define UNSERIALIZE_ENUM(scalar) \ + do { \ + int tmp; \ + paramIn(cp, section, #scalar, tmp); \ + scalar = (typeof(scalar))tmp; \ } while (0) -#define SERIALIZE_ARRAY(member, size) \ +#define SERIALIZE_ARRAY(member, size) \ arrayParamOut(os, #member, member, size) -#define UNSERIALIZE_ARRAY(member, size) \ +#define UNSERIALIZE_ARRAY(member, size) \ arrayParamIn(cp, section, #member, member, size) -#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name()) +#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name()) -#define UNSERIALIZE_OBJPTR(objptr) \ - do { \ - SimObject *sptr; \ - objParamIn(cp, section, #objptr, sptr); \ - objptr = dynamic_cast<typeof(objptr)>(sptr); \ +#define UNSERIALIZE_OBJPTR(objptr) \ + do { \ + SimObject *sptr; \ + objParamIn(cp, section, #objptr, sptr); \ + objptr = dynamic_cast<typeof(objptr)>(sptr); \ } while (0) /* @@ -121,17 +121,16 @@ class Serializable void nameOut(std::ostream &os, const std::string &_name); public: - Serializable() {} - virtual ~Serializable() {} + Serializable(); + virtual ~Serializable(); // manditory virtual function, so objects must provide names virtual const std::string name() const = 0; - virtual void serialize(std::ostream &os) {} - virtual void unserialize(Checkpoint *cp, const std::string §ion) {} + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); - static Serializable *create(Checkpoint *cp, - const std::string §ion); + static Serializable *create(Checkpoint *cp, const std::string §ion); static int ckptCount; static int ckptMaxCount; @@ -211,8 +210,8 @@ class SerializableClass // SerializableBuilder and SerializableClass objects // -#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \ -SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ +#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \ +SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ OBJ_CLASS::createForUnserialize); void diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc index 09087ef84..a6e3f0af3 100644 --- a/src/sim/sim_events.cc +++ b/src/sim/sim_events.cc @@ -40,6 +40,13 @@ using namespace std; +SimLoopExitEvent::SimLoopExitEvent(const std::string &_cause, int c, Tick r) + : Event(Sim_Exit_Pri), cause(_cause), code(c), repeat(r) +{ + setFlags(IsExitEvent); +} + + // // handle termination event // @@ -49,7 +56,7 @@ SimLoopExitEvent::process() // 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) { + if (!getFlags(IsMainQueue)) { exitSimLoop(cause, code); delete this; } @@ -59,7 +66,8 @@ SimLoopExitEvent::process() // but if you are doing this on intervals, don't forget to make another if (repeat) { - schedule(curTick + repeat); + assert(getFlags(IsMainQueue)); + mainEventQueue.schedule(this, curTick + repeat); } } @@ -70,43 +78,32 @@ SimLoopExitEvent::description() const return "simulation loop exit"; } -SimLoopExitEvent * -schedExitSimLoop(const std::string &message, Tick when, Tick repeat, - EventQueue *q, int exit_code) -{ - if (q == NULL) - q = &mainEventQueue; - - return new SimLoopExitEvent(q, when, repeat, message, exit_code); -} - void exitSimLoop(const std::string &message, int exit_code) { - schedExitSimLoop(message, curTick, 0, NULL, exit_code); + Event *event = new SimLoopExitEvent(message, exit_code); + mainEventQueue.schedule(event, curTick); } +CountedDrainEvent::CountedDrainEvent() + : SimLoopExitEvent("Finished drain", 0), count(0) +{ } + void CountedDrainEvent::process() { - if (--count == 0) { - exitSimLoop("Finished drain"); - } + if (--count == 0) + exitSimLoop(cause, code); } // // constructor: automatically schedules at specified time // -CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause, - Tick _when, int &_downCounter) - : Event(q, Sim_Exit_Pri), - cause(_cause), - downCounter(_downCounter) +CountedExitEvent::CountedExitEvent(const std::string &_cause, int &counter) + : Event(Sim_Exit_Pri), cause(_cause), downCounter(counter) { // catch stupid mistakes assert(downCounter > 0); - - schedule(_when); } @@ -128,9 +125,11 @@ CountedExitEvent::description() const return "counted exit"; } -#ifdef CHECK_SWAP_CYCLES -new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES); -#endif +CheckSwapEvent::CheckSwapEvent(int ival) + : interval(ival) +{ + mainEventQueue.schedule(this, curTick + interval); +} void CheckSwapEvent::process() @@ -149,7 +148,8 @@ CheckSwapEvent::process() exitSimLoop("Lack of swap space"); } - schedule(curTick + interval); + assert(getFlags(IsMainQueue)); + mainEventQueue.schedule(this, curTick + interval); } const char * diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh index 58ec963c0..ffd31f385 100644 --- a/src/sim/sim_events.hh +++ b/src/sim/sim_events.hh @@ -38,35 +38,19 @@ // class SimLoopExitEvent : public Event { - private: + protected: // string explaining why we're terminating std::string cause; int code; Tick repeat; public: - // Default constructor. Only really used for derived classes. - SimLoopExitEvent() - : Event(&mainEventQueue, Sim_Exit_Pri) - { } - - SimLoopExitEvent(EventQueue *q, - Tick _when, Tick _repeat, const std::string &_cause, - int c = 0) - : Event(q, Sim_Exit_Pri), cause(_cause), - code(c), repeat(_repeat) - { setFlags(IsExitEvent); schedule(_when); } - -// SimLoopExitEvent(EventQueue *q, -// Tick _when, const std::string &_cause, -// Tick _repeat = 0, int c = 0) -// : Event(q, Sim_Exit_Pri), cause(_cause), code(c), repeat(_repeat) -// { setFlags(IsExitEvent); schedule(_when); } + SimLoopExitEvent(const std::string &_cause, int c, Tick repeat = 0); std::string getCause() { return cause; } int getCode() { return code; } - void process(); // process event + void process(); // process event virtual const char *description() const; }; @@ -76,10 +60,10 @@ class CountedDrainEvent : public SimLoopExitEvent private: // Count of how many objects have not yet drained int count; + public: - CountedDrainEvent() - : count(0) - { } + CountedDrainEvent(); + void process(); void setCount(int _count) { count = _count; } @@ -95,14 +79,13 @@ class CountedDrainEvent : public SimLoopExitEvent class CountedExitEvent : public Event { private: - std::string cause; // string explaining why we're terminating - int &downCounter; // decrement & terminate if zero + std::string cause; // string explaining why we're terminating + int &downCounter; // decrement & terminate if zero public: - CountedExitEvent(EventQueue *q, const std::string &_cause, - Tick _when, int &_downCounter); + CountedExitEvent(const std::string &_cause, int &_downCounter); - void process(); // process event + void process(); // process event virtual const char *description() const; }; @@ -116,11 +99,8 @@ class CheckSwapEvent : public Event int interval; public: - CheckSwapEvent(EventQueue *q, int ival) - : Event(q), interval(ival) - { schedule(curTick + interval); } - - void process(); // process event + CheckSwapEvent(int ival); + void process(); // process event virtual const char *description() const; }; diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh index d4b31d1ea..174b00024 100644 --- a/src/sim/sim_exit.hh +++ b/src/sim/sim_exit.hh @@ -46,14 +46,6 @@ class SimLoopExitEvent; void registerExitCallback(Callback *); /// 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. -SimLoopExitEvent *schedExitSimLoop(const std::string &message, Tick when, - Tick repeat = 0, EventQueue *q = NULL, - 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. diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index a835aee5b..dad8f6e8b 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -59,7 +59,7 @@ SimObject::SimObjectList SimObject::simObjectList; // SimObject constructor: used to maintain static simObjectList // SimObject::SimObject(const Params *p) - : _params(p) + : EventManager(p->eventq), _params(p) { #ifdef DEBUG doDebugBreak = false; @@ -69,14 +69,6 @@ SimObject::SimObject(const Params *p) state = Running; } -SimObjectParams * -SimObject::makeParams(const std::string &name) -{ - SimObjectParams *params = new SimObjectParams; - params->name = name; - return params; -} - void SimObject::init() { diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index ec565ce82..d6d08f255 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -36,12 +36,14 @@ #ifndef __SIM_OBJECT_HH__ #define __SIM_OBJECT_HH__ -#include <map> +#include <iostream> #include <list> +#include <map> +#include <string> #include <vector> -#include <iostream> #include "params/SimObject.hh" +#include "sim/eventq.hh" #include "sim/serialize.hh" #include "sim/startup.hh" @@ -53,7 +55,8 @@ class Event; * correspond to physical components and can be specified via the * config file (CPUs, caches, etc.). */ -class SimObject : public Serializable, protected StartupCallback +class SimObject + : public EventManager, public Serializable, protected StartupCallback { public: enum State { @@ -86,10 +89,6 @@ class SimObject : public Serializable, protected StartupCallback SimObject(const Params *_params); virtual ~SimObject() {} - protected: - // static: support for old-style constructors (call manually) - static Params *makeParams(const std::string &name); - public: virtual const std::string name() const { return params()->name; } diff --git a/src/sim/sim_object_params.hh b/src/sim/sim_object_params.hh new file mode 100644 index 000000000..750181135 --- /dev/null +++ b/src/sim/sim_object_params.hh @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __SIM_SIM_OBJECT_PARAMS_HH__ +#define __SIM_SIM_OBJECT_PARAMS_HH__ + +#ifndef PY_VERSION +struct PyObject; +#endif + +#include <string> + +struct EventQueue; + +struct SimObjectParams +{ + SimObjectParams() + { + extern EventQueue mainEventQueue; + eventq = &mainEventQueue; + } + virtual ~SimObjectParams() {} + + std::string name; + PyObject *pyobj; + EventQueue *eventq; +}; + + +#endif // __SIM_SIM_OBJECT_PARAMS_HH__ diff --git a/src/sim/simulate.cc b/src/sim/simulate.cc index 36bdff45e..1ac2c80df 100644 --- a/src/sim/simulate.cc +++ b/src/sim/simulate.cc @@ -47,7 +47,7 @@ SimLoopExitEvent * simulate(Tick num_cycles) { - warn("Entering event queue @ %d. Starting simulation...\n", curTick); + inform("Entering event queue @ %d. Starting simulation...\n", curTick); if (num_cycles < 0) fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); @@ -56,8 +56,9 @@ simulate(Tick num_cycles) else num_cycles = curTick + num_cycles; - Event *limit_event; - limit_event = schedExitSimLoop("simulate() limit reached", num_cycles); + Event *limit_event = + new SimLoopExitEvent("simulate() limit reached", 0); + mainEventQueue.schedule(limit_event, num_cycles); while (1) { // there should always be at least one event (the SimLoopExitEvent @@ -82,8 +83,8 @@ simulate(Tick num_cycles) // if we didn't hit limit_event, delete it if (se_event != limit_event) { assert(limit_event->scheduled()); - limit_event->deschedule(); - delete limit_event; + limit_event->squash(); + hack_once("be nice to actually delete the event here"); } return se_event; diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc index 228c83898..2dcf4798d 100644 --- a/src/sim/stat_control.cc +++ b/src/sim/stat_control.cc @@ -44,14 +44,6 @@ using namespace std; -Stats::Formula hostInstRate; -Stats::Formula hostTickRate; -Stats::Value hostMemory; -Stats::Value hostSeconds; - -Stats::Value simTicks; -Stats::Value simInsts; -Stats::Value simFreq; Stats::Formula simSeconds; namespace Stats { @@ -84,8 +76,21 @@ statElapsedTicks() SimTicksReset simTicksReset; -void -initSimStats() +struct Global +{ + Stats::Formula hostInstRate; + Stats::Formula hostTickRate; + Stats::Value hostMemory; + Stats::Value hostSeconds; + + Stats::Value simTicks; + Stats::Value simInsts; + Stats::Value simFreq; + + Global(); +}; + +Global::Global() { simInsts .functor(BaseCPU::numSimulatedInstructions) @@ -146,6 +151,12 @@ initSimStats() registerResetCallback(&simTicksReset); } +void +initSimStats() +{ + static Global global; +} + class _StatEvent : public Event { private: @@ -154,12 +165,10 @@ class _StatEvent : public Event Tick repeat; public: - _StatEvent(bool _dump, bool _reset, Tick _when, Tick _repeat) - : Event(&mainEventQueue, Stat_Event_Pri), dump(_dump), reset(_reset), - repeat(_repeat) + _StatEvent(bool _dump, bool _reset, Tick _repeat) + : Event(Stat_Event_Pri), dump(_dump), reset(_reset), repeat(_repeat) { setFlags(AutoDelete); - schedule(_when); } virtual void @@ -171,15 +180,18 @@ class _StatEvent : public Event if (reset) Stats::reset(); - if (repeat) - new _StatEvent(dump, reset, curTick + repeat, repeat); + if (repeat) { + Event *event = new _StatEvent(dump, reset, repeat); + mainEventQueue.schedule(event, curTick + repeat); + } } }; void StatEvent(bool dump, bool reset, Tick when, Tick repeat) { - new _StatEvent(dump, reset, when, repeat); + Event *event = new _StatEvent(dump, reset, repeat); + mainEventQueue.schedule(event, when); } /* namespace Stats */ } diff --git a/src/sim/stats.hh b/src/sim/stats.hh index 97251283d..481c36cf6 100644 --- a/src/sim/stats.hh +++ b/src/sim/stats.hh @@ -34,6 +34,5 @@ #include "base/statistics.hh" extern Stats::Formula simSeconds; -extern Stats::Value simTicks; #endif // __SIM_SIM_STATS_HH__ diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc index f4b9b7ae3..5fe30c269 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -53,8 +53,8 @@ SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) { DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", curTick,tc->getCpuPtr()->name(), name, - tc->getSyscallArg(0),tc->getSyscallArg(1), - tc->getSyscallArg(2),tc->getSyscallArg(3)); + process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1), + process->getSyscallArg(tc, 2), process->getSyscallArg(tc, 3)); SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); @@ -62,7 +62,7 @@ SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) curTick,tc->getCpuPtr()->name(), name, retval.value()); if (!(flags & SyscallDesc::SuppressReturnValue)) - tc->setSyscallReturn(retval); + process->setSyscallReturn(tc, retval); } @@ -81,7 +81,7 @@ ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { warn("ignoring syscall %s(%d, %d, ...)", desc->name, - tc->getSyscallArg(0), tc->getSyscallArg(1)); + process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1)); return 0; } @@ -92,7 +92,8 @@ exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { if (tc->exit()) { - exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff); + exitSimLoop("target called exit()", + process->getSyscallArg(tc, 0) & 0xff); } return 1; @@ -107,21 +108,27 @@ getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn -obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) +brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - Addr junk; - // change brk addr to first arg - Addr new_brk = tc->getSyscallArg(0); - if (new_brk != 0) { + Addr new_brk = p->getSyscallArg(tc, 0); + + // in Linux at least, brk(0) returns the current break value + // (note that the syscall and the glibc function have different behavior) + if (new_brk == 0) + return p->brk_point; + + if (new_brk > p->brk_point) { + // might need to allocate some new pages for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, VMPageSize); !gen.done(); gen.next()) { - if (!p->pTable->translate(gen.addr(), junk)) + if (!p->pTable->translate(gen.addr())) p->pTable->allocate(roundDown(gen.addr(), VMPageSize), VMPageSize); } - p->brk_point = new_brk; } + + p->brk_point = new_brk; DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); return p->brk_point; } @@ -130,7 +137,7 @@ obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int target_fd = tc->getSyscallArg(0); + int target_fd = p->getSyscallArg(tc, 0); int status = close(p->sim_fd(target_fd)); if (status >= 0) p->free_fd(target_fd); @@ -141,9 +148,9 @@ closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int fd = p->sim_fd(tc->getSyscallArg(0)); - int nbytes = tc->getSyscallArg(2); - BufferArg bufArg(tc->getSyscallArg(1), nbytes); + int fd = p->sim_fd(p->getSyscallArg(tc, 0)); + int nbytes = p->getSyscallArg(tc, 2); + BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes); int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); @@ -156,9 +163,9 @@ readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int fd = p->sim_fd(tc->getSyscallArg(0)); - int nbytes = tc->getSyscallArg(2); - BufferArg bufArg(tc->getSyscallArg(1), nbytes); + int fd = p->sim_fd(p->getSyscallArg(tc, 0)); + int nbytes = p->getSyscallArg(tc, 2); + BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes); bufArg.copyIn(tc->getMemPort()); @@ -173,9 +180,9 @@ writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int fd = p->sim_fd(tc->getSyscallArg(0)); - uint64_t offs = tc->getSyscallArg(1); - int whence = tc->getSyscallArg(2); + int fd = p->sim_fd(p->getSyscallArg(tc, 0)); + uint64_t offs = p->getSyscallArg(tc, 1); + int whence = p->getSyscallArg(tc, 2); off_t result = lseek(fd, offs, whence); @@ -186,11 +193,11 @@ lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn _llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int fd = p->sim_fd(tc->getSyscallArg(0)); - uint64_t offset_high = tc->getSyscallArg(1); - uint32_t offset_low = tc->getSyscallArg(2); - Addr result_ptr = tc->getSyscallArg(3); - int whence = tc->getSyscallArg(4); + int fd = p->sim_fd(p->getSyscallArg(tc, 0)); + uint64_t offset_high = p->getSyscallArg(tc, 1); + uint32_t offset_low = p->getSyscallArg(tc, 2); + Addr result_ptr = p->getSyscallArg(tc, 3); + int whence = p->getSyscallArg(tc, 4); uint64_t offset = (offset_high << 32) | offset_low; @@ -229,8 +236,8 @@ const char *hostname = "m5.eecs.umich.edu"; SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - int name_len = tc->getSyscallArg(1); - BufferArg name(tc->getSyscallArg(0), name_len); + int name_len = p->getSyscallArg(tc, 1); + BufferArg name(p->getSyscallArg(tc, 0), name_len); strncpy((char *)name.bufferPtr(), hostname, name_len); @@ -240,11 +247,64 @@ gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) } SyscallReturn +getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) +{ + int result = 0; + unsigned long size = p->getSyscallArg(tc, 1); + BufferArg buf(p->getSyscallArg(tc, 0), size); + + // Is current working directory defined? + string cwd = p->getcwd(); + if (!cwd.empty()) { + if (cwd.length() >= size) { + // Buffer too small + return -ERANGE; + } + strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); + result = cwd.length(); + } + else { + if (getcwd((char *)buf.bufferPtr(), size) != NULL) { + result = strlen((char *)buf.bufferPtr()); + } + else { + result = -1; + } + } + + buf.copyOut(tc->getMemPort()); + + return (result == -1) ? -errno : result; +} + + +SyscallReturn +readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) +{ + string path; + + if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0))) + return (TheISA::IntReg)-EFAULT; + + // Adjust path for current working directory + path = p->fullPath(path); + + size_t bufsiz = p->getSyscallArg(tc, 2); + BufferArg buf(p->getSyscallArg(tc, 1), bufsiz); + + int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); + + buf.copyOut(tc->getMemPort()); + + return (result == -1) ? -errno : result; +} + +SyscallReturn unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0))) return (TheISA::IntReg)-EFAULT; // Adjust path for current working directory @@ -254,17 +314,35 @@ unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) return (result == -1) ? -errno : result; } + +SyscallReturn +mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) +{ + string path; + + if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0))) + return (TheISA::IntReg)-EFAULT; + + // Adjust path for current working directory + path = p->fullPath(path); + + mode_t mode = p->getSyscallArg(tc, 1); + + int result = mkdir(path.c_str(), mode); + return (result == -1) ? -errno : result; +} + SyscallReturn renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { string old_name; - if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, 0))) return -EFAULT; string new_name; - if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1))) + if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, 1))) return -EFAULT; // Adjust path for current working directory @@ -280,10 +358,10 @@ truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0))) return -EFAULT; - off_t length = tc->getSyscallArg(1); + off_t length = p->getSyscallArg(tc, 1); // Adjust path for current working directory path = p->fullPath(path); @@ -295,29 +373,40 @@ truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) { - int fd = process->sim_fd(tc->getSyscallArg(0)); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); if (fd < 0) return -EBADF; - off_t length = tc->getSyscallArg(1); + off_t length = process->getSyscallArg(tc, 1); int result = ftruncate(fd, length); return (result == -1) ? -errno : result; } SyscallReturn +umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) +{ + // Letting the simulated program change the simulator's umask seems like + // a bad idea. Compromise by just returning the current umask but not + // changing anything. + mode_t oldMask = umask(0); + umask(oldMask); + return (int)oldMask; +} + +SyscallReturn chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0))) return -EFAULT; /* XXX endianess */ - uint32_t owner = tc->getSyscallArg(1); + uint32_t owner = p->getSyscallArg(tc, 1); uid_t hostOwner = owner; - uint32_t group = tc->getSyscallArg(2); + uint32_t group = p->getSyscallArg(tc, 2); gid_t hostGroup = group; // Adjust path for current working directory @@ -330,15 +419,15 @@ chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) SyscallReturn fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) { - int fd = process->sim_fd(tc->getSyscallArg(0)); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); if (fd < 0) return -EBADF; /* XXX endianess */ - uint32_t owner = tc->getSyscallArg(1); + uint32_t owner = process->getSyscallArg(tc, 1); uid_t hostOwner = owner; - uint32_t group = tc->getSyscallArg(2); + uint32_t group = process->getSyscallArg(tc, 2); gid_t hostGroup = group; int result = fchown(fd, hostOwner, hostGroup); @@ -349,11 +438,11 @@ fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) SyscallReturn dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) { - int fd = process->sim_fd(tc->getSyscallArg(0)); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); if (fd < 0) return -EBADF; - Process::FdMap *fdo = process->sim_fd_obj(tc->getSyscallArg(0)); + Process::FdMap *fdo = process->sim_fd_obj(process->getSyscallArg(tc, 0)); int result = dup(fd); return (result == -1) ? -errno : process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false); @@ -364,12 +453,12 @@ SyscallReturn fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); + int fd = process->getSyscallArg(tc, 0); if (fd < 0 || process->sim_fd(fd) < 0) return -EBADF; - int cmd = tc->getSyscallArg(1); + int cmd = process->getSyscallArg(tc, 1); switch (cmd) { case 0: // F_DUPFD // if we really wanted to support this, we'd need to do it @@ -406,12 +495,12 @@ SyscallReturn fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); + int fd = process->getSyscallArg(tc, 0); if (fd < 0 || process->sim_fd(fd) < 0) return -EBADF; - int cmd = tc->getSyscallArg(1); + int cmd = process->getSyscallArg(tc, 1); switch (cmd) { case 33: //F_GETLK64 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd); @@ -476,7 +565,7 @@ getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, // EUID goes in r20. tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID - return process->uid(); // UID + return process->uid(); // UID } @@ -495,7 +584,7 @@ setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { // can't fathom why a benchmark would call this. - warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0)); + warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, 0)); return 0; } @@ -522,14 +611,14 @@ SyscallReturn getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - return process->uid(); // UID + return process->uid(); // UID } SyscallReturn geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - return process->euid(); // UID + return process->euid(); // UID } SyscallReturn diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index e35b0a75b..0b0e73692 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -44,15 +44,15 @@ #include <errno.h> #include <string> #ifdef __CYGWIN32__ -#include <sys/fcntl.h> // for O_BINARY +#include <sys/fcntl.h> // for O_BINARY #endif #include <sys/stat.h> #include <fcntl.h> #include <sys/uio.h> -#include "sim/host.hh" // for Addr +#include "sim/host.hh" // for Addr #include "base/chunk_generator.hh" -#include "base/intmath.hh" // for RoundUp +#include "base/intmath.hh" // for RoundUp #include "base/misc.hh" #include "base/trace.hh" #include "cpu/base.hh" @@ -72,9 +72,9 @@ class SyscallDesc { typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, LiveProcess *, ThreadContext *); - const char *name; //!< Syscall name (e.g., "open"). - FuncPtr funcPtr; //!< Pointer to emulation function. - int flags; //!< Flags (see Flags enum). + const char *name; //!< Syscall name (e.g., "open"). + FuncPtr funcPtr; //!< Pointer to emulation function. + int flags; //!< Flags (see Flags enum). /// Flag values for controlling syscall behavior. enum Flags { @@ -117,7 +117,7 @@ class BaseBufferArg { virtual bool copyIn(TranslatingPort *memport) { memport->readBlob(addr, bufPtr, size); - return true; // no EFAULT detection for now + return true; // no EFAULT detection for now } // @@ -126,7 +126,7 @@ class BaseBufferArg { virtual bool copyOut(TranslatingPort *memport) { memport->writeBlob(addr, bufPtr, size); - return true; // no EFAULT detection for now + return true; // no EFAULT detection for now } protected: @@ -140,7 +140,7 @@ class BufferArg : public BaseBufferArg { public: BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } - void *bufferPtr() { return bufPtr; } + void *bufferPtr() { return bufPtr; } }; template <class T> @@ -158,8 +158,8 @@ class TypedBufferArg : public BaseBufferArg operator T*() { return (T *)bufPtr; } // dereference operators - T &operator*() { return *((T *)bufPtr); } - T* operator->() { return (T *)bufPtr; } + T &operator*() { return *((T *)bufPtr); } + T* operator->() { return (T *)bufPtr; } T &operator[](int i) { return ((T *)bufPtr)[i]; } }; @@ -191,9 +191,9 @@ SyscallReturn exitFunc(SyscallDesc *desc, int num, SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); -/// Target obreak() handler: set brk address. -SyscallReturn obreakFunc(SyscallDesc *desc, int num, - LiveProcess *p, ThreadContext *tc); +/// Target brk() handler: set brk address. +SyscallReturn brkFunc(SyscallDesc *desc, int num, + LiveProcess *p, ThreadContext *tc); /// Target close() handler. SyscallReturn closeFunc(SyscallDesc *desc, int num, @@ -223,10 +223,22 @@ SyscallReturn munmapFunc(SyscallDesc *desc, int num, SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); +/// Target getcwd() handler. +SyscallReturn getcwdFunc(SyscallDesc *desc, int num, + LiveProcess *p, ThreadContext *tc); + +/// Target unlink() handler. +SyscallReturn readlinkFunc(SyscallDesc *desc, int num, + LiveProcess *p, ThreadContext *tc); + /// Target unlink() handler. SyscallReturn unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); +/// Target mkdir() handler. +SyscallReturn mkdirFunc(SyscallDesc *desc, int num, + LiveProcess *p, ThreadContext *tc); + /// Target rename() handler. SyscallReturn renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); @@ -242,6 +254,11 @@ SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); +/// Target umask() handler. +SyscallReturn umaskFunc(SyscallDesc *desc, int num, + LiveProcess *p, ThreadContext *tc); + + /// Target chown() handler. SyscallReturn chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); @@ -363,6 +380,11 @@ convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) tgt->st_ino = host->st_ino; tgt->st_ino = htog(tgt->st_ino); tgt->st_mode = host->st_mode; + if (fakeTTY) { + // Claim to be a character device + tgt->st_mode &= ~S_IFMT; // Clear S_IFMT + tgt->st_mode |= S_IFCHR; // Set S_IFCHR + } tgt->st_mode = htog(tgt->st_mode); tgt->st_nlink = host->st_nlink; tgt->st_nlink = htog(tgt->st_nlink); @@ -445,8 +467,8 @@ SyscallReturn ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); - unsigned req = tc->getSyscallArg(1); + int fd = process->getSyscallArg(tc, 0); + unsigned req = process->getSyscallArg(tc, 1); DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); @@ -480,7 +502,7 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; if (path == "/dev/sysdev0") { @@ -490,8 +512,8 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return -ENOENT; } - int tgtFlags = tc->getSyscallArg(1); - int mode = tc->getSyscallArg(2); + int tgtFlags = process->getSyscallArg(tc, 1); + int mode = process->getSyscallArg(tc, 2); int hostFlags = 0; // translate open flags @@ -515,10 +537,18 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); - // open the file - int fd = open(path.c_str(), hostFlags, mode); + int fd; + if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || + !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { + // It's a proc/sys entery and requires special handling + fd = OS::openSpecialFile(path, process, tc); + return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); + } else { + // open the file + fd = open(path.c_str(), hostFlags, mode); + return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); + } - return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); } @@ -530,10 +560,10 @@ chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; - uint32_t mode = tc->getSyscallArg(1); + uint32_t mode = process->getSyscallArg(tc, 1); mode_t hostMode = 0; // XXX translate mode flags via OS::something??? @@ -557,13 +587,13 @@ SyscallReturn fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); + int fd = process->getSyscallArg(tc, 0); if (fd < 0 || process->sim_fd(fd) < 0) { // doesn't map to any simulator fd: not a valid target fd return -EBADF; } - uint32_t mode = tc->getSyscallArg(1); + uint32_t mode = process->getSyscallArg(tc, 1); mode_t hostMode = 0; // XXX translate mode flags via OS::someting??? @@ -577,6 +607,51 @@ fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return 0; } +/// Target mremap() handler. +template <class OS> +SyscallReturn +mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) +{ + Addr start = process->getSyscallArg(tc, 0); + uint64_t old_length = process->getSyscallArg(tc, 1); + uint64_t new_length = process->getSyscallArg(tc, 2); + uint64_t flags = process->getSyscallArg(tc, 3); + + if ((start % TheISA::VMPageSize != 0) || + (new_length % TheISA::VMPageSize != 0)) { + warn("mremap failing: arguments not page aligned"); + return -EINVAL; + } + + if (new_length > old_length) { + if ((start + old_length) == process->mmap_end) { + uint64_t diff = new_length - old_length; + process->pTable->allocate(process->mmap_end, diff); + process->mmap_end += diff; + return start; + } else { + // sys/mman.h defined MREMAP_MAYMOVE + if (!(flags & 1)) { + warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); + return -ENOMEM; + } else { + process->pTable->remap(start, old_length, process->mmap_end); + warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", + process->mmap_end, process->mmap_end + new_length, new_length); + start = process->mmap_end; + // add on the remaining unallocated pages + process->pTable->allocate(start + old_length, new_length - old_length); + process->mmap_end += new_length; + warn("returning %08p as start\n", start); + return start; + } + } + } else { + process->pTable->deallocate(start + new_length, old_length - + new_length); + return start; + } +} /// Target stat() handler. template <class OS> @@ -586,7 +661,7 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; // Adjust path for current working directory @@ -598,7 +673,8 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), + &hostBuf); return 0; } @@ -612,7 +688,7 @@ stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; // Adjust path for current working directory @@ -629,7 +705,8 @@ stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), + &hostBuf); return 0; } @@ -641,7 +718,7 @@ SyscallReturn fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); + int fd = process->getSyscallArg(tc, 0); if (fd < 0 || process->sim_fd(fd) < 0) { // doesn't map to any simulator fd: not a valid target fd return -EBADF; @@ -658,7 +735,7 @@ fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), + copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), &hostBuf, (fd == 1)); return 0; @@ -673,7 +750,7 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; // Adjust path for current working directory @@ -685,7 +762,8 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), + &hostBuf); return 0; } @@ -698,7 +776,7 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; // Adjust path for current working directory @@ -715,7 +793,8 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), + &hostBuf); return 0; } @@ -726,7 +805,7 @@ SyscallReturn fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = process->sim_fd(tc->getSyscallArg(0)); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); @@ -739,7 +818,7 @@ fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), + copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1), &hostBuf, (fd == 1)); return 0; @@ -754,7 +833,7 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; // Adjust path for current working directory @@ -767,7 +846,7 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return -errno; OS::copyOutStatfsBuf(tc->getMemPort(), - (Addr)(tc->getSyscallArg(1)), &hostBuf); + (Addr)(process->getSyscallArg(tc, 1)), &hostBuf); return 0; } @@ -779,7 +858,7 @@ SyscallReturn fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = process->sim_fd(tc->getSyscallArg(0)); + int fd = process->sim_fd(process->getSyscallArg(tc, 0)); if (fd < 0) return -EBADF; @@ -790,7 +869,7 @@ fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), + OS::copyOutStatfsBuf(tc->getMemPort(), process->getSyscallArg(tc, 1), &hostBuf); return 0; @@ -803,15 +882,15 @@ SyscallReturn writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int fd = tc->getSyscallArg(0); + int fd = process->getSyscallArg(tc, 0); if (fd < 0 || process->sim_fd(fd) < 0) { // doesn't map to any simulator fd: not a valid target fd return -EBADF; } TranslatingPort *p = tc->getMemPort(); - uint64_t tiov_base = tc->getSyscallArg(1); - size_t count = tc->getSyscallArg(2); + uint64_t tiov_base = process->getSyscallArg(tc, 1); + size_t count = process->getSyscallArg(tc, 2); struct iovec hiov[count]; for (int i = 0; i < count; ++i) { @@ -855,12 +934,13 @@ template <class OS> SyscallReturn mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) { - Addr start = tc->getSyscallArg(0); - uint64_t length = tc->getSyscallArg(1); - // int prot = tc->getSyscallArg(2); - int flags = tc->getSyscallArg(3); - // int fd = p->sim_fd(tc->getSyscallArg(4)); - // int offset = tc->getSyscallArg(5); + Addr start = p->getSyscallArg(tc, 0); + uint64_t length = p->getSyscallArg(tc, 1); + // int prot = p->getSyscallArg(tc, 2); + int flags = p->getSyscallArg(tc, 3); + // int fd = p->sim_fd(p->getSyscallArg(tc, 4)); + // int offset = p->getSyscallArg(tc, 5); + if ((start % TheISA::VMPageSize) != 0 || (length % TheISA::VMPageSize) != 0) { @@ -882,7 +962,7 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) if (!(flags & OS::TGT_MAP_ANONYMOUS)) { warn("allowing mmap of file @ fd %d. " - "This will break if not /dev/zero.", tc->getSyscallArg(4)); + "This will break if not /dev/zero.", p->getSyscallArg(tc, 4)); } return start; @@ -894,17 +974,24 @@ SyscallReturn getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - unsigned resource = tc->getSyscallArg(0); - TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); + unsigned resource = process->getSyscallArg(tc, 0); + TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, 1)); switch (resource) { case OS::TGT_RLIMIT_STACK: - // max stack size in bytes: make up a number (2MB for now) + // max stack size in bytes: make up a number (8MB for now) rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; rlp->rlim_cur = htog(rlp->rlim_cur); rlp->rlim_max = htog(rlp->rlim_max); break; + case OS::TGT_RLIMIT_DATA: + // max data segment size in bytes: make up a number + rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; + rlp->rlim_cur = htog(rlp->rlim_cur); + rlp->rlim_max = htog(rlp->rlim_max); + break; + default: std::cerr << "getrlimitFunc: unimplemented resource " << resource << std::endl; @@ -922,7 +1009,7 @@ SyscallReturn gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); + TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, 0)); getElapsedTime(tp->tv_sec, tp->tv_usec); tp->tv_sec += seconds_since_epoch; @@ -943,10 +1030,10 @@ utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, { std::string path; - if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0))) return -EFAULT; - TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); + TypedBufferArg<typename OS::timeval [2]> tp(process->getSyscallArg(tc, 1)); tp.copyIn(tc->getMemPort()); struct timeval hostTimeval[2]; @@ -972,8 +1059,8 @@ SyscallReturn getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { - int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN - TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); + int who = process->getSyscallArg(tc, 0); // THREAD, SELF, or CHILDREN + TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, 1)); rup->ru_utime.tv_sec = 0; rup->ru_utime.tv_usec = 0; diff --git a/src/sim/system.cc b/src/sim/system.cc index 10b9b1217..d16524c41 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -42,6 +42,7 @@ #include "mem/physical.hh" #include "sim/byteswap.hh" #include "sim/system.hh" +#include "sim/debug.hh" #if FULL_SYSTEM #include "arch/vtophys.hh" #include "kern/kernel_stats.hh" @@ -57,7 +58,7 @@ vector<System *> System::systemList; int System::numSystemsRunning = 0; System::System(Params *p) - : SimObject(p), physmem(p->physmem), numcpus(0), + : SimObject(p), physmem(p->physmem), _numContexts(0), #if FULL_SYSTEM init_param(p->init_param), functionalPort(p->name + "-fport"), @@ -94,12 +95,12 @@ System::System(Params *p) * Load the kernel code into memory */ if (params()->kernel == "") { - warn("No kernel set for full system simulation. Assuming you know what" + inform("No kernel set for full system simulation. Assuming you know what" " you're doing...\n"); } else { // Load kernel code kernel = createObjectFile(params()->kernel); - warn("kernel located at: %s", params()->kernel); + inform("kernel located at: %s", params()->kernel); if (kernel == NULL) fatal("Could not load kernel file %s", params()->kernel); @@ -114,16 +115,16 @@ System::System(Params *p) // load symbols if (!kernel->loadGlobalSymbols(kernelSymtab)) - panic("could not load kernel symbols\n"); + fatal("could not load kernel symbols\n"); if (!kernel->loadLocalSymbols(kernelSymtab)) - panic("could not load kernel local symbols\n"); + fatal("could not load kernel local symbols\n"); if (!kernel->loadGlobalSymbols(debugSymbolTable)) - panic("could not load kernel symbols\n"); + fatal("could not load kernel symbols\n"); if (!kernel->loadLocalSymbols(debugSymbolTable)) - panic("could not load kernel local symbols\n"); + fatal("could not load kernel local symbols\n"); DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); @@ -165,27 +166,33 @@ bool System::breakpoint() } int -System::registerThreadContext(ThreadContext *tc, int id) +System::registerThreadContext(ThreadContext *tc, int assigned) { - if (id == -1) { + int id; + if (assigned == -1) { for (id = 0; id < threadContexts.size(); id++) { if (!threadContexts[id]) break; } - } - if (threadContexts.size() <= id) - threadContexts.resize(id + 1); + if (threadContexts.size() <= id) + threadContexts.resize(id + 1); + } else { + if (threadContexts.size() <= assigned) + threadContexts.resize(assigned + 1); + id = assigned; + } if (threadContexts[id]) - panic("Cannot have two CPUs with the same id (%d)\n", id); + fatal("Cannot have two CPUs with the same id (%d)\n", id); threadContexts[id] = tc; - numcpus++; + _numContexts++; - if (rgdb_enable) { + int port = getRemoteGDBPort(); + if (rgdb_enable && port) { RemoteGDB *rgdb = new RemoteGDB(this, tc); - GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); + GDBListener *gdbl = new GDBListener(rgdb, port + id); gdbl->listen(); /** * Uncommenting this line waits for a remote debugger to @@ -207,22 +214,24 @@ System::registerThreadContext(ThreadContext *tc, int id) void System::startup() { +#if FULL_SYSTEM int i; for (i = 0; i < threadContexts.size(); i++) TheISA::startupCPU(threadContexts[i], i); +#endif } void -System::replaceThreadContext(ThreadContext *tc, int id) +System::replaceThreadContext(ThreadContext *tc, int context_id) { - if (id >= threadContexts.size()) { + if (context_id >= threadContexts.size()) { panic("replaceThreadContext: bad id, %d >= %d\n", - id, threadContexts.size()); + context_id, threadContexts.size()); } - threadContexts[id] = tc; - if (id < remoteGDB.size()) - remoteGDB[id]->replaceThreadContext(tc); + threadContexts[context_id] = tc; + if (context_id < remoteGDB.size()) + remoteGDB[context_id]->replaceThreadContext(tc); } #if !FULL_SYSTEM @@ -235,6 +244,19 @@ System::new_page() fatal("Out of memory, please increase size of physical memory."); return return_addr; } + +Addr +System::memSize() +{ + return physmem->size(); +} + +Addr +System::freeMemSize() +{ + return physmem->size() - (page_ptr << LogVMPageSize); +} + #endif void @@ -283,11 +305,7 @@ const char *System::MemoryModeStrings[3] = {"invalid", "atomic", System * SystemParams::create() { - System::Params *p = new System::Params; - p->name = name; - p->physmem = physmem; - p->mem_mode = mem_mode; - return new System(p); + return new System(this); } #endif diff --git a/src/sim/system.hh b/src/sim/system.hh index cdd5bebb0..bfa5ea8bb 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -87,14 +87,19 @@ class System : public SimObject PCEventQueue pcEventQueue; std::vector<ThreadContext *> threadContexts; - int numcpus; + int _numContexts; - int getNumCPUs() + ThreadContext * getThreadContext(int tid) { - if (numcpus != threadContexts.size()) + return threadContexts[tid]; + } + + int numContexts() + { + if (_numContexts != threadContexts.size()) panic("cpu array not fully populated!"); - return numcpus; + return _numContexts; } #if FULL_SYSTEM @@ -134,6 +139,12 @@ class System : public SimObject return next_PID++; } + /** Amount of physical memory that is still free */ + Addr freeMemSize(); + + /** Amount of physical memory that exists */ + Addr memSize(); + #endif // FULL_SYSTEM @@ -219,8 +230,8 @@ class System : public SimObject #endif // FULL_SYSTEM - int registerThreadContext(ThreadContext *tc, int tcIndex); - void replaceThreadContext(ThreadContext *tc, int tcIndex); + int registerThreadContext(ThreadContext *tc, int assigned=-1); + void replaceThreadContext(ThreadContext *tc, int context_id); void serialize(std::ostream &os); void unserialize(Checkpoint *cp, const std::string §ion); diff --git a/src/sim/tlb.cc b/src/sim/tlb.cc index 7292a69e0..e82e4f277 100644 --- a/src/sim/tlb.cc +++ b/src/sim/tlb.cc @@ -34,7 +34,7 @@ #include "sim/tlb.hh" Fault -GenericTLB::translate(RequestPtr req, ThreadContext * tc, bool) +GenericTLB::translateAtomic(RequestPtr req, ThreadContext * tc, bool) { #if FULL_SYSTEM panic("Generic translation shouldn't be used in full system mode.\n"); @@ -50,6 +50,14 @@ GenericTLB::translate(RequestPtr req, ThreadContext * tc, bool) } void +GenericTLB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + +void GenericTLB::demapPage(Addr vaddr, uint64_t asn) { warn("Demapping pages in the generic TLB is unnecessary.\n"); diff --git a/src/sim/tlb.hh b/src/sim/tlb.hh index 011cc1144..8893f8c97 100644 --- a/src/sim/tlb.hh +++ b/src/sim/tlb.hh @@ -47,6 +47,21 @@ class BaseTLB : public SimObject public: virtual void demapPage(Addr vaddr, uint64_t asn) = 0; + + class Translation + { + public: + virtual ~Translation() + {} + + /* + * The memory for this object may be dynamically allocated, and it may + * be responsible for cleaning itself up which will happen in this + * function. Once it's called, the object is no longer valid. + */ + virtual void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write=false) = 0; + }; }; class GenericTLB : public BaseTLB @@ -58,7 +73,9 @@ class GenericTLB : public BaseTLB public: void demapPage(Addr vaddr, uint64_t asn); - Fault translate(RequestPtr req, ThreadContext *tc, bool=false); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool=false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool=false); }; #endif // __ARCH_SPARC_TLB_HH__ diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh index 383f65351..09aa2d213 100644 --- a/src/sim/vptr.hh +++ b/src/sim/vptr.hh @@ -71,9 +71,8 @@ class VPtr if (!ptr) return; - VirtualPort *port = tc->getVirtPort(tc); + VirtualPort *port = tc->getVirtPort(); port->readBlob(ptr, buffer, sizeof(T)); - tc->delVirtPort(port); } bool diff --git a/src/unittest/Makefile b/src/unittest/Makefile deleted file mode 100644 index e6a621a9e..000000000 --- a/src/unittest/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) 2006-2007 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert -# Steve Reinhardt - -CC?= gcc -CXX?= g++ -PYTHON?=/usr/bin/env python - -CURDIR?= $(shell /bin/pwd) -SRCDIR?= $(CURDIR)/.. - -CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 -MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient - -VPATH=$(SRCDIR):$(CURDIR) - -default: - @echo "You must specify a target" - -base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py - mkdir -p base; \ - cd base; \ - $(PYTHON) $< - -bitvectest: unittest/bitvectest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -circletest: unittest/circletest.cc base/circlebuf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -cprintftest: unittest/cprintftest.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -cprintftime: unittest/cprintftime.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -initest: unittest/initest.cc base/str.cc base/inifile.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -lrutest: unittest/lru_test.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -nmtest: unittest/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc - $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^ - -offtest: unittest/offtest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -rangetest: unittest/rangetest.cc base/range.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc -STATTEST+= base/python.cc base/str.cc base/time.cc -STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc -STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc -STATTEST+= unittest/stattest.cc -stattest: $(STATTEST) - $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ - -strnumtest: unittest/strnumtest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -symtest: unittest/symtest.cc base/misc.cc base/symtab.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -tokentest: unittest/tokentest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -TRACE+=unittest/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc -TRACE+=base/str.cc base/misc.cc -tracetest: $(TRACE) - $(CXX) $(CCFLAGS) -o $@ $^ - -clean: - @rm -rf *test *~ .#* *.core core base -.PHONY: clean diff --git a/src/unittest/SConscript b/src/unittest/SConscript new file mode 100644 index 000000000..1c1959165 --- /dev/null +++ b/src/unittest/SConscript @@ -0,0 +1,48 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +Import('*') + +UnitTest('bitvectest', 'bitvectest.cc') +UnitTest('circletest', 'circletest.cc') +UnitTest('cprintftest', 'cprintftest.cc') +UnitTest('cprintftime', 'cprintftest.cc') +UnitTest('initest', 'initest.cc') +UnitTest('lrutest', 'lru_test.cc') +UnitTest('nmtest', 'nmtest.cc') +UnitTest('offtest', 'offtest.cc') +UnitTest('rangetest', 'rangetest.cc') +UnitTest('rangemaptest', 'rangemaptest.cc') +UnitTest('rangemultimaptest', 'rangemultimaptest.cc') +UnitTest('stattest', 'stattest.cc') +UnitTest('strnumtest', 'strnumtest.cc') +UnitTest('symtest', 'symtest.cc') +UnitTest('tokentest', 'tokentest.cc') +UnitTest('tracetest', 'tracetest.cc') diff --git a/src/unittest/bitvectest.cc b/src/unittest/bitvectest.cc index 440a150a3..29069081b 100644 --- a/src/unittest/bitvectest.cc +++ b/src/unittest/bitvectest.cc @@ -28,41 +28,42 @@ * Authors: Nathan Binkert */ -#include <iostream.h> - +#include <iostream> #include <vector> +using namespace std; + int main() { - vector<bool> v1(100); + vector<bool> v1(100); - v1[0] = true; - v1.resize(500); - v1[100] = true; - v1[499] = true; - v1.resize(10000); - v1[9999] = true; + v1[0] = true; + v1.resize(500); + v1[100] = true; + v1[499] = true; + v1.resize(10000); + v1[9999] = true; - cout << "v1.size() = " << v1.size() << "\n"; - for (int i = 0; i < v1.size(); i++) - if (v1[i]) - cout << "v1[" << i << "] = " << v1[i] << "\n"; + cout << "v1.size() = " << v1.size() << "\n"; + for (int i = 0; i < v1.size(); i++) + if (v1[i]) + cout << "v1[" << i << "] = " << v1[i] << "\n"; - cout << "\n"; + cout << "\n"; - vector<bool> v2 = v1; + vector<bool> v2 = v1; - for (int i = 0; i < v2.size(); i++) - if (v2[i]) - cout << "v2[" << i << "] = " << v2[i] << "\n"; + for (int i = 0; i < v2.size(); i++) + if (v2[i]) + cout << "v2[" << i << "] = " << v2[i] << "\n"; - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v2[8583] = true; - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v1[8583] = true; - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v1.resize(100000); - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - cout << flush; + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v2[8583] = true; + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v1[8583] = true; + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v1.resize(100000); + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + cout << flush; } diff --git a/src/unittest/circletest.cc b/src/unittest/circletest.cc index f072cf044..2ee75b6df 100644 --- a/src/unittest/circletest.cc +++ b/src/unittest/circletest.cc @@ -29,19 +29,21 @@ */ #include <fcntl.h> -#include <iostream.h> #include <unistd.h> +#include <iostream> + #include "base/circlebuf.hh" -char *strings[] = -{ "This is the first test\n", - "he went with his woman to the store\n", - "the man with the bat hit the woman with the hat\n", - "that that is is that that was\n", - "sue sells sea shells by the sea shore\n", - "go to the store and buy me some milk and bread\n", - "the friendly flight attendants spoke soothingly to the frightened passengers in their native languages\n" +const char *strings[] = { + "This is the first test\n", + "he went with his woman to the store\n", + "the man with the bat hit the woman with the hat\n", + "that that is is that that was\n", + "sue sells sea shells by the sea shore\n", + "go to the store and buy me some milk and bread\n", + "the friendly flight attendants spoke soothingly to " + "the frightened passengers in their native languages\n" }; const int num_strings = sizeof(strings) / sizeof(char *); @@ -49,26 +51,26 @@ const int num_strings = sizeof(strings) / sizeof(char *); int main() { - CircleBuf buf(1024); + CircleBuf buf(1024); - for (int count = 0; count < 100; count++) - buf.write(strings[count % num_strings]); - buf.read(STDOUT_FILENO); - write(STDOUT_FILENO, "<\n", 2); + for (int count = 0; count < 100; count++) + buf.write(strings[count % num_strings]); + buf.read(STDOUT_FILENO); + write(STDOUT_FILENO, "<\n", 2); - for (int count = 0; count < 100; count++) - buf.write(strings[count % num_strings]); - buf.read(STDOUT_FILENO, 100); - write(STDOUT_FILENO, "<\n", 2); + for (int count = 0; count < 100; count++) + buf.write(strings[count % num_strings]); + buf.read(STDOUT_FILENO, 100); + write(STDOUT_FILENO, "<\n", 2); - buf.flush(); - buf.write("asdfa asdf asd fasdf asdf\n"); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.read(STDOUT_FILENO); - write(STDOUT_FILENO, "<\n", 2); + buf.flush(); + buf.write("asdfa asdf asd fasdf asdf\n"); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.read(STDOUT_FILENO); + write(STDOUT_FILENO, "<\n", 2); } diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc index 7fb10375c..6722ce6a3 100644 --- a/src/unittest/cprintftest.cc +++ b/src/unittest/cprintftest.cc @@ -34,6 +34,7 @@ #include <sstream> #include "base/cprintf.hh" +#include "base/misc.hh" using namespace std; @@ -43,6 +44,14 @@ main() char foo[] = "foo"; cprintf("%s\n", foo); + string _bar = "asdfkhasdlkfjhasdlkfhjalksdjfhalksdjhfalksdjfhalksdjhf"; + int length = 11; + char bar[length + 1]; + bar[length] = 0; + + memcpy(bar, _bar.c_str(), length); + warn("%s\n", bar); + cprintf("%d\n", 'A'); cprintf("%shits%%s + %smisses%%s\n", "test", "test"); cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n", @@ -158,6 +167,13 @@ main() cprintf("%c %c\n", 'c', 65); - cout << '9'; + cout << '9' << endl; + + cout << endl; + + cprintf("%08.4f\n", 99.99); + cprintf("%0*.*f\n", 8, 4, 99.99); + cprintf("%07.*f\n", 4, 1.234); + cprintf("%#0*x\n", 9, 123412); return 0; } diff --git a/src/unittest/foo.ini b/src/unittest/foo.ini index 534a4e001..0f91c1fd6 100644 --- a/src/unittest/foo.ini +++ b/src/unittest/foo.ini @@ -1,4 +1,3 @@ -#define JUNK [Foo] Foo1=89 Foo2=384 diff --git a/src/unittest/initest.cc b/src/unittest/initest.cc index 8f53fce5c..67ac44874 100644 --- a/src/unittest/initest.cc +++ b/src/unittest/initest.cc @@ -68,32 +68,14 @@ main(int argc, char *argv[]) progname = argv[0]; - vector<char *> cppArgs; - - vector<char *> cpp_options; - cpp_options.reserve(argc * 2); - for (int i = 1; i < argc; ++i) { char *arg_str = argv[i]; // if arg starts with '-', parse as option, // else treat it as a configuration file name and load it if (arg_str[0] == '-') { - // switch on second char switch (arg_str[1]) { - case 'D': - case 'U': - case 'I': - // cpp options: record & pass to cpp. Note that these - // cannot have spaces, i.e., '-Dname=val' is OK, but - // '-D name=val' is not. I don't consider this a - // problem, since even though gnu cpp accepts the - // latter, other cpp implementations do not (Tru64, - // for one). - cppArgs.push_back(arg_str); - break; - case '-': // command-line configuration parameter: // '--<section>:<parameter>=<value>' @@ -115,7 +97,7 @@ main(int argc, char *argv[]) else { // no '-', treat as config file name - if (!simConfigDB.loadCPP(arg_str, cppArgs)) { + if (!simConfigDB.load(arg_str)) { cprintf("Error processing file %s\n", arg_str); exit(1); } diff --git a/src/unittest/initest.ini b/src/unittest/initest.ini deleted file mode 100644 index ebf2719d8..000000000 --- a/src/unittest/initest.ini +++ /dev/null @@ -1,14 +0,0 @@ -#define JUNK -// General stuff -#define FOO(X) BAR##X -[General] - Test1=FOO(asdf) - Test2=bar - -#ifdef JUNK -[Junk] // This is the junk -Test3=yo -Test4=mama -#endif - -#include "foo.ini" diff --git a/src/unittest/lru_test.cc b/src/unittest/lru_test.cc deleted file mode 100644 index d10eb1dd0..000000000 --- a/src/unittest/lru_test.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Dave Greene - * Nathan Binkert - */ - -#include <iostream> -#include "bhgp.hh" - -int main(void) -{ - typedef AssociativeTable<unsigned int, unsigned int> tableType; - tableType table(10, 4); // 40 entry table - - std::cout << "Initial state:" << std::endl; - table.dump(); - - std::cout << "Inserting (2, 1)" << std::endl; - table[2] = 1; - table.dump(); - - std::cout << "Inserting (5, 2)" << std::endl; - table[5] = 2; - table.dump(); - - std::cout << "Inserting (10 + 2, 3)" << std::endl; - table[10 + 2] = 3; - table.dump(); - - tableType::const_iterator i = table.find(2); - assert(i != table.end()); - std::cout << "Accessed 2: " << *i << std::endl; - table.dump(); - - i = table.find(10 + 2); - assert(i != table.end()); - std::cout << "Accessed 10 + 2: " << *i << std::endl; - table.dump(); - - i = table.find(34); - assert(i == table.end()); - - std::cout << "Inserting (2 * 10 + 2, 4)" << std::endl; - table[2 * 10 + 2] = 4; - table.dump(); - - std::cout << "Replacing (10 + 2) with 5" << std::endl; - table[10 + 2] = 5; - table.dump(); - - std::cout << "Inserting (3 * 10 + 2, 6)" << std::endl; - table[3 * 10 + 2] = 6; - table.dump(); - - std::cout << "Inserting (4 * 10 + 2, 7)" << std::endl; - table[4 * 10 + 2] = 7; - table.dump(); - - return(0); -} diff --git a/src/unittest/nmtest.cc b/src/unittest/nmtest.cc index b6b74e08d..fdd865f2d 100644 --- a/src/unittest/nmtest.cc +++ b/src/unittest/nmtest.cc @@ -38,9 +38,6 @@ #include "base/str.hh" using namespace std; -Tick curTick; - -ostream *outputStream = &cout; int main(int argc, char *argv[]) diff --git a/src/unittest/paramtest.cc b/src/unittest/paramtest.cc deleted file mode 100644 index e513ab981..000000000 --- a/src/unittest/paramtest.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Nathan Binkert - */ - -// -// This file is not part of the regular simulator. It is solely for -// testing the parameter code. Edit the Makefile to add param_test.cc -// to the sources list, then use configs/test.ini as the configuration -// file. -// -#include "sim/sim_object.hh" -#include "mem/cache/cache.hh" - -class ParamTest : public SimObject -{ - public: - ParamTest(string name) - : SimObject(name) - { - } - - virtual ~ParamTest() {} -}; - -enum Enum1Type { Enum0 }; -enum Enum2Type { Enum10 }; - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest) - - Param<int> intparam; - VectorParam<int> vecint; - Param<string> stringparam; - VectorParam<string> vecstring; - Param<bool> boolparam; - VectorParam<bool> vecbool; - SimObjectParam<BaseMemory *> memobj; - SimObjectVectorParam<BaseMemory *> vecmemobj; - SimpleEnumParam<Enum1Type> enum1; - MappedEnumParam<Enum2Type> enum2; - SimpleEnumVectorParam<Enum1Type> vecenum1; - MappedEnumVectorParam<Enum2Type> vecenum2; - -END_DECLARE_SIM_OBJECT_PARAMS(ParamTest) - -const char *enum1_strings[] = -{ - "zero", "one", "two", "three" -}; - -const EnumParamMap enum2_map[] = -{ - { "ten", 10 }, - { "twenty", 20 }, - { "thirty", 30 }, - { "forty", 40 } -}; - -BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest) - - INIT_PARAM(intparam, "intparam"), - INIT_PARAM(vecint, "vecint"), - INIT_PARAM(stringparam, "stringparam"), - INIT_PARAM(vecstring, "vecstring"), - INIT_PARAM(boolparam, "boolparam"), - INIT_PARAM(vecbool, "vecbool"), - INIT_PARAM(memobj, "memobj"), - INIT_PARAM(vecmemobj, "vecmemobj"), - INIT_ENUM_PARAM(enum1, "enum1", enum1_strings), - INIT_ENUM_PARAM(enum2, "enum2", enum2_map), - INIT_ENUM_PARAM(vecenum1, "vecenum1", enum1_strings), - INIT_ENUM_PARAM(vecenum2, "vecenum2", enum2_map) - -END_INIT_SIM_OBJECT_PARAMS(ParamTest) - - -CREATE_SIM_OBJECT(ParamTest) -{ - return new ParamTest(getInstanceName()); -} - -REGISTER_SIM_OBJECT("ParamTest", ParamTest) diff --git a/src/unittest/rangemaptest.cc b/src/unittest/rangemaptest.cc index 983a41520..36223ed9c 100644 --- a/src/unittest/rangemaptest.cc +++ b/src/unittest/rangemaptest.cc @@ -35,7 +35,8 @@ using namespace std; -int main() +int +main() { range_map<Addr,int> r; diff --git a/src/unittest/rangemaptest2.cc b/src/unittest/rangemultimaptest.cc index b253dbe86..a110256c9 100644 --- a/src/unittest/rangemaptest2.cc +++ b/src/unittest/rangemultimaptest.cc @@ -28,20 +28,22 @@ * Authors: Ali Saidi */ -#include <iostream> #include <cassert> +#include <iostream> + #include "sim/host.hh" #include "base/range_map.hh" using namespace std; -int main() +int +main() { - range_multimap<Addr,int> r; + typedef range_multimap<Addr, int> multimap_t; - range_multimap<Addr,int>::iterator i; - std::pair<range_multimap<Addr,int>::iterator,range_multimap<Addr,int>::iterator> - jk; + multimap_t r; + multimap_t::iterator i; + std::pair<multimap_t::iterator, multimap_t::iterator> jk; i = r.insert(RangeIn<Addr>(10,40),5); assert(i != r.end()); diff --git a/src/unittest/rangetest.cc b/src/unittest/rangetest.cc index b7a68ab44..eab2f39a8 100644 --- a/src/unittest/rangetest.cc +++ b/src/unittest/rangetest.cc @@ -38,39 +38,40 @@ using namespace std; int main() { - Range<int> r1(make_pair(9, 28)); - Range<unsigned> r2("0x1000:+0x100"); + Range<int> r1(make_pair(9, 28)); + Range<unsigned> r2("0x1000:+0x100"); - cout << r1 << "\n" - << r2 << "\n"; + cout << r1 << "\n" + << r2 << "\n"; -#define RANGETEST(X, C, Y) \ - cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n" +#define RANGETEST(X, C, Y) \ + cout << X << " "#C" " << Y << " => " << \ + ((X C Y) ? "true" : "false") << "\n" #define TESTEM(X, Y) do { \ - RANGETEST(X, < , Y); \ - RANGETEST(X, <=, Y); \ - RANGETEST(X, > , Y); \ - RANGETEST(X, >=, Y); \ - RANGETEST(X, ==, Y); \ - RANGETEST(X, !=, Y); \ - RANGETEST(Y, < , X); \ - RANGETEST(Y, <=, X); \ - RANGETEST(Y, > , X); \ - RANGETEST(Y, >=, X); \ - RANGETEST(Y, ==, X); \ - RANGETEST(Y, !=, X); \ -} while (0) + RANGETEST(X, < , Y); \ + RANGETEST(X, <=, Y); \ + RANGETEST(X, > , Y); \ + RANGETEST(X, >=, Y); \ + RANGETEST(X, ==, Y); \ + RANGETEST(X, !=, Y); \ + RANGETEST(Y, < , X); \ + RANGETEST(Y, <=, X); \ + RANGETEST(Y, > , X); \ + RANGETEST(Y, >=, X); \ + RANGETEST(Y, ==, X); \ + RANGETEST(Y, !=, X); \ + } while (0) - TESTEM(8, r1); - TESTEM(9, r1); - TESTEM(27, r1); - TESTEM(28, r1); + TESTEM(8, r1); + TESTEM(9, r1); + TESTEM(27, r1); + TESTEM(28, r1); - TESTEM(0x0fff, r2); - TESTEM(0x1000, r2); - TESTEM(0x10ff, r2); - TESTEM(0x1100, r2); + TESTEM(0x0fff, r2); + TESTEM(0x1000, r2); + TESTEM(0x10ff, r2); + TESTEM(0x1100, r2); - return 0; + return 0; } diff --git a/src/unittest/sized_test.cc b/src/unittest/sized_test.cc deleted file mode 100644 index f1bf7528f..000000000 --- a/src/unittest/sized_test.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Dave Greene - * Nathan Binkert - */ - -#include <iostream> -#include <algorithm> - -#include "sized.hh" -#include <queue> -#include <typeinfo> - -template<typename C> -void print(C &cont) -{ - std::cout << std::endl; - std::cout << "Printing " << typeid(cont).name() << std::endl; - while (!cont.empty()) { - std::cout << cont.front() << " "; - cont.pop(); - } - std::cout << std::endl; -} - -int main(void) -{ - sized<std::queue<int>, sized_error_policy<std::queue<int> > > - error_queue(10); - sized<std::queue<int>, sized_drop_policy<std::queue<int> > > - drop_queue(5); - - for (int i = 0; i < 10; ++i) { - error_queue.push(i); - } - - for (int i = 0; i < 3; ++i) { - drop_queue.push(i); - } - - print(error_queue); - print(drop_queue); - - return(0); -} diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc index 4e504fde9..3934786ec 100644 --- a/src/unittest/stattest.cc +++ b/src/unittest/stattest.cc @@ -30,9 +30,7 @@ #include <iomanip> #include <iostream> -#include <fstream> #include <string> -#include <unistd.h> #include "base/cprintf.hh" #include "base/misc.hh" @@ -44,36 +42,6 @@ using namespace std; using namespace Stats; -Tick curTick = 0; -Tick ticksPerSecond = ULL(2000000000); - -Scalar<> s1; -Scalar<> s2; -Average<> s3; -Scalar<> s4; -Vector<> s5; -Distribution<> s6; -Vector<> s7; -AverageVector<> s8; -StandardDeviation<> s9; -AverageDeviation<> s10; -Scalar<> s11; -Distribution<> s12; -VectorDistribution<> s13; -VectorStandardDeviation<> s14; -VectorAverageDeviation<> s15; -Vector2d<> s16; - -Formula f1; -Formula f2; -Formula f3; -Value f4; -Value f5; -Formula f6; -Formula f7; - -ostream *outputStream = &cout; - double testfunc() { @@ -85,7 +53,7 @@ class TestClass { double operator()() { return 9.7; } }; -char *progname = ""; +const char *progname = ""; void usage() @@ -101,14 +69,18 @@ main(int argc, char *argv[]) bool descriptions = false; bool compat = false; bool text = false; + +#if USE_MYSQL string mysql_name; + string mysql_db; string mysql_host; string mysql_user = "binkertn"; string mysql_passwd; +#endif char c; progname = argv[0]; - while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) { + while ((c = getopt(argc, argv, "cD:dh:P:p:s:tu:")) != -1) { switch (c) { case 'c': compat = true; @@ -116,6 +88,13 @@ main(int argc, char *argv[]) case 'd': descriptions = true; break; + case 't': + text = true; + break; +#if USE_MYSQL + case 'D': + mysql_db = optarg; + break; case 'h': mysql_host = optarg; break; @@ -125,12 +104,10 @@ main(int argc, char *argv[]) case 's': mysql_name = optarg; break; - case 't': - text = true; - break; case 'u': mysql_user = optarg; break; +#endif default: usage(); } @@ -139,15 +116,34 @@ main(int argc, char *argv[]) if (!text && (compat || descriptions)) usage(); - s5.init(5); - s6.init(1, 100, 13); - s7.init(7); - s8.init(10); - s12.init(1, 100, 13); - s13.init(4, 0, 99, 10); - s14.init(9); - s15.init(10); - s16.init(2, 9); + Scalar s1; + Scalar s2; + Average s3; + Scalar s4; + Vector s5; + Distribution s6; + Vector s7; + AverageVector s8; + StandardDeviation s9; + AverageDeviation s10; + Scalar s11; + Distribution s12; + VectorDistribution s13; + VectorStandardDeviation s14; + VectorAverageDeviation s15; + Vector2d s16; + Value s17; + Value s18; + + Formula f1; + Formula f2; + Formula f3; + Formula f4; + Formula f5; + + cprintf("sizeof(Scalar) = %d\n", sizeof(Scalar)); + cprintf("sizeof(Vector) = %d\n", sizeof(Vector)); + cprintf("sizeof(Distribution) = %d\n", sizeof(Distribution)); s1 .name("Stat01") @@ -163,7 +159,7 @@ main(int argc, char *argv[]) s3 .name("Stat03") .desc("this is statistic 3") - .prereq(f7) + .prereq(f5) ; s4 @@ -173,6 +169,7 @@ main(int argc, char *argv[]) ; s5 + .init(5) .name("Stat05") .desc("this is statistic 5") .prereq(s11) @@ -184,12 +181,14 @@ main(int argc, char *argv[]) ; s6 + .init(1, 100, 13) .name("Stat06") .desc("this is statistic 6") .prereq(s11) ; s7 + .init(7) .name("Stat07") .desc("this is statistic 7") .precision(1) @@ -198,6 +197,7 @@ main(int argc, char *argv[]) ; s8 + .init(10) .name("Stat08") .desc("this is statistic 8") .precision(2) @@ -219,26 +219,31 @@ main(int argc, char *argv[]) ; s12 + .init(1, 100, 13) .name("Stat12") .desc("this is statistic 12") ; s13 + .init(4, 0, 99, 10) .name("Stat13") .desc("this is statistic 13") ; s14 + .init(9) .name("Stat14") .desc("this is statistic 14") ; s15 + .init(10) .name("Stat15") .desc("this is statistic 15") ; s16 + .init(2, 9) .name("Stat16") .desc("this is statistic 16") .flags(total) @@ -248,6 +253,20 @@ main(int argc, char *argv[]) .ysubname(1, "y1") ; + s17 + .functor(testfunc) + .name("Stat17") + .desc("this is stat 17") + ; + + TestClass testclass; + s18 + .functor(testclass) + .name("Stat18") + .desc("this is stat 18") + ; + + f1 .name("Formula1") .desc("this is formula 1") @@ -273,29 +292,17 @@ main(int argc, char *argv[]) ; f4 - .functor(testfunc) .name("Formula4") .desc("this is formula 4") ; - TestClass testclass; - f5 - .functor(testclass) - .name("Formula5") - .desc("this is formula 5") - ; - - f6 - .name("Formula6") - .desc("this is formula 6") - ; f1 = s1 + s2; f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); f3 = sum(s5) * s7; - f6 += constant(10.0); - f6 += s5[3]; - f7 = constant(1); + f4 += constant(10.0); + f4 += s5[3]; + f5 = constant(1); check(); reset(); @@ -545,12 +552,14 @@ main(int argc, char *argv[]) out(); } +#if USE_MYSQL if (!mysql_name.empty()) { MySql out; - out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats", + out.connect(mysql_host, mysql_db, mysql_user, mysql_passwd, "test", mysql_name, "test"); out(); } +#endif return 0; } diff --git a/src/unittest/strnumtest.cc b/src/unittest/strnumtest.cc index ea28e35df..0e234884d 100644 --- a/src/unittest/strnumtest.cc +++ b/src/unittest/strnumtest.cc @@ -28,8 +28,7 @@ * Authors: Nathan Binkert */ -#include <iostream.h> - +#include <iostream> #include <string> #include <vector> @@ -40,39 +39,39 @@ using namespace std; int main(int argc, char *argv[]) { - if (argc != 2) { - cout << "Usage: " << argv[0] << " <number>\n"; - exit(1); - } + if (argc != 2) { + cout << "Usage: " << argv[0] << " <number>\n"; + exit(1); + } - string s = argv[1]; + string s = argv[1]; #define OUTVAL(valtype, type) do { \ - valtype value; \ - cout << "TYPE = " #valtype "\n"; \ - if (to_number(s, value)) { \ - cout << "Number(" << s << ") = " << dec \ - << (unsigned long long)(unsigned type)value << "\n" \ - << "Number(" << s << ") = " << dec \ - << (signed long long)(signed type)value << "\n" \ - << "Number(" << s << ") = 0x" << hex \ - << (unsigned long long)(unsigned type)value << "\n" \ - << "Number(" << s << ") = 0" << oct \ - << (unsigned long long)(unsigned type)value << "\n\n"; \ - } else \ - cout << "Number(" << s << ") is invalid\n\n"; \ - } while (0) + valtype value; \ + cout << "TYPE = " #valtype "\n"; \ + if (to_number(s, value)) { \ + cout << "Number(" << s << ") = " << dec \ + << (unsigned long long)(unsigned type)value << "\n" \ + << "Number(" << s << ") = " << dec \ + << (signed long long)(signed type)value << "\n" \ + << "Number(" << s << ") = 0x" << hex \ + << (unsigned long long)(unsigned type)value << "\n" \ + << "Number(" << s << ") = 0" << oct \ + << (unsigned long long)(unsigned type)value << "\n\n"; \ + } else \ + cout << "Number(" << s << ") is invalid\n\n"; \ + } while (0) - OUTVAL(signed long long, long long); - OUTVAL(unsigned long long, long long); - OUTVAL(signed long, long); - OUTVAL(unsigned long, long); - OUTVAL(signed int, int); - OUTVAL(unsigned int, int); - OUTVAL(signed short, short); - OUTVAL(unsigned short, short); - OUTVAL(signed char, char); - OUTVAL(unsigned char, char); + OUTVAL(signed long long, long long); + OUTVAL(unsigned long long, long long); + OUTVAL(signed long, long); + OUTVAL(unsigned long, long); + OUTVAL(signed int, int); + OUTVAL(unsigned int, int); + OUTVAL(signed short, short); + OUTVAL(unsigned short, short); + OUTVAL(signed char, char); + OUTVAL(unsigned char, char); - return 0; + return 0; } diff --git a/src/unittest/symtest.cc b/src/unittest/symtest.cc index f0142b923..10ffb42e5 100644 --- a/src/unittest/symtest.cc +++ b/src/unittest/symtest.cc @@ -28,12 +28,12 @@ * Authors: Nathan Binkert */ -#include <iostream.h> +#include <iostream> #include "base/str.hh" #include "base/loader/symtab.hh" -Tick curTick = 0; +using namespace std; void usage(const char *progname) |