diff options
Diffstat (limited to 'src')
75 files changed, 1423 insertions, 611 deletions
diff --git a/src/SConscript b/src/SConscript index 5efd2f794..34c5453b7 100644 --- a/src/SConscript +++ b/src/SConscript @@ -30,28 +30,71 @@ import os import sys +import zipfile +from os.path import basename from os.path import join as joinpath +import SCons + # This file defines how to build a particular configuration of M5 # based on variable settings in the 'env' build environment. Import('*') +# Children need to see the environment +Export('env') + +######################################################################## +# Code for adding source files +# sources = [] -def Source(*args): - for arg in args: - if isinstance(arg, (list, tuple)): - # Recurse to load a list - Source(*arg) - elif isinstance(arg, str): - sources.extend([ File(f) for f in Split(arg) ]) - else: - sources.append(File(arg)) +def Source(source): + if isinstance(source, SCons.Node.FS.File): + sources.append(source) + else: + sources.append(File(source)) -Export('env') +# Children should have access Export('Source') +######################################################################## +# Code for adding python objects +# +py_sources = [] +py_source_packages = {} +def PySource(package, source): + if not isinstance(source, SCons.Node.FS.File): + source = File(source) + py_source_packages[source] = package + py_sources.append(source) + +sim_objects = [] +def SimObject(source): + if not isinstance(source, SCons.Node.FS.File): + source = File(source) + PySource('m5.objects', source) + modname = basename(str(source)) + sim_objects.append(modname) + +swig_sources = [] +swig_source_packages = {} +def SwigSource(package, source): + if not isinstance(source, SCons.Node.FS.File): + source = File(source) + swig_source_packages[source] = package + swig_sources.append(source) + +# Children should have access +Export('PySource') +Export('SimObject') +Export('SwigSource') + +######################################################################## +# +# Set some compiler variables +# + # Include file paths are rooted in this directory. SCons will # automatically expand '.' to refer to both the source directory and # the corresponding build directory to pick up generated include @@ -61,7 +104,9 @@ env.Append(CPPPATH=Dir('.')) # Add a flag defining what THE_ISA should be for all compilation env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) +######################################################################## # Walk the tree and execute all SConscripts +# scripts = [] srcdir = env['SRCDIR'] for root, dirs, files in os.walk(srcdir, topdown=True): @@ -78,6 +123,132 @@ for root, dirs, files in os.walk(srcdir, topdown=True): for opt in env.ExportOptions: env.ConfigFile(opt) +######################################################################## +# +# Deal with python/swig, object code. Collect .py files and +# generating a zip archive that is appended to the m5 binary. +# + +# Generate Python file that contains a dict specifying the current +# build_env flags. +def MakeDefinesPyFile(target, source, env): + f = file(str(target[0]), 'w') + print >>f, "m5_build_env = ", source[0] + f.close() + +optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) +env.Command('python/m5/defines.py', Value(optionDict), MakeDefinesPyFile) +PySource('m5', 'python/m5/defines.py') + +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() + +env.Command('python/m5/info.py', + [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], + MakeInfoPyFile) +PySource('m5', 'python/m5/info.py') + +def MakeObjectsInitFile(target, source, env): + f = file(str(target[0]), 'w') + print >>f, 'from m5.SimObject import *' + for src_path in source: + src_file = basename(src_path.get_contents()) + assert(src_file.endswith('.py')) + src_module = src_file[:-3] + print >>f, 'from %s import *' % src_module + f.close() + +env.Command('python/m5/objects/__init__.py', + [ Value(o) for o in sim_objects], + MakeObjectsInitFile) +PySource('m5.objects', 'python/m5/objects/__init__.py') + +swig_modules = [] +for source in swig_sources: + source.rfile() # Hack to cause the symlink to the .i file to be created + package = swig_source_packages[source] + filename = str(source) + module = basename(filename) + + assert(module.endswith('.i')) + module = module[:-2] + cc_file = 'swig/%s_wrap.cc' % module + py_file = 'm5/internal/%s.py' % module + + env.Command([cc_file, py_file], source, + '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' + '-o ${TARGETS[0]} $SOURCES') + env.Depends(py_file, source) + env.Depends(cc_file, source) + + swig_modules.append(Value(module)) + Source(cc_file) + PySource(package, py_file) + +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 init_swig() {' + for module in source: + print >>f, ' init_%s();' % module.get_contents() + print >>f, '}' + f.close() +env.Command('python/swig/init.cc', swig_modules, MakeSwigInit) + +def CompilePyFile(target, source, env): + import py_compile + py_compile.compile(str(source[0]), str(target[0])) + +py_compiled = [] +py_arcname = {} +py_zip_depends = [] +for source in py_sources: + filename = str(source) + package = py_source_packages[source] + arc_path = package.split('.') + [ basename(filename) + 'c' ] + zip_path = [ 'zip' ] + arc_path + arcname = joinpath(*arc_path) + zipname = joinpath(*zip_path) + f = File(zipname) + + env.Command(f, source, CompilePyFile) + py_compiled.append(f) + py_arcname[f] = arcname + + # make the zipfile depend on the archive name so that the archive + # is rebuilt if the name changes + py_zip_depends.append(Value(arcname)) + +# Action function to build the zip archive. Uses the PyZipFile module +# included in the standard Python library. +def buildPyZip(target, source, env): + zf = zipfile.ZipFile(str(target[0]), 'w') + for s in source: + arcname = py_arcname[s] + zipname = str(s) + zf.write(zipname, arcname) + zf.close() + +# Add the zip file target to the environment. +env.Command('m5py.zip', py_compiled, buildPyZip) +env.Depends('m5py.zip', py_zip_depends) + +######################################################################## +# +# Define binaries. Each different build type (debug, opt, etc.) gets +# a slightly different build environment. +# + +# List of constructed environments to pass back to SConstruct +envList = [] + # This function adds the specified sources to the given build # environment, and returns a list of all the corresponding SCons # Object nodes (including an extra one for date.cc). We explicitly @@ -92,16 +263,6 @@ def make_objs(sources, env): objs.append(date_obj) return objs -################################################### -# -# Define binaries. Each different build type (debug, opt, etc.) gets -# a slightly different build environment. -# -################################################### - -# List of constructed environments to pass back to SConstruct -envList = [] - # Function to create a new build environment as clone of current # environment 'env' with modified object suffix and optional stripped # binary. Additional keyword arguments are appended to corresponding @@ -120,7 +281,7 @@ def makeEnv(label, objsfx, strip = False, **kwargs): else: newEnv.Command(stripped_bin, bin, 'strip $SOURCE -o $TARGET') bin = stripped_bin - targets = newEnv.Concat(exe, [bin, 'python/m5py.zip']) + targets = newEnv.Concat(exe, [bin, 'm5py.zip']) newEnv.M5Binary = targets[0] envList.append(newEnv) diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc index ec5090eb8..86b8fd2d0 100644 --- a/src/arch/alpha/ev5.cc +++ b/src/arch/alpha/ev5.cc @@ -245,13 +245,13 @@ AlphaISA::MiscRegFile::readIpr(int idx, ThreadContext *tc) { AlphaISA::PTE &pte = tc->getDTBPtr()->index(!tc->misspeculating()); - retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; - retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; - retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; - retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; - retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; - retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; - retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; + retval |= ((uint64_t)pte.ppn & ULL(0x7ffffff)) << 32; + retval |= ((uint64_t)pte.xre & ULL(0xf)) << 8; + retval |= ((uint64_t)pte.xwe & ULL(0xf)) << 12; + retval |= ((uint64_t)pte.fonr & ULL(0x1)) << 1; + retval |= ((uint64_t)pte.fonw & ULL(0x1))<< 2; + retval |= ((uint64_t)pte.asma & ULL(0x1)) << 4; + retval |= ((uint64_t)pte.asn & ULL(0x7f)) << 57; } break; diff --git a/src/arch/alpha/floatregfile.hh b/src/arch/alpha/floatregfile.hh index d289f5785..0c5fe17a7 100644 --- a/src/arch/alpha/floatregfile.hh +++ b/src/arch/alpha/floatregfile.hh @@ -35,7 +35,7 @@ #include "arch/alpha/isa_traits.hh" #include "arch/alpha/types.hh" -#include <string.h> +#include <cstring> #include <iostream> class Checkpoint; @@ -61,7 +61,7 @@ namespace AlphaISA void unserialize(Checkpoint *cp, const std::string §ion); void clear() - { bzero(d, sizeof(d)); } + { std::memset(d, 0, sizeof(d)); } }; } diff --git a/src/arch/alpha/intregfile.hh b/src/arch/alpha/intregfile.hh index 0d65f69e0..dea160992 100644 --- a/src/arch/alpha/intregfile.hh +++ b/src/arch/alpha/intregfile.hh @@ -35,7 +35,7 @@ #include "arch/alpha/types.hh" #include <iostream> -#include <strings.h> +#include <cstring> class Checkpoint; @@ -71,7 +71,7 @@ namespace AlphaISA void unserialize(Checkpoint *cp, const std::string §ion); void clear() - { bzero(regs, sizeof(regs)); } + { std::memset(regs, 0, sizeof(regs)); } }; } diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa index a350aa05f..773e7d10c 100644 --- a/src/arch/alpha/isa/fp.isa +++ b/src/arch/alpha/isa/fp.isa @@ -192,10 +192,10 @@ output decoder {{ } const int AlphaFP::alphaToC99RoundingMode[] = { - FE_TOWARDZERO, // Chopped - FE_DOWNWARD, // Minus_Infinity - FE_TONEAREST, // Normal - FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR + M5_FE_TOWARDZERO, // Chopped + M5_FE_DOWNWARD, // Minus_Infinity + M5_FE_TONEAREST, // Normal + M5_FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR }; const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" }; @@ -228,10 +228,10 @@ def template FloatingPointExecute {{ if (roundingMode == Normal) { %(code)s; } else { - fesetround(getC99RoundingMode( + m5_fesetround(getC99RoundingMode( xc->readMiscRegNoEffect(AlphaISA::MISCREG_FPCR))); %(code)s; - fesetround(FE_TONEAREST); + m5_fesetround(M5_FE_TONEAREST); } #else if (roundingMode != Normal && !warnedOnRounding) { diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc index e9f126f12..714bca22a 100644 --- a/src/arch/alpha/tlb.cc +++ b/src/arch/alpha/tlb.cc @@ -213,7 +213,7 @@ TLB::flushAddr(Addr addr, uint8_t asn) if (i == lookupTable.end()) return; - while (i->first == vaddr.vpn()) { + while (i != lookupTable.end() && i->first == vaddr.vpn()) { int index = i->second; PTE *pte = &table[index]; assert(pte->valid); @@ -225,10 +225,10 @@ TLB::flushAddr(Addr addr, uint8_t asn) // invalidate this entry pte->valid = false; - lookupTable.erase(i); + lookupTable.erase(i++); + } else { + ++i; } - - ++i; } } diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa index bba63f407..4339003e0 100644 --- a/src/arch/sparc/isa/base.isa +++ b/src/arch/sparc/isa/base.isa @@ -154,6 +154,76 @@ def template ROrImmDecode {{ } }}; +output header {{ + union DoubleSingle + { + double d; + uint64_t ui; + uint32_t s[2]; + DoubleSingle(double _d) : d(_d) + {} + DoubleSingle(uint64_t _ui) : ui(_ui) + {} + DoubleSingle(uint32_t _s0, uint32_t _s1) + { + s[0] = _s0; + s[1] = _s1; + } + }; +}}; + +let {{ + def filterDoubles(code): + assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) + for opName in ("Frd", "Frs1", "Frs2", "Frd_N"): + next_pos = 0 + operandsREString = (r''' + (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches + ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix + (?![\w\.]) # neg. lookahead assertion: prevent partial matches + ''' % opName) + operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) + is_src = False + is_dest = False + extension = None + foundOne = False + while 1: + match = operandsRE.search(code, next_pos) + if not match: + break + foundOne = True + op = match.groups() + (op_full, op_base, op_ext) = op + is_dest_local = (assignRE.match(code, match.end()) != None) + is_dest = is_dest or is_dest_local + is_src = is_src or not is_dest_local + if extension and extension != op_ext: + raise Exception, "Inconsistent extensions in double filter." + extension = op_ext + next_pos = match.end() + if foundOne: + # Get rid of any unwanted extension + code = operandsRE.sub(op_base, code) + is_int = False + member = "d" + if extension in ("sb", "ub", "shw", "uhw", "sw", "uw", "sdw", "udw"): + is_int = True + member = "ui" + if is_src: + code = ("%s = DoubleSingle(%s_high, %s_low).%s;" % \ + (opName, opName, opName, member)) + code + if is_dest: + code += ''' + %s_low = DoubleSingle(%s).s[1]; + %s_high = DoubleSingle(%s).s[0];''' % \ + (opName, opName, opName, opName) + if is_int: + code = ("uint64_t %s;" % opName) + code + else: + code = ("double %s;" % opName) + code + return code +}}; + let {{ def splitOutImm(code): matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?') diff --git a/src/arch/sparc/isa/formats/basic.isa b/src/arch/sparc/isa/formats/basic.isa index 017f43780..5b0868132 100644 --- a/src/arch/sparc/isa/formats/basic.isa +++ b/src/arch/sparc/isa/formats/basic.isa @@ -97,6 +97,7 @@ def template BasicDecodeWithMnemonic {{ // The most basic instruction format... used only for a few misc. insts def format BasicOperate(code, *flags) {{ + code = filterDoubles(code) iop = InstObjParams(name, Name, 'SparcStaticInst', code, flags) header_output = BasicDeclare.subst(iop) decoder_output = BasicConstructor.subst(iop) @@ -108,38 +109,24 @@ def format FpBasic(code, *flags) {{ fp_code = """ Fsr |= bits(Fsr,4,0) << 5; Fsr = insertBits(Fsr,4,0,0); -#if defined(__sun) || defined (__OpenBSD__) - fp_rnd newrnd = FP_RN; + int newrnd = M5_FE_TONEAREST; switch (Fsr<31:30>) { - case 0: newrnd = FP_RN; break; - case 1: newrnd = FP_RZ; break; - case 2: newrnd = FP_RP; break; - case 3: newrnd = FP_RM; break; + case 0: newrnd = M5_FE_TONEAREST; break; + case 1: newrnd = M5_FE_TOWARDZERO; break; + case 2: newrnd = M5_FE_UPWARD; break; + case 3: newrnd = M5_FE_DOWNWARD; break; } - fp_rnd oldrnd = fpsetround(newrnd); -#else - int newrnd = FE_TONEAREST; - switch (Fsr<31:30>) { - case 0: newrnd = FE_TONEAREST; break; - case 1: newrnd = FE_TOWARDZERO; break; - case 2: newrnd = FE_UPWARD; break; - case 3: newrnd = FE_DOWNWARD; break; - } - int oldrnd = fegetround(); - fesetround(newrnd); -#endif + int oldrnd = m5_fegetround(); + m5_fesetround(newrnd); """ fp_code += code fp_code += """ -#if defined(__sun) || defined (__OpenBSD__) - fpsetround(oldrnd); -#else - fesetround(oldrnd); -#endif + m5_fesetround(oldrnd); """ + fp_code = filterDoubles(fp_code) iop = InstObjParams(name, Name, 'SparcStaticInst', fp_code, flags) header_output = BasicDeclare.subst(iop) decoder_output = BasicConstructor.subst(iop) diff --git a/src/arch/sparc/isa/formats/mem/basicmem.isa b/src/arch/sparc/isa/formats/mem/basicmem.isa index 751262811..2f62c7bef 100644 --- a/src/arch/sparc/isa/formats/mem/basicmem.isa +++ b/src/arch/sparc/isa/formats/mem/basicmem.isa @@ -71,6 +71,7 @@ let {{ }}; def format LoadAlt(code, asi, *opt_flags) {{ + code = filterDoubles(code) (header_output, decoder_output, exec_output, @@ -79,6 +80,7 @@ def format LoadAlt(code, asi, *opt_flags) {{ }}; def format StoreAlt(code, asi, *opt_flags) {{ + code = filterDoubles(code) (header_output, decoder_output, exec_output, @@ -87,6 +89,7 @@ def format StoreAlt(code, asi, *opt_flags) {{ }}; def format Load(code, *opt_flags) {{ + code = filterDoubles(code) (header_output, decoder_output, exec_output, @@ -95,6 +98,7 @@ def format Load(code, *opt_flags) {{ }}; def format Store(code, *opt_flags) {{ + code = filterDoubles(code) (header_output, decoder_output, exec_output, diff --git a/src/arch/sparc/isa/formats/mem/blockmem.isa b/src/arch/sparc/isa/formats/mem/blockmem.isa index 499685a5c..e19016bd0 100644 --- a/src/arch/sparc/isa/formats/mem/blockmem.isa +++ b/src/arch/sparc/isa/formats/mem/blockmem.isa @@ -317,6 +317,7 @@ let {{ }}; def format BlockLoad(code, asi, *opt_flags) {{ + code = filterDoubles(code) # We need to make sure to check the highest priority fault last. # That way, if other faults have been detected, they'll be overwritten # rather than the other way around. @@ -329,6 +330,7 @@ def format BlockLoad(code, asi, *opt_flags) {{ }}; def format BlockStore(code, asi, *opt_flags) {{ + code = filterDoubles(code) # We need to make sure to check the highest priority fault last. # That way, if other faults have been detected, they'll be overwritten # rather than the other way around. diff --git a/src/arch/sparc/isa/formats/mem/swap.isa b/src/arch/sparc/isa/formats/mem/swap.isa index b71542a2b..f3d15670f 100644 --- a/src/arch/sparc/isa/formats/mem/swap.isa +++ b/src/arch/sparc/isa/formats/mem/swap.isa @@ -39,7 +39,7 @@ def template SwapExecute {{ Addr EA; %(fp_enable_check)s; %(op_decl)s; - uint64_t mem_data; + uint64_t mem_data = 0; %(op_rd)s; %(ea_code)s; diff --git a/src/arch/sparc/isa/formats/micro.isa b/src/arch/sparc/isa/formats/micro.isa index 82d7fb4cb..da0f97d1b 100644 --- a/src/arch/sparc/isa/formats/micro.isa +++ b/src/arch/sparc/isa/formats/micro.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2006 The Regents of The University of Michigan +// 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 @@ -26,6 +26,33 @@ // // Authors: Gabe Black +//This delcares the initiateAcc function in memory operations +def template MacroInitiateAcc {{ + Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + panic("Tried to execute a macroop directly!\n"); + return NoFault; + } +}}; + +def template MacroCompleteAcc {{ + Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, + Trace::InstRecord *) const + { + panic("Tried to execute a macroop directly!\n"); + return NoFault; + } +}}; + +//This template provides the execute functions for a store +def template MacroExecute {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + panic("Tried to execute a macroop directly!\n"); + return NoFault; + } +}}; + output header {{ class SparcMacroInst : public SparcStaticInst @@ -60,7 +87,9 @@ output header {{ return microOps[microPC]; } - %(BasicExecPanic)s + %(MacroExecute)s + %(MacroInitiateAcc)s + %(MacroCompleteAcc)s }; class SparcMicroInst : public SparcStaticInst diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa index 05e9e8731..e9cd660b5 100644 --- a/src/arch/sparc/isa/includes.isa +++ b/src/arch/sparc/isa/includes.isa @@ -53,22 +53,14 @@ output decoder {{ #include "cpu/thread_context.hh" // for Jump::branchTarget() #include "mem/packet.hh" -#if defined(linux) || defined(__APPLE__) -#include <fenv.h> -#endif +#include "base/fenv.hh" #include <algorithm> using namespace SparcISA; }}; output exec {{ -#if defined(linux) || defined(__APPLE__) -#include <fenv.h> -#endif - -#if defined(__sun) || defined (__OpenBSD__) -#include <ieeefp.h> -#endif +#include "base/fenv.hh" #if FULL_SYSTEM #include "sim/pseudo_inst.hh" diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa index 038919bd1..58d616a7a 100644 --- a/src/arch/sparc/isa/operands.isa +++ b/src/arch/sparc/isa/operands.isa @@ -52,6 +52,16 @@ output header {{ { return (regNum & (~1)) | ((regNum & 1) << 5); } + + static inline unsigned int dfprl(unsigned int regNum) + { + return dfpr(regNum) & (~0x1); + } + + static inline unsigned int dfprh(unsigned int regNum) + { + return dfpr(regNum) | 0x1; + } }}; def operands {{ @@ -79,21 +89,43 @@ def operands {{ # differently, they get different operands. The single precision versions # have an s post pended to their name. 'Frds': ('FloatReg', 'sf', 'RD', 'IsFloating', 10), - 'Frd': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), + #'Frd': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), + 'Frd_low': ('FloatReg', 'uw', 'dfprl(RD)', 'IsFloating', 10), + 'Frd_high': ('FloatReg', 'uw', 'dfprh(RD)', 'IsFloating', 10), # Each Frd_N refers to the Nth double precision register from Frd. # Note that this adds twice N to the register number. - 'Frd_0': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), - 'Frd_1': ('FloatReg', 'df', 'dfpr(RD) + 2', 'IsFloating', 10), - 'Frd_2': ('FloatReg', 'df', 'dfpr(RD) + 4', 'IsFloating', 10), - 'Frd_3': ('FloatReg', 'df', 'dfpr(RD) + 6', 'IsFloating', 10), - 'Frd_4': ('FloatReg', 'df', 'dfpr(RD) + 8', 'IsFloating', 10), - 'Frd_5': ('FloatReg', 'df', 'dfpr(RD) + 10', 'IsFloating', 10), - 'Frd_6': ('FloatReg', 'df', 'dfpr(RD) + 12', 'IsFloating', 10), - 'Frd_7': ('FloatReg', 'df', 'dfpr(RD) + 14', 'IsFloating', 10), + #'Frd_0': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), + 'Frd_0_low': ('FloatReg', 'uw', 'dfprl(RD)', 'IsFloating', 10), + 'Frd_0_high': ('FloatReg', 'uw', 'dfprh(RD)', 'IsFloating', 10), + #'Frd_1': ('FloatReg', 'df', 'dfpr(RD) + 2', 'IsFloating', 10), + 'Frd_1_low': ('FloatReg', 'uw', 'dfprl(RD) + 2', 'IsFloating', 10), + 'Frd_1_high': ('FloatReg', 'uw', 'dfprh(RD) + 2', 'IsFloating', 10), + #'Frd_2': ('FloatReg', 'df', 'dfpr(RD) + 4', 'IsFloating', 10), + 'Frd_2_low': ('FloatReg', 'uw', 'dfprl(RD) + 4', 'IsFloating', 10), + 'Frd_2_high': ('FloatReg', 'uw', 'dfprh(RD) + 4', 'IsFloating', 10), + #'Frd_3': ('FloatReg', 'df', 'dfpr(RD) + 6', 'IsFloating', 10), + 'Frd_3_low': ('FloatReg', 'uw', 'dfprl(RD) + 6', 'IsFloating', 10), + 'Frd_3_high': ('FloatReg', 'uw', 'dfprh(RD) + 6', 'IsFloating', 10), + #'Frd_4': ('FloatReg', 'df', 'dfpr(RD) + 8', 'IsFloating', 10), + 'Frd_4_low': ('FloatReg', 'uw', 'dfprl(RD) + 8', 'IsFloating', 10), + 'Frd_4_high': ('FloatReg', 'uw', 'dfprh(RD) + 8', 'IsFloating', 10), + #'Frd_5': ('FloatReg', 'df', 'dfpr(RD) + 10', 'IsFloating', 10), + 'Frd_5_low': ('FloatReg', 'uw', 'dfprl(RD) + 10', 'IsFloating', 10), + 'Frd_5_high': ('FloatReg', 'uw', 'dfprh(RD) + 10', 'IsFloating', 10), + #'Frd_6': ('FloatReg', 'df', 'dfpr(RD) + 12', 'IsFloating', 10), + 'Frd_6_low': ('FloatReg', 'uw', 'dfprl(RD) + 12', 'IsFloating', 10), + 'Frd_6_high': ('FloatReg', 'uw', 'dfprh(RD) + 12', 'IsFloating', 10), + #'Frd_7': ('FloatReg', 'df', 'dfpr(RD) + 14', 'IsFloating', 10), + 'Frd_7_low': ('FloatReg', 'uw', 'dfprl(RD) + 14', 'IsFloating', 10), + 'Frd_7_high': ('FloatReg', 'uw', 'dfprh(RD) + 14', 'IsFloating', 10), 'Frs1s': ('FloatReg', 'sf', 'RS1', 'IsFloating', 11), - 'Frs1': ('FloatReg', 'df', 'dfpr(RS1)', 'IsFloating', 11), + #'Frs1': ('FloatReg', 'df', 'dfpr(RS1)', 'IsFloating', 11), + 'Frs1_low': ('FloatReg', 'uw', 'dfprl(RS1)', 'IsFloating', 11), + 'Frs1_high': ('FloatReg', 'uw', 'dfprh(RS1)', 'IsFloating', 11), 'Frs2s': ('FloatReg', 'sf', 'RS2', 'IsFloating', 12), - 'Frs2': ('FloatReg', 'df', 'dfpr(RS2)', 'IsFloating', 12), + #'Frs2': ('FloatReg', 'df', 'dfpr(RS2)', 'IsFloating', 12), + 'Frs2_low': ('FloatReg', 'uw', 'dfprl(RS2)', 'IsFloating', 12), + 'Frs2_high': ('FloatReg', 'uw', 'dfprh(RS2)', 'IsFloating', 12), 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 31), 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 32), # Registers which are used explicitly in instructions diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index e4774ab54..d595664a0 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -39,6 +39,7 @@ #include "base/misc.hh" #include "cpu/thread_context.hh" #include "mem/page_table.hh" +#include "sim/process_impl.hh" #include "mem/translating_port.hh" #include "sim/system.hh" diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index e6d1e4921..af7494598 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -95,6 +95,7 @@ #include "cpu/thread_context.hh" #include "mem/page_table.hh" #include "mem/translating_port.hh" +#include "sim/process_impl.hh" #include "sim/system.hh" using namespace std; diff --git a/src/base/SConscript b/src/base/SConscript index 6fc140145..cc9d06a0e 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -57,6 +57,7 @@ Source('circlebuf.cc') Source('cprintf.cc') Source('crc.cc') Source('fast_alloc.cc') +Source('fenv.c') Source('fifo_buffer.cc') Source('hostinfo.cc') Source('hybrid_pred.cc') @@ -97,3 +98,5 @@ Source('stats/visit.cc') if env['USE_MYSQL']: Source('mysql.cc') Source('stats/mysql.cc') + +PySource('m5', 'traceflags.py') diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 69cce2245..518bad6b8 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -96,8 +96,9 @@ inline T insertBits(T val, int first, int last, B bit_val) { + T t_bit_val = bit_val; T bmask = mask(first - last + 1) << last; - return ((bit_val << last) & bmask) | (val & ~bmask); + return ((t_bit_val << last) & bmask) | (val & ~bmask); } /** diff --git a/src/base/fenv.c b/src/base/fenv.c new file mode 100644 index 000000000..269913a60 --- /dev/null +++ b/src/base/fenv.c @@ -0,0 +1,56 @@ +/* + * 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: Ali Saidi + */ + +#include <assert.h> +#include <stdlib.h> +#include <fenv.h> + +void m5_fesetround(int rm); +int m5_fegetround(); + +static const int m5_round_ops[] = {FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD}; + +void m5_fesetround(int rm) +{ + assert(rm > 0 && rm < 4); + fesetround(m5_round_ops[rm]); +} + +int m5_fegetround() +{ + int x; + int rm = fegetround(); + for(x = 0; x < 4; x++) + if (m5_round_ops[x] == rm) + return x; + abort(); + return 0; +} + diff --git a/src/base/fenv.hh b/src/base/fenv.hh index 013d2f09b..42b383888 100644 --- a/src/base/fenv.hh +++ b/src/base/fenv.hh @@ -33,20 +33,21 @@ #include "config/use_fenv.hh" -#if USE_FENV - -#include <fenv.h> +#define M5_FE_DOWNWARD 0 +#define M5_FE_TONEAREST 1 +#define M5_FE_TOWARDZERO 2 +#define M5_FE_UPWARD 3 +#if USE_FENV +extern "C" { +void m5_fesetround(int rm); +int m5_fegetround(); +} #else // Dummy definitions to allow code to compile w/o a real <fenv.h>. - -#define FE_TONEAREST 0 -#define FE_DOWNWARD 0 -#define FE_UPWARD 0 -#define FE_TOWARDZERO 0 - -inline int fesetround(int rounding_mode) { return 0; } +inline void m5_fesetround(int rm) { ; } +inline int m5_fegetround() {return 0; } #endif // USE_FENV diff --git a/src/base/random.cc b/src/base/random.cc index ceab337d9..8a2e3c1c0 100644 --- a/src/base/random.cc +++ b/src/base/random.cc @@ -29,9 +29,6 @@ * Ali Saidi */ -#if defined(__sun) -#include <ieeefp.h> -#endif #ifdef __SUNPRO_CC #include <stdlib.h> #include <math.h> @@ -40,6 +37,7 @@ #include <cstdlib> #include <cmath> +#include "base/fenv.hh" #include "base/random.hh" using namespace std; @@ -61,9 +59,10 @@ m5round(double r) { #if defined(__sun) double val; - fp_rnd oldrnd = fpsetround(FP_RN); + int oldrnd = m5_fegetround(); + m5_fesetround(M5_FE_TONEAREST); val = rint(r); - fpsetround(oldrnd); + m5_fesetround(oldrnd); return val; #else return round(r); diff --git a/src/base/statistics.hh b/src/base/statistics.hh index 761b30c2b..8d3f53d4c 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -2094,9 +2094,13 @@ class UnaryNode : public Node return vresult; } - Result total() const { - Op op; - return op(l->total()); + Result total() const + { + const VResult &vec = this->result(); + Result total = 0; + for (int i = 0; i < size(); i++) + total += vec[i]; + return total; } virtual size_t size() const { return l->size(); } @@ -2149,9 +2153,13 @@ class BinaryNode : public Node return vresult; } - Result total() const { - Op op; - return op(l->total(), r->total()); + Result total() const + { + const VResult &vec = this->result(); + Result total = 0; + for (int i = 0; i < size(); i++) + total += vec[i]; + return total; } virtual size_t size() const { diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 65625065d..dd4c333d3 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -641,9 +641,6 @@ DefaultCommit<Impl>::handleInterrupt() // an interrupt needed to be handled. DPRINTF(Commit, "Interrupt detected.\n"); - Fault new_interrupt = cpu->getInterrupts(); - assert(new_interrupt != NoFault); - // Clear the interrupt now that it's going to be handled toIEW->commitInfo[0].clearInterrupt = true; diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 2e6a43f9c..a775b66d5 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -384,25 +384,25 @@ FullO3CPU<Impl>::fullCPURegStats() .name(name() + ".cpi") .desc("CPI: Cycles Per Instruction") .precision(6); - cpi = simTicks / committedInsts; + cpi = numCycles / committedInsts; totalCpi .name(name() + ".cpi_total") .desc("CPI: Total CPI of All Threads") .precision(6); - totalCpi = simTicks / totalCommittedInsts; + totalCpi = numCycles / totalCommittedInsts; ipc .name(name() + ".ipc") .desc("IPC: Instructions Per Cycle") .precision(6); - ipc = committedInsts / simTicks; + ipc = committedInsts / numCycles; totalIpc .name(name() + ".ipc_total") .desc("IPC: Total IPC of All Threads") .precision(6); - totalIpc = totalCommittedInsts / simTicks; + totalIpc = totalCommittedInsts / numCycles; } diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index f24de20d9..cc33e025d 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -33,6 +33,7 @@ #define __CPU_O3_LSQ_UNIT_HH__ #include <algorithm> +#include <cstring> #include <map> #include <queue> @@ -292,7 +293,7 @@ class LSQUnit { : inst(NULL), req(NULL), size(0), canWB(0), committed(0), completed(0) { - bzero(data, sizeof(data)); + std::memset(data, 0, sizeof(data)); } /** Constructs a store queue entry for a given instruction. */ @@ -300,7 +301,7 @@ class LSQUnit { : inst(_inst), req(NULL), size(0), canWB(0), committed(0), completed(0) { - bzero(data, sizeof(data)); + std::memset(data, 0, sizeof(data)); } /** The store instruction. */ diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index 44e2cea76..bde4f8079 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -680,7 +680,6 @@ LSQUnit<Impl>::writebackStores() inst->seqNum); WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this); wb->schedule(curTick + 1); - delete state; completeStore(storeWBIdx); incrStIdx(storeWBIdx); continue; diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4f623a3f5..d2718c5f9 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -79,7 +79,7 @@ BaseSimpleCPU::BaseSimpleCPU(Params *p) /* asid */ 0); #endif // !FULL_SYSTEM - thread->setStatus(ThreadContext::Suspended); + thread->setStatus(ThreadContext::Unallocated); tc = thread->getTC(); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 45da7c3eb..fa7bb4f86 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -574,10 +574,16 @@ TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) return true; } - else { - //Snooping a Coherence Request, do nothing - return true; + else if (pkt->result == Packet::Nacked) { + assert(cpu->_status == IcacheWaitResponse); + pkt->reinitNacked(); + if (!sendTiming(pkt)) { + cpu->_status = IcacheRetry; + cpu->ifetch_pkt = pkt; + } } + //Snooping a Coherence Request, do nothing + return true; } void @@ -663,10 +669,16 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) return true; } - else { - //Snooping a coherence req, do nothing - return true; + else if (pkt->result == Packet::Nacked) { + assert(cpu->_status == DcacheWaitResponse); + pkt->reinitNacked(); + if (!sendTiming(pkt)) { + cpu->_status = DcacheRetry; + cpu->dcache_pkt = pkt; + } } + //Snooping a Coherence Request, do nothing + return true; } void diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 39f31782b..191ae2f2e 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -221,10 +221,10 @@ SimpleThread::activate(int delay) lastActivate = curTick; - if (status() == ThreadContext::Unallocated) { - cpu->activateWhenReady(tid); - return; - } +// if (status() == ThreadContext::Unallocated) { +// cpu->activateWhenReady(tid); +// return; +// } _status = ThreadContext::Active; diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 4b65ca4b8..be8f822f2 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -169,9 +169,8 @@ ThreadState::getMemPort() return port; /* Use this port to for syscall emulation writes to memory. */ - port = new TranslatingPort(csprintf("%s-%d-funcport", - baseCpu->name(), tid), - process->pTable, false); + port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid), + process, TranslatingPort::NextPage); connectToMemFunc(port); diff --git a/src/dev/alpha/console.cc b/src/dev/alpha/console.cc index f077efe6c..443f376a5 100644 --- a/src/dev/alpha/console.cc +++ b/src/dev/alpha/console.cc @@ -76,7 +76,7 @@ AlphaConsole::AlphaConsole(Params *p) alphaAccess->diskOperation = 0; alphaAccess->outputChar = 0; alphaAccess->inputChar = 0; - bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack)); + std::memset(alphaAccess->cpuStack, 0, sizeof(alphaAccess->cpuStack)); } diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh index dfc224ecc..430f45d66 100644 --- a/src/dev/etherint.hh +++ b/src/dev/etherint.hh @@ -63,6 +63,9 @@ class EtherInt : public SimObject bool sendPacket(EthPacketPtr packet) { return peer ? peer->recvPacket(packet) : true; } virtual bool recvPacket(EthPacketPtr packet) = 0; + + bool askBusy() {return peer->isBusy(); } + virtual bool isBusy() { return false; } }; #endif // __DEV_ETHERINT_HH__ diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh index bb2854810..a16d6d799 100644 --- a/src/dev/etherlink.hh +++ b/src/dev/etherlink.hh @@ -114,6 +114,7 @@ class EtherLink : public SimObject Interface(const std::string &name, Link *txlink, Link *rxlink); bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); } void sendDone() { peer->sendDone(); } + bool isBusy() { return txlink->busy(); } }; Link *link[2]; diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 3d08bca1e..baf13c49a 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -656,7 +656,7 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet) return false; pktPtr = packet; - + pktDone = false; igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf), packet->length, &pktEvent, packet->data); return true; @@ -683,8 +683,12 @@ IGbE::RxDescCache::pktComplete() uint8_t status = RXDS_DD | RXDS_EOP; uint8_t err = 0; + IpPtr ip(pktPtr); + if (ip) { + DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); + if (igbe->regs.rxcsum.ipofld()) { DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; @@ -710,12 +714,15 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; desc->csum = htole(cksum(udp)); - if (cksum(tcp) != 0) { + if (cksum(udp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } - } // if ip + } else { // if ip + DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); + } + desc->status = htole(status); desc->errors = htole(err); @@ -727,12 +734,8 @@ IGbE::RxDescCache::pktComplete() if (igbe->regs.rdtr.delay()) { DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", igbe->regs.rdtr.delay() * igbe->intClock()); - if (igbe->rdtrEvent.scheduled()) - igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() * - igbe->intClock()); - else - igbe->rdtrEvent.schedule(curTick + igbe->regs.rdtr.delay() * - igbe->intClock()); + igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() * + igbe->intClock(),true); } if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) { @@ -895,6 +898,7 @@ IGbE::TxDescCache::pktComplete() pktPtr = NULL; DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); + enableSm(); return; } @@ -915,10 +919,20 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); + if (DTRACE(EthernetDesc)) { + IpPtr ip(pktPtr); + if (ip) + DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", + ip->id()); + else + DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); + } + // Checksums are only ofloaded for new descriptor types if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); + if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); @@ -927,11 +941,13 @@ IGbE::TxDescCache::pktComplete() if (TxdOp::txsm(desc)) { if (isTcp) { TcpPtr tcp(ip); + assert(tcp); tcp->sum(0); tcp->sum(cksum(tcp)); DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else { UdpPtr udp(ip); + assert(udp); udp->sum(0); udp->sum(cksum(udp)); DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); @@ -944,12 +960,8 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); if (igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tidv\n"); - if (igbe->tidvEvent.scheduled()) - igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * - igbe->intClock()); - else - igbe->tidvEvent.schedule(curTick + igbe->regs.tidv.idv() * - igbe->intClock()); + igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * + igbe->intClock(), true); } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { @@ -977,6 +989,7 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); writeback((igbe->cacheBlockSize()-1)>>4); } + enableSm(); igbe->checkDrain(); } @@ -1028,7 +1041,7 @@ IGbE::TxDescCache::hasOutstandingEvents() void IGbE::restartClock() { - if (!tickEvent.scheduled() && (rxTick || txTick) && getState() == + if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() == SimObject::Running) tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1)); } @@ -1156,6 +1169,8 @@ IGbE::txStateMachine() return; } + DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n"); + txTick = false; } bool @@ -1194,6 +1209,7 @@ IGbE::rxStateMachine() // If the packet is done check for interrupts/descriptors/etc if (rxDescCache.packetDone()) { + rxDmaPacket = false; DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); int descLeft = rxDescCache.descLeft(); switch (regs.rctl.rdmts()) { @@ -1238,6 +1254,12 @@ IGbE::rxStateMachine() return; } + if (rxDmaPacket) { + DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); + rxTick = false; + return; + } + if (!rxDescCache.descUnused()) { DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); rxTick = false; @@ -1264,6 +1286,7 @@ IGbE::rxStateMachine() rxFifo.pop(); DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); rxTick = false; + rxDmaPacket = true; } void @@ -1458,6 +1481,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE) SimObjectParam<System *> system; SimObjectParam<Platform *> platform; + Param<Tick> min_backoff_delay; + Param<Tick> max_backoff_delay; SimObjectParam<PciConfigData *> configdata; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; @@ -1479,6 +1504,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE) INIT_PARAM(system, "System pointer"), INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), + INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), INIT_PARAM(configdata, "PCI Config data"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), @@ -1503,6 +1530,8 @@ CREATE_SIM_OBJECT(IGbE) params->name = getInstanceName(); params->platform = platform; params->system = system; + params->min_backoff_delay = min_backoff_delay; + params->max_backoff_delay = max_backoff_delay; params->configData = configdata; params->busNum = pci_bus; params->deviceNum = pci_dev; diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index 2dec3b08c..b6da53b09 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -80,6 +80,8 @@ class IGbE : public PciDev bool txTick; bool txFifoTick; + bool rxDmaPacket; + // Event and function to deal with RDTR timer expiring void rdtrProcess() { rxDescCache.writeback(0); diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc index 1afad529f..921ba1cd0 100644 --- a/src/dev/ide_ctrl.cc +++ b/src/dev/ide_ctrl.cc @@ -751,6 +751,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) SimObjectParam<System *> system; SimObjectParam<Platform *> platform; + Param<Tick> min_backoff_delay; + Param<Tick> max_backoff_delay; SimObjectParam<PciConfigData *> configdata; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; @@ -765,6 +767,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) INIT_PARAM(system, "System pointer"), INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), + INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), INIT_PARAM(configdata, "PCI Config data"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), @@ -781,6 +785,8 @@ CREATE_SIM_OBJECT(IdeController) params->name = getInstanceName(); params->platform = platform; params->system = system; + params->min_backoff_delay = min_backoff_delay; + params->max_backoff_delay = max_backoff_delay; params->configData = configdata; params->busNum = pci_bus; params->deviceNum = pci_dev; diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index a1285fefc..6528bd81c 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -93,7 +93,8 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list) DmaPort::DmaPort(DmaDevice *dev, System *s) : Port(dev->name() + "-dmaport", dev), device(dev), sys(s), - pendingCount(0), actionInProgress(0), drainEvent(NULL) + pendingCount(0), actionInProgress(0), drainEvent(NULL), + backoffTime(0), inRetry(false), backoffEvent(this) { } bool @@ -104,12 +105,24 @@ DmaPort::recvTiming(PacketPtr pkt) if (pkt->result == Packet::Nacked) { DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n", pkt, pkt->senderState, pkt->getAddr()); + + if (backoffTime < device->minBackoffDelay) + backoffTime = device->minBackoffDelay; + else if (backoffTime < device->maxBackoffDelay) + backoffTime <<= 1; + + backoffEvent.reschedule(curTick + backoffTime, true); + + DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); + pkt->reinitNacked(); - sendDma(pkt, true); + queueDma(pkt, true); } else if (pkt->senderState) { DmaReqState *state; - DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x\n", - pkt, pkt->senderState, pkt->getAddr()); + backoffTime >>= 2; + + DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x size: %#x\n", + pkt, pkt->senderState, pkt->getAddr(), pkt->req->getSize()); state = dynamic_cast<DmaReqState*>(pkt->senderState); pendingCount--; @@ -117,6 +130,7 @@ DmaPort::recvTiming(PacketPtr pkt) assert(state); state->numBytes += pkt->req->getSize(); + assert(state->totBytes >= state->numBytes); if (state->totBytes == state->numBytes) { state->completionEvent->process(); delete state; @@ -136,7 +150,8 @@ DmaPort::recvTiming(PacketPtr pkt) } DmaDevice::DmaDevice(Params *p) - : PioDevice(p), dmaPort(NULL) + : PioDevice(p), dmaPort(NULL), minBackoffDelay(p->min_backoff_delay), + maxBackoffDelay(p->max_backoff_delay) { } @@ -165,19 +180,31 @@ DmaPort::drain(Event *de) void DmaPort::recvRetry() { + assert(transmitList.size()); PacketPtr pkt = transmitList.front(); bool result = true; - while (result && transmitList.size()) { + do { DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n", pkt, pkt->senderState); result = sendTiming(pkt); if (result) { DPRINTF(DMA, "-- Done\n"); transmitList.pop_front(); + inRetry = false; } else { + inRetry = true; DPRINTF(DMA, "-- Failed, queued\n"); } + } while (!backoffTime && result && transmitList.size()); + + if (transmitList.size() && backoffTime && !inRetry) { + DPRINTF(DMA, "Scheduling backoff for %d\n", curTick+backoffTime); + if (!backoffEvent.scheduled()) + backoffEvent.schedule(backoffTime+curTick); } + DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", + transmitList.size(), backoffTime, inRetry, + backoffEvent.scheduled()); } @@ -191,6 +218,9 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, DmaReqState *reqState = new DmaReqState(event, this, size); + + DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, + event->scheduled()); for (ChunkGenerator gen(addr, size, peerBlockSize()); !gen.done(); gen.next()) { Request *req = new Request(gen.addr(), gen.size(), 0); @@ -204,41 +234,80 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, assert(pendingCount >= 0); pendingCount++; - sendDma(pkt); + DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), + gen.size()); + queueDma(pkt); } } +void +DmaPort::queueDma(PacketPtr pkt, bool front) +{ + + if (front) + transmitList.push_front(pkt); + else + transmitList.push_back(pkt); + sendDma(); +} + void -DmaPort::sendDma(PacketPtr pkt, bool front) +DmaPort::sendDma() { // some kind of selction between access methods // more work is going to have to be done to make // switching actually work + assert(transmitList.size()); + PacketPtr pkt = transmitList.front(); System::MemoryMode state = sys->getMemoryMode(); if (state == System::Timing) { + if (backoffEvent.scheduled() || inRetry) { + DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); + return; + } + DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", pkt, pkt->getAddr()); - if (transmitList.size() || !sendTiming(pkt)) { - if (front) - transmitList.push_front(pkt); - else - transmitList.push_back(pkt); - DPRINTF(DMA, "-- Failed: queued\n"); - } else { - DPRINTF(DMA, "-- Done\n"); + + bool result; + do { + result = sendTiming(pkt); + if (result) { + transmitList.pop_front(); + DPRINTF(DMA, "-- Done\n"); + } else { + inRetry = true; + DPRINTF(DMA, "-- Failed: queued\n"); + } + } while (result && !backoffTime && transmitList.size()); + + if (transmitList.size() && backoffTime && !inRetry && + !backoffEvent.scheduled()) { + DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", + backoffTime+curTick); + backoffEvent.schedule(backoffTime+curTick); } } else if (state == System::Atomic) { + transmitList.pop_front(); + Tick lat; + DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", + pkt->req->getPaddr(), pkt->req->getSize()); lat = sendAtomic(pkt); assert(pkt->senderState); DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); assert(state); - state->numBytes += pkt->req->getSize(); + + DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", + pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, + state->totBytes, state->completionEvent->scheduled()); + if (state->totBytes == state->numBytes) { + assert(!state->completionEvent->scheduled()); state->completionEvent->schedule(curTick + lat); delete state; delete pkt->req; diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index cd7a5296a..bd150bfe4 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -107,6 +107,14 @@ class DmaPort : public Port * here.*/ Event *drainEvent; + /** time to wait between sending another packet, increases as NACKs are + * recived, decreases as responses are recived. */ + Tick backoffTime; + + /** If the port is currently waiting for a retry before it can send whatever + * it is that it's sending. */ + bool inRetry; + virtual bool recvTiming(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt) { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN } @@ -122,7 +130,11 @@ class DmaPort : public Port AddrRangeList &snoop) { resp.clear(); snoop.clear(); } - void sendDma(PacketPtr pkt, bool front = false); + void queueDma(PacketPtr pkt, bool front = false); + void sendDma(); + + /** event to give us a kick every time we backoff time is reached. */ + EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; public: DmaPort(DmaDevice *dev, System *s); @@ -249,8 +261,17 @@ class BasicPioDevice : public PioDevice class DmaDevice : public PioDevice { - protected: + public: + struct Params : public PioDevice::Params + { + Tick min_backoff_delay; + Tick max_backoff_delay; + }; + + protected: DmaPort *dmaPort; + Tick minBackoffDelay; + Tick maxBackoffDelay; public: DmaDevice(Params *p); diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc index 86f56b62e..d9985f808 100644 --- a/src/dev/ns_gige.cc +++ b/src/dev/ns_gige.cc @@ -2310,10 +2310,7 @@ NSGigE::transferDone() DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); + txEvent.reschedule(curTick + cycles(1), true); } bool @@ -2812,6 +2809,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) SimObjectParam<System *> system; SimObjectParam<Platform *> platform; + Param<Tick> min_backoff_delay; + Param<Tick> max_backoff_delay; SimObjectParam<PciConfigData *> configdata; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; @@ -2846,6 +2845,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) INIT_PARAM(system, "System pointer"), INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), + INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), INIT_PARAM(configdata, "PCI Config data"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), @@ -2884,6 +2885,8 @@ CREATE_SIM_OBJECT(NSGigE) params->name = getInstanceName(); params->platform = platform; params->system = system; + params->min_backoff_delay = min_backoff_delay; + params->max_backoff_delay = max_backoff_delay; params->configData = configdata; params->busNum = pci_bus; params->deviceNum = pci_dev; diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh index 56e3ffb4a..5044e2932 100644 --- a/src/dev/pcidev.hh +++ b/src/dev/pcidev.hh @@ -105,7 +105,7 @@ class PciDev : public DmaDevice }; public: - struct Params : public PioDevice::Params + struct Params : public DmaDevice::Params { /** * A pointer to the object that contains the first 64 bytes of diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc index f61c161aa..420761620 100644 --- a/src/dev/sinic.cc +++ b/src/dev/sinic.cc @@ -1199,10 +1199,7 @@ Device::transferDone() DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); + txEvent.reschedule(curTick + cycles(1), true); } bool @@ -1635,6 +1632,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS_WNS(Sinic, SinicDevice) SimObjectParam<System *> system; SimObjectParam<Platform *> platform; + Param<Tick> min_backoff_delay; + Param<Tick> max_backoff_delay; SimObjectParam<PciConfigData *> configdata; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; @@ -1678,6 +1677,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS_WNS(Sinic, SinicDevice) INIT_PARAM(system, "System pointer"), INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), + INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), INIT_PARAM(configdata, "PCI Config data"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), @@ -1723,6 +1724,8 @@ CREATE_SIM_OBJECT_WNS(Sinic, SinicDevice) params->name = getInstanceName(); params->platform = platform; params->system = system; + params->min_backoff_delay = min_backoff_delay; + params->max_backoff_delay = max_backoff_delay; params->configData = configdata; params->busNum = pci_bus; params->deviceNum = pci_dev; diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc index ddee33695..50307aad4 100644 --- a/src/dev/uart8250.cc +++ b/src/dev/uart8250.cc @@ -68,6 +68,7 @@ Uart8250::IntrEvent::process() DPRINTF(Uart, "UART InterEvent, interrupting\n"); uart->platform->postConsoleInt(); uart->status |= intrBit; + uart->lastTxInt = curTick; } else DPRINTF(Uart, "UART InterEvent, not interrupting\n"); @@ -100,14 +101,11 @@ Uart8250::IntrEvent::scheduleIntr() Uart8250::Uart8250(Params *p) - : Uart(p), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) + : Uart(p), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0), + txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) { pioSize = 8; - IER = 0; - DLAB = 0; - LCR = 0; - MCR = 0; } Tick @@ -153,13 +151,13 @@ Uart8250::read(PacketPtr pkt) if (status & RX_INT) /* Rx data interrupt has a higher priority */ pkt->set(IIR_RXID); - else if (status & TX_INT) + else if (status & TX_INT) { pkt->set(IIR_TXID); - else + //Tx interrupts are cleared on IIR reads + status &= ~TX_INT; + } else pkt->set(IIR_NOPEND); - //Tx interrupts are cleared on IIR reads - status &= ~TX_INT; break; case 0x3: // Line Control Register (LCR) pkt->set(LCR); @@ -222,7 +220,16 @@ Uart8250::write(PacketPtr pkt) if (UART_IER_THRI & IER) { DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); - txIntrEvent.scheduleIntr(); + if (curTick - lastTxInt > + (Tick)((Clock::Float::s / 2e9) * 450)) { + DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n", + curTick, lastTxInt); + txIntrEvent.process(); + } else { + DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n", + curTick, lastTxInt); + txIntrEvent.scheduleIntr(); + } } else { diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh index c28200592..c9c878aed 100644 --- a/src/dev/uart8250.hh +++ b/src/dev/uart8250.hh @@ -74,6 +74,7 @@ class Uart8250 : public Uart protected: uint8_t IER, DLAB, LCR, MCR; + Tick lastTxInt; class IntrEvent : public Event { diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc index ba52e040a..42fa63a27 100644 --- a/src/kern/linux/events.cc +++ b/src/kern/linux/events.cc @@ -37,6 +37,7 @@ #include "kern/system_events.hh" #include "sim/system.hh" +#include <sstream> namespace Linux { @@ -44,15 +45,13 @@ void DebugPrintkEvent::process(ThreadContext *tc) { if (DTRACE(DebugPrintf)) { - if (!raw) { - StringWrap name(tc->getSystemPtr()->name() + ".dprintk"); - DPRINTFN(""); - } - + std::stringstream ss; TheISA::Arguments args(tc); - Printk(args); - SkipFuncEvent::process(tc); + Printk(ss, args); + StringWrap name(tc->getSystemPtr()->name() + ".dprintk"); + DPRINTFN("%s", ss.str()); } + SkipFuncEvent::process(tc); } } // namespace linux diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh index b0510c18f..e36a72dde 100644 --- a/src/kern/linux/events.hh +++ b/src/kern/linux/events.hh @@ -38,13 +38,9 @@ namespace Linux { class DebugPrintkEvent : public SkipFuncEvent { - private: - bool raw; - public: - DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool r = false) - : SkipFuncEvent(q, desc, addr), raw(r) {} + DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : SkipFuncEvent(q, desc, addr) {} virtual void process(ThreadContext *xc); }; diff --git a/src/kern/linux/printk.cc b/src/kern/linux/printk.cc index 0e9fd6620..866353e31 100644 --- a/src/kern/linux/printk.cc +++ b/src/kern/linux/printk.cc @@ -32,22 +32,18 @@ #include <sys/types.h> #include <algorithm> -#include "base/trace.hh" #include "arch/arguments.hh" +#include "base/trace.hh" +#include "kern/linux/printk.hh" using namespace std; void -Printk(TheISA::Arguments args) +Printk(stringstream &out, TheISA::Arguments args) { - std::ostream &out = Trace::output(); char *p = (char *)args++; - ios::fmtflags saved_flags = out.flags(); - char old_fill = out.fill(); - int old_precision = out.precision(); - while (*p) { switch (*p) { case '%': { @@ -258,8 +254,5 @@ Printk(TheISA::Arguments args) } } - out.flags(saved_flags); - out.fill(old_fill); - out.precision(old_precision); } diff --git a/src/kern/linux/printk.hh b/src/kern/linux/printk.hh index 17d59b765..20dfb430f 100644 --- a/src/kern/linux/printk.hh +++ b/src/kern/linux/printk.hh @@ -34,8 +34,10 @@ #include "arch/isa_specific.hh" +#include <sstream> + class TheISA::Arguments; -void Printk(TheISA::Arguments args); +void Printk(std::stringstream &out, TheISA::Arguments args); #endif // __PRINTK_HH__ diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh index b94276035..a7703be7c 100644 --- a/src/kern/tru64/tru64.hh +++ b/src/kern/tru64/tru64.hh @@ -792,7 +792,7 @@ class Tru64 : public OperatingSystem for (int i = 0; i < process->numCpus(); ++i) { ThreadContext *tc = process->threadContexts[i]; - if (tc->status() == ThreadContext::Suspended) { + if (tc->status() == ThreadContext::Unallocated) { // inactive context... grab it init_thread_context(tc, attrp, uniq_val); diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index b787f79ca..9509aea38 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -43,20 +43,25 @@ Bridge::BridgePort::BridgePort(const std::string &_name, Bridge *_bridge, BridgePort *_otherPort, - int _delay, int _queueLimit) + int _delay, int _nack_delay, int _req_limit, + int _resp_limit, bool fix_partial_write) : Port(_name), bridge(_bridge), otherPort(_otherPort), - delay(_delay), outstandingResponses(0), - queueLimit(_queueLimit), sendEvent(this) + delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), + outstandingResponses(0), queuedRequests(0), inRetry(false), + reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) { } -Bridge::Bridge(const std::string &n, int qsa, int qsb, - Tick _delay, int write_ack) - : MemObject(n), - portA(n + "-portA", this, &portB, _delay, qsa), - portB(n + "-portB", this, &portA, _delay, qsa), - ackWrites(write_ack) +Bridge::Bridge(Params *p) + : MemObject(p->name), + portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, + p->req_size_a, p->resp_size_a, p->fix_partial_write_a), + portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, + p->req_size_b, p->resp_size_b, p->fix_partial_write_b), + ackWrites(p->write_ack), _params(p) { + if (ackWrites) + panic("No support for acknowledging writes\n"); } Port * @@ -82,35 +87,118 @@ Bridge::init() { // Make sure that both sides are connected to. if (portA.getPeer() == NULL || portB.getPeer() == NULL) - panic("Both ports of bus bridge are not connected to a bus.\n"); + fatal("Both ports of bus bridge are not connected to a bus.\n"); + + if (portA.peerBlockSize() != portB.peerBlockSize()) + fatal("Busses don't have the same block size... Not supported.\n"); +} + +bool +Bridge::BridgePort::respQueueFull() +{ + assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); + return outstandingResponses >= respQueueLimit; } +bool +Bridge::BridgePort::reqQueueFull() +{ + assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); + return queuedRequests >= reqQueueLimit; +} /** Function called by the port when the bus is receiving a Timing * transaction.*/ bool Bridge::BridgePort::recvTiming(PacketPtr pkt) { - if (pkt->flags & SNOOP_COMMIT) { - DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + if (!(pkt->flags & SNOOP_COMMIT)) + return true; + + + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", pkt->getSrc(), pkt->getDest(), pkt->getAddr()); - return otherPort->queueForSendTiming(pkt); + DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", + sendQueue.size(), queuedRequests, outstandingResponses); + DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n", + otherPort->sendQueue.size(), otherPort->queuedRequests, + otherPort->outstandingResponses); + + if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result != + Packet::Nacked) { + DPRINTF(BusBridge, "Remote queue full, nacking\n"); + nackRequest(pkt); + return true; } - else { - // Else it's just a snoop, properly return if we are blocking - return !queueFull(); + + if (pkt->needsResponse() && pkt->result != Packet::Nacked) + if (respQueueFull()) { + DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); + DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", + sendQueue.size(), queuedRequests, outstandingResponses); + nackRequest(pkt); + return true; + } else { + DPRINTF(BusBridge, "Request Needs response, reserving space\n"); + ++outstandingResponses; + } + + otherPort->queueForSendTiming(pkt); + + return true; +} + +void +Bridge::BridgePort::nackRequest(PacketPtr pkt) +{ + // Nack the packet + pkt->result = Packet::Nacked; + pkt->setDest(pkt->getSrc()); + + //put it on the list to send + Tick readyTime = curTick + nackDelay; + PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); + + // nothing on the list, add it and we're done + if (sendQueue.empty()) { + assert(!sendEvent.scheduled()); + sendEvent.schedule(readyTime); + sendQueue.push_back(buf); + return; + } + + assert(sendEvent.scheduled() || inRetry); + + // does it go at the end? + if (readyTime >= sendQueue.back()->ready) { + sendQueue.push_back(buf); + return; + } + + // ok, somewhere in the middle, fun + std::list<PacketBuffer*>::iterator i = sendQueue.begin(); + std::list<PacketBuffer*>::iterator end = sendQueue.end(); + std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); + bool done = false; + + while (i != end && !done) { + if (readyTime < (*i)->ready) { + if (i == begin) + sendEvent.reschedule(readyTime); + sendQueue.insert(i,buf); + done = true; + } + i++; } + assert(done); } -bool +void Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) { - if (queueFull()) - return false; - - if (pkt->isResponse()) { + if (pkt->isResponse() || pkt->result == Packet::Nacked) { // This is a response for a request we forwarded earlier. The // corresponding PacketBuffer should be stored in the packet's // senderState field. @@ -119,12 +207,26 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) // set up new packet dest & senderState based on values saved // from original request buf->fixResponse(pkt); + + // Check if this packet was expecting a response and it's a nacked + // packet, in which case we will never being seeing it + if (buf->expectResponse && pkt->result == Packet::Nacked) + --outstandingResponses; + + DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", pkt->senderState, buf); DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); delete buf; } + + if (pkt->isRequest() && pkt->result != Packet::Nacked) { + ++queuedRequests; + } + + + Tick readyTime = curTick + delay; PacketBuffer *buf = new PacketBuffer(pkt, readyTime); DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", @@ -137,10 +239,7 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) if (sendQueue.empty()) { sendEvent.schedule(readyTime); } - sendQueue.push_back(buf); - - return true; } void @@ -148,28 +247,38 @@ Bridge::BridgePort::trySend() { assert(!sendQueue.empty()); - bool was_full = queueFull(); - PacketBuffer *buf = sendQueue.front(); assert(buf->ready <= curTick); PacketPtr pkt = buf->pkt; + pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set + + // Ugly! @todo When multilevel coherence works this will be removed + if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && + pkt->result != Packet::Nacked) { + PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq, + Packet::Broadcast); + funcPkt->dataStatic(pkt->getPtr<uint8_t>()); + sendFunctional(funcPkt); + pkt->cmd = MemCmd::WriteReq; + delete funcPkt; + } + DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", buf->origSrc, pkt->getDest(), pkt->getAddr()); - pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set + bool wasReq = pkt->isRequest(); + bool wasNacked = pkt->result == Packet::Nacked; + if (sendTiming(pkt)) { // send successful sendQueue.pop_front(); buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it if (buf->expectResponse) { - // Must wait for response. We just need to count outstanding - // responses (in case we want to cap them); PacketBuffer - // pointer will be recovered on response. - ++outstandingResponses; + // Must wait for response DPRINTF(BusBridge, " successful: awaiting response (%d)\n", outstandingResponses); } else { @@ -178,27 +287,37 @@ Bridge::BridgePort::trySend() delete buf; } + if (!wasNacked) { + if (wasReq) + --queuedRequests; + else + --outstandingResponses; + } + // If there are more packets to send, schedule event to try again. if (!sendQueue.empty()) { buf = sendQueue.front(); + DPRINTF(BusBridge, "Scheduling next send\n"); sendEvent.schedule(std::max(buf->ready, curTick + 1)); } - // Let things start sending again - if (was_full) { - DPRINTF(BusBridge, "Queue was full, sending retry\n"); - otherPort->sendRetry(); - } - } else { DPRINTF(BusBridge, " unsuccessful\n"); + inRetry = true; } + DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", + sendQueue.size(), queuedRequests, outstandingResponses); } void Bridge::BridgePort::recvRetry() { - trySend(); + inRetry = false; + Tick nextReady = sendQueue.front()->ready; + if (nextReady <= curTick) + trySend(); + else + sendEvent.schedule(nextReady); } /** Function called by the port when the bus is receiving a Atomic @@ -206,7 +325,18 @@ Bridge::BridgePort::recvRetry() Tick Bridge::BridgePort::recvAtomic(PacketPtr pkt) { - return otherPort->sendAtomic(pkt) + delay; + // fix partial atomic writes... similar to the timing code that does the + // same... will be removed once our code gets this right + if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) { + + PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq, + Packet::Broadcast); + funcPkt->dataStatic(pkt->getPtr<uint8_t>()); + otherPort->sendFunctional(funcPkt); + delete funcPkt; + pkt->cmd = MemCmd::WriteReq; + } + return delay + otherPort->sendAtomic(pkt); } /** Function called by the port when the bus is receiving a Functional @@ -244,26 +374,48 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) - Param<int> queue_size_a; - Param<int> queue_size_b; + Param<int> req_size_a; + Param<int> req_size_b; + Param<int> resp_size_a; + Param<int> resp_size_b; Param<Tick> delay; + Param<Tick> nack_delay; Param<bool> write_ack; + Param<bool> fix_partial_write_a; + Param<bool> fix_partial_write_b; END_DECLARE_SIM_OBJECT_PARAMS(Bridge) BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) - INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), - INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), + INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"), + INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"), + INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"), + INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"), INIT_PARAM(delay, "The miminum delay to cross this bridge"), - INIT_PARAM(write_ack, "Acknowledge any writes that are received.") + INIT_PARAM(nack_delay, "The minimum delay to nack a packet"), + INIT_PARAM(write_ack, "Acknowledge any writes that are received."), + INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), + INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") END_INIT_SIM_OBJECT_PARAMS(Bridge) CREATE_SIM_OBJECT(Bridge) { - return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, - write_ack); + Bridge::Params *p = new Bridge::Params; + p->name = getInstanceName(); + p->req_size_a = req_size_a; + p->req_size_b = req_size_b; + p->resp_size_a = resp_size_a; + p->resp_size_b = resp_size_b; + p->delay = delay; + p->nack_delay = nack_delay; + p->write_ack = write_ack; + p->fix_partial_write_a = fix_partial_write_a; + p->fix_partial_write_b = fix_partial_write_b; + return new Bridge(p); } REGISTER_SIM_OBJECT("Bridge", Bridge) + + diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index f7d0d12d0..a47fe3c1e 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -66,6 +66,11 @@ class Bridge : public MemObject /** Minimum delay though this bridge. */ Tick delay; + /** Min delay to respond to a nack. */ + Tick nackDelay; + + bool fixPartialWrite; + class PacketBuffer : public Packet::SenderState { public: @@ -75,12 +80,13 @@ class Bridge : public MemObject short origSrc; bool expectResponse; - PacketBuffer(PacketPtr _pkt, Tick t) + PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false) : ready(t), pkt(_pkt), origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), - expectResponse(_pkt->needsResponse()) + expectResponse(_pkt->needsResponse() && !nack) + { - if (!pkt->isResponse()) + if (!pkt->isResponse() && !nack && pkt->result != Packet::Nacked) pkt->senderState = this; } @@ -100,19 +106,29 @@ class Bridge : public MemObject std::list<PacketBuffer*> sendQueue; int outstandingResponses; + int queuedRequests; + + /** If we're waiting for a retry to happen.*/ + bool inRetry; /** Max queue size for outbound packets */ - int queueLimit; + int reqQueueLimit; + + /** Max queue size for reserved responses. */ + int respQueueLimit; /** * Is this side blocked from accepting outbound packets? */ - bool queueFull() { return (sendQueue.size() == queueLimit); } + bool respQueueFull(); + bool reqQueueFull(); - bool queueForSendTiming(PacketPtr pkt); + void queueForSendTiming(PacketPtr pkt); void finishSend(PacketBuffer *buf); + void nackRequest(PacketPtr pkt); + /** * Handle send event, scheduled when the packet at the head of * the outbound queue is ready to transmit (for timing @@ -136,11 +152,10 @@ class Bridge : public MemObject SendEvent sendEvent; public: - /** Constructor for the BusPort.*/ - BridgePort(const std::string &_name, - Bridge *_bridge, BridgePort *_otherPort, - int _delay, int _queueLimit); + BridgePort(const std::string &_name, Bridge *_bridge, + BridgePort *_otherPort, int _delay, int _nack_delay, + int _req_limit, int _resp_limit, bool fix_partial_write); protected: @@ -176,13 +191,32 @@ class Bridge : public MemObject bool ackWrites; public: + struct Params + { + std::string name; + int req_size_a; + int req_size_b; + int resp_size_a; + int resp_size_b; + Tick delay; + Tick nack_delay; + bool write_ack; + bool fix_partial_write_a; + bool fix_partial_write_b; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } /** A function used to return the port associated with this bus object. */ virtual Port *getPort(const std::string &if_name, int idx = -1); virtual void init(); - Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); + Bridge(Params *p); }; #endif //__MEM_BUS_HH__ diff --git a/src/mem/bus.cc b/src/mem/bus.cc index b0636ecc2..95d4e2873 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -48,6 +48,7 @@ Bus::getPort(const std::string &if_name, int idx) if (defaultPort == NULL) { defaultPort = new BusPort(csprintf("%s-default",name()), this, defaultId); + cachedBlockSizeValid = false; return defaultPort; } else fatal("Default port already set\n"); @@ -68,6 +69,7 @@ Bus::getPort(const std::string &if_name, int idx) assert(maxId < std::numeric_limits<typeof(maxId)>::max()); BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); interfaces[id] = bp; + cachedBlockSizeValid = false; return bp; } @@ -169,8 +171,9 @@ bool Bus::recvTiming(PacketPtr pkt) { Port *port; - DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", - pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s result %d\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString(), + pkt->result); BusPort *pktPort; if (pkt->getSrc() == defaultId) @@ -182,6 +185,7 @@ Bus::recvTiming(PacketPtr pkt) if (tickNextIdle > curTick || (retryList.size() && (!inRetry || pktPort != retryList.front()))) { addToRetryList(pktPort); + DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n"); return false; } @@ -207,11 +211,12 @@ Bus::recvTiming(PacketPtr pkt) inRetry = false; } occupyBus(pkt); + DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n"); return true; } } else { //Snoop didn't succeed - DPRINTF(Bus, "Adding a retry to RETRY list %d\n", + DPRINTF(Bus, "Adding1 a retry to RETRY list %d\n", pktPort->getId()); addToRetryList(pktPort); return false; @@ -239,13 +244,14 @@ Bus::recvTiming(PacketPtr pkt) } // Packet not successfully sent. Leave or put it on the retry list. - DPRINTF(Bus, "Adding a retry to RETRY list %d\n", + DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", pktPort->getId()); addToRetryList(pktPort); return false; } else { //Forwarding up from responder, just return true; + DPRINTF(Bus, "recvTiming: can we be here?\n"); return true; } } @@ -253,12 +259,12 @@ Bus::recvTiming(PacketPtr pkt) void Bus::recvRetry(int id) { - DPRINTF(Bus, "Received a retry\n"); + DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name()); // If there's anything waiting, and the bus isn't busy... if (retryList.size() && curTick >= tickNextIdle) { //retryingPort = retryList.front(); inRetry = true; - DPRINTF(Bus, "Sending a retry\n"); + DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); retryList.front()->sendRetry(); // If inRetry is still true, sendTiming wasn't called if (inRetry) @@ -274,11 +280,7 @@ Bus::recvRetry(int id) //Burn a cycle for the missed grant. tickNextIdle += clock; - if (!busIdle.scheduled()) { - busIdle.schedule(tickNextIdle); - } else { - busIdle.reschedule(tickNextIdle); - } + busIdle.reschedule(tickNextIdle, true); } } //If we weren't able to drain before, we might be able to now. @@ -598,6 +600,37 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) } } +int +Bus::findBlockSize(int id) +{ + if (cachedBlockSizeValid) + return cachedBlockSize; + + int max_bs = -1, tmp_bs; + range_map<Addr,int>::iterator portIter; + std::vector<DevMap>::iterator snoopIter; + for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) { + tmp_bs = interfaces[portIter->second]->peerBlockSize(); + if (tmp_bs > max_bs) + max_bs = tmp_bs; + } + for (snoopIter = portSnoopList.begin(); + snoopIter != portSnoopList.end(); snoopIter++) { + tmp_bs = interfaces[snoopIter->portId]->peerBlockSize(); + if (tmp_bs > max_bs) + max_bs = tmp_bs; + } + if (max_bs <= 0) + max_bs = defaultBlockSize; + + if (max_bs != 64) + warn_once("Blocksize found to not be 64... hmm... probably not.\n"); + cachedBlockSize = max_bs; + cachedBlockSizeValid = true; + return max_bs; +} + + unsigned int Bus::drain(Event * de) { @@ -618,6 +651,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) Param<int> clock; Param<int> width; Param<bool> responder_set; + Param<int> block_size; END_DECLARE_SIM_OBJECT_PARAMS(Bus) @@ -625,12 +659,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) INIT_PARAM(bus_id, "a globally unique bus id"), INIT_PARAM(clock, "bus clock speed"), INIT_PARAM(width, "width of the bus (bits)"), - INIT_PARAM(responder_set, "Is a default responder set by the user") + INIT_PARAM(responder_set, "Is a default responder set by the user"), + INIT_PARAM(block_size, "Default blocksize if no device has one") END_INIT_SIM_OBJECT_PARAMS(Bus) CREATE_SIM_OBJECT(Bus) { - return new Bus(getInstanceName(), bus_id, clock, width, responder_set); + return new Bus(getInstanceName(), bus_id, clock, width, responder_set, + block_size); } REGISTER_SIM_OBJECT("Bus", Bus) diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 0dd7547c5..f0dc67b12 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -133,6 +133,12 @@ class Bus : public MemObject /** Occupy the bus with transmitting the packet pkt */ void occupyBus(PacketPtr pkt); + /** Ask everyone on the bus what their size is + * @param id id of the busport that made the request + * @return the max of all the sizes + */ + int findBlockSize(int id); + /** Declaration of the buses port type, one will be instantiated for each of the interfaces connecting to the bus. */ class BusPort : public Port @@ -195,8 +201,11 @@ class Bus : public MemObject AddrRangeList &snoop) { bus->addressRanges(resp, snoop, id); } - // Hack to make translating port work without changes - virtual int deviceBlockSize() { return 32; } + // Ask the bus to ask everyone on the bus what their block size is and + // take the max of it. This might need to be changed a bit if we ever + // support multiple block sizes. + virtual int deviceBlockSize() + { return bus->findBlockSize(id); } }; @@ -256,6 +265,10 @@ class Bus : public MemObject /** Has the user specified their own default responder? */ bool responderSet; + int defaultBlockSize; + int cachedBlockSize; + bool cachedBlockSizeValid; + public: /** A function used to return the port associated with this bus object. */ @@ -267,11 +280,12 @@ class Bus : public MemObject unsigned int drain(Event *de); Bus(const std::string &n, int bus_id, int _clock, int _width, - bool responder_set) + bool responder_set, int dflt_blk_size) : MemObject(n), busId(bus_id), clock(_clock), width(_width), tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4), - responderSet(responder_set) + responderSet(responder_set), defaultBlockSize(dflt_blk_size), + cachedBlockSize(0), cachedBlockSizeValid(false) { //Both the width and clock period must be positive if (width <= 0) diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc index ed665dafb..3ed4b84d1 100644 --- a/src/mem/cache/base_cache.cc +++ b/src/mem/cache/base_cache.cc @@ -134,8 +134,7 @@ BaseCache::CachePort::recvRetry() isCpuSide && cache->doSlaveRequest()) { DPRINTF(CachePort, "%s has more responses/requests\n", name()); - BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this, false); - reqCpu->schedule(curTick + 1); + new BaseCache::RequestEvent(this, curTick + 1); } waitingOnRetry = false; } @@ -178,8 +177,7 @@ BaseCache::CachePort::recvRetry() { DPRINTF(CachePort, "%s has more requests\n", name()); //Still more to issue, rerequest in 1 cycle - BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this, false); - reqCpu->schedule(curTick + 1); + new BaseCache::RequestEvent(this, curTick + 1); } } else @@ -196,8 +194,7 @@ BaseCache::CachePort::recvRetry() { DPRINTF(CachePort, "%s has more requests\n", name()); //Still more to issue, rerequest in 1 cycle - BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this, false); - reqCpu->schedule(curTick + 1); + new BaseCache::RequestEvent(this, curTick + 1); } } if (waitingOnRetry) DPRINTF(CachePort, "%s STILL Waiting on retry\n", name()); @@ -228,102 +225,109 @@ BaseCache::CachePort::clearBlocked() } } -BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, bool _newResponse) - : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), - newResponse(_newResponse) +BaseCache::RequestEvent::RequestEvent(CachePort *_cachePort, Tick when) + : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort) { - if (!newResponse) - this->setFlags(AutoDelete); - pkt = NULL; + this->setFlags(AutoDelete); + schedule(when); } void -BaseCache::CacheEvent::process() +BaseCache::RequestEvent::process() { - if (!newResponse) - { - if (cachePort->waitingOnRetry) return; - //We have some responses to drain first - if (!cachePort->drainList.empty()) { - DPRINTF(CachePort, "%s trying to drain a response\n", cachePort->name()); - if (cachePort->sendTiming(cachePort->drainList.front())) { - DPRINTF(CachePort, "%s drains a response succesfully\n", cachePort->name()); - cachePort->drainList.pop_front(); - if (!cachePort->drainList.empty() || - !cachePort->isCpuSide && cachePort->cache->doMasterRequest() || - cachePort->isCpuSide && cachePort->cache->doSlaveRequest()) { - - DPRINTF(CachePort, "%s still has outstanding bus reqs\n", cachePort->name()); - this->schedule(curTick + 1); - } - } - else { - cachePort->waitingOnRetry = true; - DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); + if (cachePort->waitingOnRetry) return; + //We have some responses to drain first + if (!cachePort->drainList.empty()) { + DPRINTF(CachePort, "%s trying to drain a response\n", cachePort->name()); + if (cachePort->sendTiming(cachePort->drainList.front())) { + DPRINTF(CachePort, "%s drains a response succesfully\n", cachePort->name()); + cachePort->drainList.pop_front(); + if (!cachePort->drainList.empty() || + !cachePort->isCpuSide && cachePort->cache->doMasterRequest() || + cachePort->isCpuSide && cachePort->cache->doSlaveRequest()) { + + DPRINTF(CachePort, "%s still has outstanding bus reqs\n", cachePort->name()); + this->schedule(curTick + 1); } } - else if (!cachePort->isCpuSide) - { //MSHR - DPRINTF(CachePort, "%s trying to send a MSHR request\n", cachePort->name()); - if (!cachePort->cache->doMasterRequest()) { - //This can happen if I am the owner of a block and see an upgrade - //while the block was in my WB Buffers. I just remove the - //wb and de-assert the masterRequest - return; - } + else { + cachePort->waitingOnRetry = true; + DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); + } + } + else if (!cachePort->isCpuSide) + { //MSHR + DPRINTF(CachePort, "%s trying to send a MSHR request\n", cachePort->name()); + if (!cachePort->cache->doMasterRequest()) { + //This can happen if I am the owner of a block and see an upgrade + //while the block was in my WB Buffers. I just remove the + //wb and de-assert the masterRequest + return; + } - pkt = cachePort->cache->getPacket(); - MSHR* mshr = (MSHR*) pkt->senderState; - //Copy the packet, it may be modified/destroyed elsewhere - PacketPtr copyPkt = new Packet(*pkt); - copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>()); - mshr->pkt = copyPkt; + PacketPtr pkt = cachePort->cache->getPacket(); + MSHR* mshr = (MSHR*) pkt->senderState; + //Copy the packet, it may be modified/destroyed elsewhere + PacketPtr copyPkt = new Packet(*pkt); + copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>()); + mshr->pkt = copyPkt; - bool success = cachePort->sendTiming(pkt); - DPRINTF(Cache, "Address %x was %s in sending the timing request\n", - pkt->getAddr(), success ? "succesful" : "unsuccesful"); + bool success = cachePort->sendTiming(pkt); + DPRINTF(Cache, "Address %x was %s in sending the timing request\n", + pkt->getAddr(), success ? "succesful" : "unsuccesful"); - cachePort->waitingOnRetry = !success; - if (cachePort->waitingOnRetry) { - DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); - } + cachePort->waitingOnRetry = !success; + if (cachePort->waitingOnRetry) { + DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); + } - cachePort->cache->sendResult(pkt, mshr, success); - if (success && cachePort->cache->doMasterRequest()) - { - DPRINTF(CachePort, "%s still more MSHR requests to send\n", - cachePort->name()); - //Still more to issue, rerequest in 1 cycle - pkt = NULL; - this->schedule(curTick+1); - } + cachePort->cache->sendResult(pkt, mshr, success); + if (success && cachePort->cache->doMasterRequest()) + { + DPRINTF(CachePort, "%s still more MSHR requests to send\n", + cachePort->name()); + //Still more to issue, rerequest in 1 cycle + this->schedule(curTick+1); } - else + } + else + { + //CSHR + assert(cachePort->cache->doSlaveRequest()); + PacketPtr pkt = cachePort->cache->getCoherencePacket(); + MSHR* cshr = (MSHR*) pkt->senderState; + bool success = cachePort->sendTiming(pkt); + cachePort->cache->sendCoherenceResult(pkt, cshr, success); + cachePort->waitingOnRetry = !success; + if (cachePort->waitingOnRetry) + DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); + if (success && cachePort->cache->doSlaveRequest()) { - //CSHR - assert(cachePort->cache->doSlaveRequest()); - pkt = cachePort->cache->getCoherencePacket(); - MSHR* cshr = (MSHR*) pkt->senderState; - bool success = cachePort->sendTiming(pkt); - cachePort->cache->sendCoherenceResult(pkt, cshr, success); - cachePort->waitingOnRetry = !success; - if (cachePort->waitingOnRetry) - DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name()); - if (success && cachePort->cache->doSlaveRequest()) - { - DPRINTF(CachePort, "%s still more CSHR requests to send\n", - cachePort->name()); - //Still more to issue, rerequest in 1 cycle - pkt = NULL; - this->schedule(curTick+1); - } + DPRINTF(CachePort, "%s still more CSHR requests to send\n", + cachePort->name()); + //Still more to issue, rerequest in 1 cycle + this->schedule(curTick+1); } - return; } - //Else it's a response +} + +const char * +BaseCache::RequestEvent::description() +{ + return "Cache request event"; +} + +BaseCache::ResponseEvent::ResponseEvent(CachePort *_cachePort) + : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort) +{ +} + +void +BaseCache::ResponseEvent::process() +{ assert(cachePort->transmitList.size()); assert(cachePort->transmitList.front().first <= curTick); - pkt = cachePort->transmitList.front().second; + PacketPtr pkt = cachePort->transmitList.front().second; cachePort->transmitList.pop_front(); if (!cachePort->transmitList.empty()) { Tick time = cachePort->transmitList.front().first; @@ -354,9 +358,9 @@ BaseCache::CacheEvent::process() } const char * -BaseCache::CacheEvent::description() +BaseCache::ResponseEvent::description() { - return "BaseCache timing event"; + return "Cache response event"; } void diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh index ee871c1c4..e45e36fa0 100644 --- a/src/mem/cache/base_cache.hh +++ b/src/mem/cache/base_cache.hh @@ -117,13 +117,20 @@ class BaseCache : public MemObject std::list<std::pair<Tick,PacketPtr> > transmitList; }; - struct CacheEvent : public Event + struct RequestEvent : public Event { CachePort *cachePort; - PacketPtr pkt; - bool newResponse; - CacheEvent(CachePort *_cachePort, bool response); + RequestEvent(CachePort *_cachePort, Tick when); + void process(); + const char *description(); + }; + + struct ResponseEvent : public Event + { + CachePort *cachePort; + + ResponseEvent(CachePort *_cachePort); void process(); const char *description(); }; @@ -132,8 +139,8 @@ class BaseCache : public MemObject CachePort *cpuSidePort; CachePort *memSidePort; - CacheEvent *sendEvent; - CacheEvent *memSendEvent; + ResponseEvent *sendEvent; + ResponseEvent *memSendEvent; private: void recvStatusChange(Port::Status status, bool isCpuSide) @@ -432,9 +439,7 @@ class BaseCache : public MemObject { if (!doMasterRequest() && !memSidePort->waitingOnRetry) { - BaseCache::CacheEvent * reqCpu = - new BaseCache::CacheEvent(memSidePort, false); - reqCpu->schedule(time); + new RequestEvent(memSidePort, time); } uint8_t flag = 1<<cause; masterRequests |= flag; @@ -469,9 +474,7 @@ class BaseCache : public MemObject { if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry) { - BaseCache::CacheEvent * reqCpu = - new BaseCache::CacheEvent(cpuSidePort, false); - reqCpu->schedule(time); + new RequestEvent(cpuSidePort, time); } uint8_t flag = 1<<cause; slaveRequests |= flag; diff --git a/src/mem/cache/cache_builder.cc b/src/mem/cache/cache_builder.cc index 318b57d50..e887f711e 100644 --- a/src/mem/cache/cache_builder.cc +++ b/src/mem/cache/cache_builder.cc @@ -134,7 +134,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(BaseCache) Param<bool> prefetch_cache_check_push; Param<bool> prefetch_use_cpu_id; Param<bool> prefetch_data_accesses_only; - Param<int> hit_latency; END_DECLARE_SIM_OBJECT_PARAMS(BaseCache) @@ -190,8 +189,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(BaseCache) INIT_PARAM_DFLT(prefetch_policy, "Type of prefetcher to use", "none"), INIT_PARAM_DFLT(prefetch_cache_check_push, "Check if in cash on push or pop of prefetch queue", true), INIT_PARAM_DFLT(prefetch_use_cpu_id, "Use the CPU ID to seperate calculations of prefetches", true), - INIT_PARAM_DFLT(prefetch_data_accesses_only, "Only prefetch on data not on instruction accesses", false), - INIT_PARAM_DFLT(hit_latency, "Hit Latecny for a succesful access", 1) + INIT_PARAM_DFLT(prefetch_data_accesses_only, "Only prefetch on data not on instruction accesses", false) END_INIT_SIM_OBJECT_PARAMS(BaseCache) @@ -211,7 +209,7 @@ END_INIT_SIM_OBJECT_PARAMS(BaseCache) BUILD_NULL_PREFETCHER(TAGS); \ } \ Cache<TAGS, c>::Params params(tags, mq, coh, base_params, \ - pf, prefetch_access, hit_latency, \ + pf, prefetch_access, latency, \ true, \ store_compressed, \ adaptive_compression, \ diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 0a528aa5d..9b094c1e3 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -1146,11 +1146,11 @@ template<class TagStore, class Coherence> Port * Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx) { - if (if_name == "") + if (if_name == "" || if_name == "cpu_side") { if (cpuSidePort == NULL) { cpuSidePort = new CpuSidePort(name() + "-cpu_side_port", this); - sendEvent = new CacheEvent(cpuSidePort, true); + sendEvent = new ResponseEvent(cpuSidePort); } return cpuSidePort; } @@ -1158,20 +1158,12 @@ Cache<TagStore,Coherence>::getPort(const std::string &if_name, int idx) { return new CpuSidePort(name() + "-cpu_side_funcport", this); } - else if (if_name == "cpu_side") - { - if (cpuSidePort == NULL) { - cpuSidePort = new CpuSidePort(name() + "-cpu_side_port", this); - sendEvent = new CacheEvent(cpuSidePort, true); - } - return cpuSidePort; - } else if (if_name == "mem_side") { if (memSidePort != NULL) panic("Already have a mem side for this cache\n"); memSidePort = new MemSidePort(name() + "-mem_side_port", this); - memSendEvent = new CacheEvent(memSidePort, true); + memSendEvent = new ResponseEvent(memSidePort); return memSidePort; } else panic("Port name %s unrecognized\n", if_name); @@ -1192,6 +1184,8 @@ template<class TagStore, class Coherence> bool Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt) { + assert(pkt->result != Packet::Nacked); + if (!pkt->req->isUncacheable() && pkt->isInvalidate() && !pkt->isRead() && !pkt->isWrite()) { @@ -1249,6 +1243,12 @@ template<class TagStore, class Coherence> bool Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt) { + // this needs to be fixed so that the cache updates the mshr and sends the + // packet back out on the link, but it probably won't happen so until this + // gets fixed, just panic when it does + if (pkt->result == Packet::Nacked) + panic("Need to implement cache resending nacked packets!\n"); + if (pkt->isRequest() && blocked) { DPRINTF(Cache,"Scheduling a retry while blocked\n"); @@ -1282,9 +1282,9 @@ template<class TagStore, class Coherence> void Cache<TagStore,Coherence>::MemSidePort::recvFunctional(PacketPtr pkt) { - if (checkFunctional(pkt)) { - myCache()->probe(pkt, false, cache->cpuSidePort); - } + myCache()->probe(pkt, false, cache->cpuSidePort); + if (pkt->result != Packet::Success) + checkFunctional(pkt); } diff --git a/src/mem/packet.cc b/src/mem/packet.cc index 14d08db1b..2463a19ba 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -85,7 +85,7 @@ MemCmd::commandInfo[] = { SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse), WriteInvalidateResp, "WriteInvalidateReq" }, /* WriteInvalidateResp */ - { SET5(IsWrite, IsInvalidate, IsRequest, NeedsResponse, IsResponse), + { SET3(IsWrite, IsInvalidate, IsResponse), InvalidCmd, "WriteInvalidateResp" }, /* UpgradeReq */ { SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" }, diff --git a/src/mem/port.hh b/src/mem/port.hh index 6296b42ca..877e00293 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -161,10 +161,10 @@ class Port /** Called by a peer port in order to determine the block size of the device connected to this port. It sometimes doesn't make sense for - this function to be called, a DMA interface doesn't really have a - block size, so it is defaulted to a panic. + this function to be called, so it just returns 0. Anytthing that is + concerned with the size should just ignore that. */ - virtual int deviceBlockSize() { panic("??"); M5_DUMMY_RETURN } + virtual int deviceBlockSize() { return 0; } /** The peer port is requesting us to reply with a list of the ranges we are responsible for. diff --git a/src/mem/tport.cc b/src/mem/tport.cc index b384a0444..9a4bd7967 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -128,6 +128,7 @@ SimpleTimingPort::sendTiming(PacketPtr pkt, Tick time) } i++; } + assert(done); } void diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc index d2c854086..54de6625e 100644 --- a/src/mem/translating_port.cc +++ b/src/mem/translating_port.cc @@ -34,12 +34,14 @@ #include "mem/port.hh" #include "mem/translating_port.hh" #include "mem/page_table.hh" +#include "sim/process.hh" using namespace TheISA; TranslatingPort::TranslatingPort(const std::string &_name, - PageTable *p_table, bool alloc) - : FunctionalPort(_name), pTable(p_table), allocating(alloc) + Process *p, AllocType alloc) + : FunctionalPort(_name), pTable(p->pTable), process(p), + allocating(alloc) { } TranslatingPort::~TranslatingPort() @@ -81,13 +83,18 @@ TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size) for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { if (!pTable->translate(gen.addr(), paddr)) { - if (allocating) { + if (allocating == Always) { pTable->allocate(roundDown(gen.addr(), VMPageSize), VMPageSize); - pTable->translate(gen.addr(), paddr); + } else if (allocating == NextPage) { + // check if we've accessed the next page on the stack + if (!process->checkAndAllocNextPage(gen.addr())) + panic("Page table fault when accessing virtual address %#x " + "during functional write\n", gen.addr()); } else { return false; } + pTable->translate(gen.addr(), paddr); } Port::writeBlob(paddr, p + prevSize, gen.size()); @@ -113,7 +120,7 @@ TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size) for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { if (!pTable->translate(gen.addr(), paddr)) { - if (allocating) { + if (allocating == Always) { pTable->allocate(roundDown(gen.addr(), VMPageSize), VMPageSize); pTable->translate(gen.addr(), paddr); diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh index 7354278ba..76c7947be 100644 --- a/src/mem/translating_port.hh +++ b/src/mem/translating_port.hh @@ -35,16 +35,25 @@ #include "mem/port.hh" class PageTable; +class Process; class TranslatingPort : public FunctionalPort { + public: + enum AllocType { + Always, + Never, + NextPage + }; + private: PageTable *pTable; - bool allocating; + Process *process; + AllocType allocating; public: TranslatingPort(const std::string &_name, - PageTable *p_table, bool alloc = false); + Process *p, AllocType alloc); virtual ~TranslatingPort(); bool tryReadBlob(Addr addr, uint8_t *p, int size); diff --git a/src/python/SConscript b/src/python/SConscript index 6662c8a45..562278aa0 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -30,129 +30,84 @@ # Nathan Binkert import os -import zipfile - -# handy function for path joins -def join(*args): - return os.path.normpath(os.path.join(*args)) - Import('*') -# This SConscript is in charge of collecting .py files and generating -# a zip archive that is appended to the m5 binary. - -# List of files & directories to include in the zip file. To include -# a package, list only the root directory of the package, not any -# internal .py files (else they will get the path stripped off when -# they are imported into the zip file). -pyzip_files = [] - -# List of additional files on which the zip archive depends, but which -# are not included in pyzip_files... i.e. individual .py files within -# a package. -pyzip_dep_files = [] - -# Add the specified package to the zip archive. Adds the directory to -# pyzip_files and all included .py files to pyzip_dep_files. -def addPkg(pkgdir): - pyzip_files.append(pkgdir) - origdir = os.getcwd() - srcdir = join(Dir('.').srcnode().abspath, pkgdir) - os.chdir(srcdir) - for path, dirs, files in os.walk('.'): - for i,dir in enumerate(dirs): - if dir == 'SCCS': - del dirs[i] - break - - for f in files: - if f.endswith('.py'): - pyzip_dep_files.append(join(pkgdir, path, f)) - - os.chdir(origdir) - -# Generate Python file that contains a dict specifying the current -# build_env flags. -def MakeDefinesPyFile(target, source, env): - f = file(str(target[0]), 'w') - print >>f, "m5_build_env = ", source[0] - f.close() - -optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) -env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile) - -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() - -env.Command('m5/info.py', - [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], - MakeInfoPyFile) - -# Now specify the packages & files for the zip archive. -addPkg('m5') -pyzip_files.append('m5/defines.py') -pyzip_files.append('m5/info.py') -pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py')) -pyzip_files.append(join(env['ROOT'], 'src/base/traceflags.py')) - -swig_modules = [] -def swig_it(module): - env.Command(['swig/%s_wrap.cc' % module, 'm5/internal/%s.py' % module], - 'swig/%s.i' % module, - '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' - '-o ${TARGETS[0]} $SOURCES') - swig_modules.append(module) - Source('swig/%s_wrap.cc' % module) - Source('swig/init.cc') Source('swig/pyevent.cc') Source('swig/pyobject.cc') -swig_it('core') -swig_it('debug') -swig_it('event') -swig_it('random') -swig_it('sim_object') -swig_it('stats') -swig_it('trace') - -# Automatically generate m5/internals/__init__.py -def MakeInternalsInit(target, source, env): - f = file(str(target[0]), 'w') - for m in swig_modules: - print >>f, 'import %s' % m - f.close() - -swig_py_files = [ 'm5/internal/%s.py' % m for m in swig_modules ] -env.Command('m5/internal/__init__.py', swig_py_files, MakeInternalsInit) -pyzip_dep_files.append('m5/internal/__init__.py') - -def MakeSwigInit(target, source, env): - f = file(str(target[0]), 'w') - print >>f, 'extern "C" {' - for m in swig_modules: - print >>f, ' void init_%s();' % m - print >>f, '}' - print >>f, 'void init_swig() {' - for m in swig_modules: - print >>f, ' init_%s();' % m - print >>f, '}' - f.close() - -swig_cc_files = [ 'swig/%s_wrap.cc' % m for m in swig_modules ] -env.Command('swig/init.cc', swig_cc_files, MakeSwigInit) - -# Action function to build the zip archive. Uses the PyZipFile module -# included in the standard Python library. -def buildPyZip(target, source, env): - pzf = zipfile.PyZipFile(str(target[0]), 'w') - for s in source: - pzf.writepy(str(s)) - -# Add the zip file target to the environment. -env.Command('m5py.zip', pyzip_files, buildPyZip) -env.Depends('m5py.zip', pyzip_dep_files) +PySource('m5', 'm5/__init__.py') +PySource('m5', 'm5/SimObject.py') +PySource('m5', 'm5/attrdict.py') +PySource('m5', 'm5/convert.py') +PySource('m5', 'm5/event.py') +PySource('m5', 'm5/main.py') +PySource('m5', 'm5/multidict.py') +PySource('m5', 'm5/params.py') +PySource('m5', 'm5/proxy.py') +PySource('m5', 'm5/smartdict.py') +PySource('m5', 'm5/stats.py') +PySource('m5', 'm5/ticks.py') +PySource('m5', 'm5/util.py') + +PySource('m5', os.path.join(env['ROOT'], 'util/pbs/jobfile.py')) + +SwigSource('m5.internal', 'swig/core.i') +SwigSource('m5.internal', 'swig/debug.i') +SwigSource('m5.internal', 'swig/event.i') +SwigSource('m5.internal', 'swig/random.i') +SwigSource('m5.internal', 'swig/sim_object.i') +SwigSource('m5.internal', 'swig/stats.i') +SwigSource('m5.internal', 'swig/trace.i') +PySource('m5.internal', 'm5/internal/__init__.py') + +SimObject('m5/objects/AlphaConsole.py') +SimObject('m5/objects/AlphaTLB.py') +SimObject('m5/objects/BadDevice.py') +SimObject('m5/objects/BaseCPU.py') +SimObject('m5/objects/BaseCache.py') +SimObject('m5/objects/BaseHier.py') +SimObject('m5/objects/BaseMem.py') +SimObject('m5/objects/BaseMemory.py') +SimObject('m5/objects/BranchPred.py') +SimObject('m5/objects/Bridge.py') +SimObject('m5/objects/Bus.py') +SimObject('m5/objects/Checker.py') +SimObject('m5/objects/CoherenceProtocol.py') +SimObject('m5/objects/DRAMMemory.py') +SimObject('m5/objects/Device.py') +SimObject('m5/objects/DiskImage.py') +SimObject('m5/objects/Ethernet.py') +SimObject('m5/objects/FUPool.py') +SimObject('m5/objects/FastCPU.py') +#SimObject('m5/objects/FreebsdSystem.py') +SimObject('m5/objects/FuncUnit.py') +SimObject('m5/objects/FuncUnitConfig.py') +SimObject('m5/objects/FunctionalMemory.py') +SimObject('m5/objects/HierParams.py') +SimObject('m5/objects/Ide.py') +SimObject('m5/objects/IntrControl.py') +SimObject('m5/objects/LinuxSystem.py') +SimObject('m5/objects/MainMemory.py') +SimObject('m5/objects/MemObject.py') +SimObject('m5/objects/MemTest.py') +SimObject('m5/objects/MemoryController.py') +SimObject('m5/objects/O3CPU.py') +SimObject('m5/objects/OzoneCPU.py') +SimObject('m5/objects/Pci.py') +SimObject('m5/objects/PhysicalMemory.py') +SimObject('m5/objects/Platform.py') +SimObject('m5/objects/Process.py') +SimObject('m5/objects/Repl.py') +SimObject('m5/objects/Root.py') +SimObject('m5/objects/Sampler.py') +SimObject('m5/objects/SimConsole.py') +SimObject('m5/objects/SimpleCPU.py') +SimObject('m5/objects/SimpleDisk.py') +#SimObject('m5/objects/SimpleOzoneCPU.py') +SimObject('m5/objects/SparcTLB.py') +SimObject('m5/objects/System.py') +SimObject('m5/objects/T1000.py') +#SimObject('m5/objects/Tru64System.py') +SimObject('m5/objects/Tsunami.py') +SimObject('m5/objects/Uart.py') diff --git a/src/python/m5/internal/__init__.py b/src/python/m5/internal/__init__.py new file mode 100644 index 000000000..6b7859cd7 --- /dev/null +++ b/src/python/m5/internal/__init__.py @@ -0,0 +1,35 @@ +# 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: Nathan Binkert + +import core +import debug +import event +import random +import sim_object +import stats +import trace diff --git a/src/python/m5/objects/BaseCache.py b/src/python/m5/objects/BaseCache.py index 773a11bea..7df5215e4 100644 --- a/src/python/m5/objects/BaseCache.py +++ b/src/python/m5/objects/BaseCache.py @@ -9,7 +9,7 @@ class BaseCache(MemObject): "Use an adaptive compression scheme") assoc = Param.Int("associativity") block_size = Param.Int("block size in bytes") - latency = Param.Int("Latency") + latency = Param.Latency("Latency") compressed_bus = Param.Bool(False, "This cache connects to a compressed memory") compression_latency = Param.Latency('0ns', @@ -59,6 +59,5 @@ class BaseCache(MemObject): "Use the CPU ID to seperate calculations of prefetches") prefetch_data_accesses_only = Param.Bool(False, "Only prefetch on data not on instruction accesses") - hit_latency = Param.Int(1,"Hit Latency of the cache") cpu_side = Port("Port on side closer to CPU") mem_side = Port("Port on side closer to MEM") diff --git a/src/python/m5/objects/Bridge.py b/src/python/m5/objects/Bridge.py index ee8e76bff..33b24ad3c 100644 --- a/src/python/m5/objects/Bridge.py +++ b/src/python/m5/objects/Bridge.py @@ -5,7 +5,12 @@ class Bridge(MemObject): type = 'Bridge' side_a = Port('Side A port') side_b = Port('Side B port') - queue_size_a = Param.Int(16, "The number of requests to buffer") - queue_size_b = Param.Int(16, "The number of requests to buffer") + req_size_a = Param.Int(16, "The number of requests to buffer") + req_size_b = Param.Int(16, "The number of requests to buffer") + resp_size_a = Param.Int(16, "The number of requests to buffer") + resp_size_b = Param.Int(16, "The number of requests to buffer") delay = Param.Latency('0ns', "The latency of this bridge") + nack_delay = Param.Latency('0ns', "The latency of this bridge") write_ack = Param.Bool(False, "Should this bridge ack writes") + fix_partial_write_a = Param.Bool(False, "Should this bridge fixup partial block writes") + fix_partial_write_b = Param.Bool(False, "Should this bridge fixup partial block writes") diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py index 8226fe8d2..48dbbe307 100644 --- a/src/python/m5/objects/Bus.py +++ b/src/python/m5/objects/Bus.py @@ -11,6 +11,7 @@ class Bus(MemObject): clock = Param.Clock("1GHz", "bus clock speed") width = Param.Int(64, "bus width (bytes)") responder_set = Param.Bool(False, "Did the user specify a default responder.") + block_size = Param.Int(64, "The default block size if one isn't set by a device attached to the bus.") if build_env['FULL_SYSTEM']: responder = BadAddr(pio_addr=0x0, pio_latency="1ps") default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.") diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py index f4b873a60..90fbfb552 100644 --- a/src/python/m5/objects/Device.py +++ b/src/python/m5/objects/Device.py @@ -19,6 +19,12 @@ class DmaDevice(PioDevice): type = 'DmaDevice' abstract = True dma = Port(Self.pio.peerObj.port, "DMA port") + min_backoff_delay = Param.Latency('4ns', + "min time between a nack packet being received and the next request made by the device") + max_backoff_delay = Param.Latency('10us', + "max time between a nack packet being received and the next request made by the device") + + class IsaFake(BasicPioDevice): type = 'IsaFake' diff --git a/src/python/m5/params.py b/src/python/m5/params.py index 9892df97c..88b162874 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -51,6 +51,7 @@ import sys import time import convert +import proxy import ticks from util import * @@ -347,7 +348,7 @@ class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 class Float(ParamValue, float): - pass + cxx_type = 'double' class MemorySize(CheckedInt): cxx_type = 'uint64_t' @@ -477,12 +478,13 @@ def IncEthernetAddr(addr, val = 1): assert(bytes[0] <= 255) return ':'.join(map(lambda x: '%02x' % x, bytes)) -class NextEthernetAddr(object): - addr = "00:90:00:00:00:01" +_NextEthernetAddr = "00:90:00:00:00:01" +def NextEthernetAddr(): + global _NextEthernetAddr - def __init__(self, inc = 1): - self.value = NextEthernetAddr.addr - NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) + value = _NextEthernetAddr + _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) + return value class EthernetAddr(ParamValue): cxx_type = 'Net::EthAddr' @@ -508,17 +510,11 @@ class EthernetAddr(ParamValue): def unproxy(self, base): if self.value == NextEthernetAddr: - self.addr = self.value().value + return EthernetAddr(self.value()) return self - def __str__(self): - if self.value == NextEthernetAddr: - if hasattr(self, 'addr'): - return self.addr - else: - return "NextEthernetAddr (unresolved)" - else: - return self.value + def ini_str(self): + return self.value time_formats = [ "%a %b %d %H:%M:%S %Z %Y", "%a %b %d %H:%M:%S %Z %Y", @@ -1028,6 +1024,5 @@ __all__ = ['Param', 'VectorParam', # see comment on imports at end of __init__.py. from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass -import proxy import objects import internal diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh index a57e9077e..974313968 100644 --- a/src/sim/eventq.hh +++ b/src/sim/eventq.hh @@ -210,7 +210,8 @@ class Event : public Serializable, public FastAlloc void schedule(Tick t); /// Reschedule the event with the current priority - void reschedule(Tick t); + // 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(); @@ -402,16 +403,22 @@ Event::deschedule() } inline void -Event::reschedule(Tick t) +Event::reschedule(Tick t, bool always) { - assert(scheduled()); - clearFlags(Squashed); + assert(scheduled() || always); #if TRACING_ON when_scheduled = curTick; #endif _when = t; - queue->reschedule(this); + + if (scheduled()) { + clearFlags(Squashed); + queue->reschedule(this); + } else { + setFlags(Scheduled); + queue->schedule(this); + } } inline void diff --git a/src/sim/faults.cc b/src/sim/faults.cc index b09bbc177..fe62874d7 100644 --- a/src/sim/faults.cc +++ b/src/sim/faults.cc @@ -61,21 +61,8 @@ void PageTableFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); - // We've accessed the next page of the stack, so extend the stack - // to cover it. - if(vaddr < p->stack_min && vaddr >= p->stack_min - TheISA::PageBytes) - { - p->stack_min -= TheISA::PageBytes; - if(p->stack_base - p->stack_min > 8*1024*1024) - fatal("Over max stack size for one thread\n"); - p->pTable->allocate(p->stack_min, TheISA::PageBytes); - warn("Increasing stack size by one page."); - } - // Otherwise, we have an unexpected page fault. Report that fact, - // and what address was accessed to cause the fault. - else - { + if (!p->checkAndAllocNextPage(vaddr)) panic("Page table fault when accessing virtual address %#x\n", vaddr); - } + } #endif diff --git a/src/sim/process.cc b/src/sim/process.cc index 68239fa52..8b273d591 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -47,6 +47,7 @@ #include "mem/translating_port.hh" #include "sim/builder.hh" #include "sim/process.hh" +#include "sim/process_impl.hh" #include "sim/stats.hh" #include "sim/syscall_emul.hh" #include "sim/system.hh" @@ -182,7 +183,8 @@ Process::startup() Port *mem_port; mem_port = system->physmem->getPort("functional"); - initVirtMem = new TranslatingPort("process init port", pTable, true); + initVirtMem = new TranslatingPort("process init port", this, + TranslatingPort::Always); mem_port->setPeer(initVirtMem); initVirtMem->setPeer(mem_port); } @@ -250,6 +252,29 @@ Process::sim_fd(int tgt_fd) return fd_map[tgt_fd]; } +bool +Process::checkAndAllocNextPage(Addr vaddr) +{ + // if this is an initial write we might not have + if (vaddr >= stack_min && vaddr < stack_base) { + pTable->allocate(roundDown(vaddr, VMPageSize), VMPageSize); + return true; + } + + // We've accessed the next page of the stack, so extend the stack + // to cover it. + if(vaddr < stack_min && vaddr >= stack_min - TheISA::PageBytes) + { + stack_min -= TheISA::PageBytes; + 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."); + return true; + } + return false; +} + void Process::serialize(std::ostream &os) { diff --git a/src/sim/process.hh b/src/sim/process.hh index dd64fa607..fa46b9c95 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -45,7 +45,6 @@ #include <vector> #include "base/statistics.hh" -#include "mem/translating_port.hh" #include "sim/host.hh" #include "sim/sim_object.hh" @@ -60,28 +59,6 @@ namespace TheISA class RemoteGDB; } -//This needs to be templated for cases where 32 bit pointers are needed. -template<class AddrType> -void -copyStringArray(std::vector<std::string> &strings, - AddrType array_ptr, AddrType data_ptr, - TranslatingPort* memPort) -{ - AddrType data_ptr_swap; - for (int i = 0; i < strings.size(); ++i) { - data_ptr_swap = htog(data_ptr); - memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, - sizeof(AddrType)); - memPort->writeString(data_ptr, strings[i].c_str()); - array_ptr += sizeof(AddrType); - data_ptr += strings[i].size() + 1; - } - // add NULL terminator - data_ptr = 0; - - memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(AddrType)); -} - class Process : public SimObject { public: @@ -194,6 +171,10 @@ class Process : public SimObject virtual void syscall(int64_t callnum, ThreadContext *tc) = 0; + // check if the this addr is on the next available page and allocate it + // if it's not we'll panic + bool checkAndAllocNextPage(Addr vaddr); + void serialize(std::ostream &os); void unserialize(Checkpoint *cp, const std::string §ion); }; diff --git a/src/sim/process_impl.hh b/src/sim/process_impl.hh new file mode 100644 index 000000000..a3519fe39 --- /dev/null +++ b/src/sim/process_impl.hh @@ -0,0 +1,75 @@ +/* + * 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __SIM_PROCESS_IMPL_HH__ +#define __SIM_PROCESS_IMPL_HH__ + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no reason to use it in FULL_SYSTEM +// mode when we do have an OS. +// +#include "config/full_system.hh" + +#if !FULL_SYSTEM + +#include <string> +#include <vector> + +#include "mem/translating_port.hh" + + +//This needs to be templated for cases where 32 bit pointers are needed. +template<class AddrType> +void +copyStringArray(std::vector<std::string> &strings, + AddrType array_ptr, AddrType data_ptr, + TranslatingPort* memPort) +{ + AddrType data_ptr_swap; + for (int i = 0; i < strings.size(); ++i) { + data_ptr_swap = htog(data_ptr); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, + sizeof(AddrType)); + memPort->writeString(data_ptr, strings[i].c_str()); + array_ptr += sizeof(AddrType); + data_ptr += strings[i].size() + 1; + } + // add NULL terminator + data_ptr = 0; + + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(AddrType)); +} + + +#endif // !FULL_SYSTEM + +#endif diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index 56a779674..10127aa5f 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -87,10 +87,7 @@ namespace PseudoInst Tick resume = curTick + Clock::Int::ns * ns; - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(resume); - else - quiesceEvent->schedule(resume); + quiesceEvent->reschedule(resume, true); DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", tc->getCpuPtr()->name(), ns, resume); @@ -110,10 +107,7 @@ namespace PseudoInst Tick resume = curTick + tc->getCpuPtr()->cycles(cycles); - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(resume); - else - quiesceEvent->schedule(resume); + quiesceEvent->reschedule(resume, true); DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", tc->getCpuPtr()->name(), cycles, resume); diff --git a/src/sim/simulate.cc b/src/sim/simulate.cc index 55cbb50a9..36bdff45e 100644 --- a/src/sim/simulate.cc +++ b/src/sim/simulate.cc @@ -92,10 +92,9 @@ simulate(Tick num_cycles) if (async_event) { async_event = false; if (async_statdump || async_statreset) { + Stats::StatEvent(async_statdump, async_statreset); async_statdump = false; async_statreset = false; - - Stats::StatEvent(async_statdump, async_statreset); } if (async_exit) { |