diff options
Diffstat (limited to 'src')
31 files changed, 593 insertions, 113 deletions
diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index 495cb722c..b671843cf 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -49,7 +49,8 @@ let {{ svcIop = InstObjParams("svc", "Svc", "PredOp", { "code": svcCode, - "predicate_test": predicateTest }, ["IsSyscall"]) + "predicate_test": predicateTest }, + ["IsSyscall", "IsNonSpeculative", "IsSerializeAfter"]) header_output = BasicDeclare.subst(svcIop) decoder_output = BasicConstructor.subst(svcIop) exec_output = PredOpExecute.subst(svcIop) diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 62b22472b..b2ab010c0 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -99,7 +99,7 @@ TableWalker::getPort(const std::string &if_name, int idx) System *sys = params()->sys; Tick minb = params()->min_backoff; Tick maxb = params()->max_backoff; - port = new DmaPort(this, sys, minb, maxb); + port = new DmaPort(this, sys, minb, maxb, true); return port; } return NULL; diff --git a/src/arch/sparc/isa/formats/basic.isa b/src/arch/sparc/isa/formats/basic.isa index bef8af2cd..915e34564 100644 --- a/src/arch/sparc/isa/formats/basic.isa +++ b/src/arch/sparc/isa/formats/basic.isa @@ -33,6 +33,11 @@ def template BasicExecDeclare {{ Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; }}; +def template DoFpOpDeclare {{ + Fault doFpOp(%(CPU_exec_context)s *, Trace::InstRecord *) + const M5_NO_INLINE; +}}; + // Definitions of execute methods that panic. def template BasicExecPanic {{ Fault @@ -58,6 +63,21 @@ def template BasicDeclare {{ }}; // Basic instruction class declaration template. +def template FpBasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + // Constructor. + %(class_name)s(ExtMachInst machInst); + %(BasicExecDeclare)s + %(DoFpOpDeclare)s + }; +}}; + +// Basic instruction class declaration template. def template BasicDeclareWithMnemonic {{ /** * Static instruction class for "%(mnemonic)s". @@ -110,6 +130,22 @@ def template BasicExecute {{ } }}; +def template DoFpOpExecute {{ + Fault + %(class_name)s::doFpOp(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + %(op_decl)s; + %(op_rd)s; + %(fp_code)s; + if (fault == NoFault) { + %(op_wb)s; + } + return fault; + } +}}; + // Basic decode template. def template BasicDecode {{ return new %(class_name)s(machInst); @@ -131,9 +167,9 @@ def format BasicOperate(code, *flags) {{ }}; def format FpBasic(code, *flags) {{ - fp_code = """ - Fsr |= bits(Fsr,4,0) << 5; - Fsr = insertBits(Fsr,4,0,0); + exec_code = """ + Fsr |= bits(Fsr, 4, 0) << 5; + Fsr = insertBits(Fsr, 4, 0, 0); int newrnd = M5_FE_TONEAREST; switch (Fsr<31:30>) { case 0: newrnd = M5_FE_TONEAREST; break; @@ -143,18 +179,18 @@ def format FpBasic(code, *flags) {{ } int oldrnd = m5_fegetround(); m5_fesetround(newrnd); + __asm__ __volatile__("" ::: "memory"); + fault = doFpOp(xc, traceData); + __asm__ __volatile__("" ::: "memory"); + m5_fesetround(oldrnd); + return fault; """ - - fp_code += code - - - fp_code += """ - 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) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) + fp_code = filterDoubles(code) + iop = InstObjParams(name, Name, 'SparcStaticInst', + { "code" : exec_code, "fp_code" : fp_code }, flags) + header_output = FpBasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) + exec_output += DoFpOpExecute.subst(iop) }}; diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index a6e0564ba..bc139a609 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -1335,16 +1335,15 @@ let {{ if (selector.si || selector.ti) { if (!desc.p) { fault = new StackFault(selector); - } - } else { - if ((m5reg.submode != SixtyFourBitMode || - m5reg.cpl == 3) || - !(desc.s == 1 && - desc.type.codeOrData == 0 && desc.type.w) || + } else if (!(desc.s == 1 && desc.type.codeOrData == 0 && + desc.type.w) || (desc.dpl != m5reg.cpl) || (selector.rpl != m5reg.cpl)) { fault = new GeneralProtection(selector); } + } else if (m5reg.submode != SixtyFourBitMode || + m5reg.cpl == 3) { + fault = new GeneralProtection(selector); } break; case SegIretCheck: diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc index 429b91687..a4aa93b48 100644 --- a/src/arch/x86/predecoder.cc +++ b/src/arch/x86/predecoder.cc @@ -186,7 +186,7 @@ namespace X86ISA DPRINTF(Predecoder, "Found two byte opcode.\n"); emi.opcode.prefixA = nextByte; } - else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3F)) + else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A)) { nextState = OpcodeState; DPRINTF(Predecoder, "Found three byte opcode.\n"); diff --git a/src/base/bitmap.cc b/src/base/bitmap.cc index 0d2a9302b..08425d74f 100644 --- a/src/base/bitmap.cc +++ b/src/base/bitmap.cc @@ -36,6 +36,7 @@ * * Authors: William Wang * Ali Saidi + * Chris Emmons */ #include <cassert> @@ -43,29 +44,50 @@ #include "base/bitmap.hh" #include "base/misc.hh" +const size_t Bitmap::sizeofHeaderBuffer = sizeof(Magic) + sizeof(Header) + + sizeof(Info); + // bitmap class ctor Bitmap::Bitmap(VideoConvert::Mode _mode, uint16_t w, uint16_t h, uint8_t *d) : mode(_mode), height(h), width(w), data(d), - vc(mode, VideoConvert::rgb8888, width, height) + vc(mode, VideoConvert::rgb8888, width, height), headerBuffer(0) { } +Bitmap::~Bitmap() { + if (headerBuffer) + delete [] headerBuffer; +} + void -Bitmap::write(std::ostream *bmp) +Bitmap::write(std::ostream *bmp) const { assert(data); - // For further information see: http://en.wikipedia.org/wiki/BMP_file_format - Magic magic = {{'B','M'}}; - Header header = {sizeof(VideoConvert::Rgb8888) * width * height , 0, 0, 54}; - Info info = {sizeof(Info), width, height, 1, - sizeof(VideoConvert::Rgb8888) * 8, 0, - sizeof(VideoConvert::Rgb8888) * width * height, 1, 1, 0, 0}; + // header is always the same for a bitmap object; compute the info once per + // bitmap object + if (!headerBuffer) { + // For further information see: + // http://en.wikipedia.org/wiki/BMP_file_format + Magic magic = {{'B','M'}}; + Header header = {sizeof(VideoConvert::Rgb8888) * width * height, + 0, 0, 54}; + Info info = {sizeof(Info), width, height, 1, + sizeof(VideoConvert::Rgb8888) * 8, 0, + sizeof(VideoConvert::Rgb8888) * width * height, 1, 1, 0, 0}; + + char *p = headerBuffer = new char[sizeofHeaderBuffer]; + memcpy(p, &magic, sizeof(Magic)); + p += sizeof(Magic); + memcpy(p, &header, sizeof(Header)); + p += sizeof(Header); + memcpy(p, &info, sizeof(Info)); + } - bmp->write(reinterpret_cast<char*>(&magic), sizeof(magic)); - bmp->write(reinterpret_cast<char*>(&header), sizeof(header)); - bmp->write(reinterpret_cast<char*>(&info), sizeof(info)); + // 1. write the header + bmp->write(headerBuffer, sizeofHeaderBuffer); + // 2. write the bitmap data uint8_t *tmp = vc.convert(data); uint32_t *tmp32 = (uint32_t*)tmp; diff --git a/src/base/bitmap.hh b/src/base/bitmap.hh index 9dfaa87a1..e9ad15473 100644 --- a/src/base/bitmap.hh +++ b/src/base/bitmap.hh @@ -36,6 +36,7 @@ * * Authors: William Wang * Ali Saidi + * Chris Emmons */ #ifndef __BASE_BITMAP_HH__ #define __BASE_BITMAP_HH__ @@ -62,6 +63,9 @@ class Bitmap */ Bitmap(VideoConvert::Mode mode, uint16_t w, uint16_t h, uint8_t *d); + /** Destructor */ + ~Bitmap(); + /** Provide the converter with the data that should be output. It will be * converted into rgb8888 and write out when write() is called. * @param d the data @@ -71,7 +75,13 @@ class Bitmap /** Write the provided data into the fstream provided * @param bmp stream to write to */ - void write(std::ostream *bmp); + void write(std::ostream *bmp) const; + + /** Gets a hash over the bitmap for quick comparisons to other bitmaps. + * @return hash of the bitmap + */ + uint64_t getHash() const { return vc.getHash(data); } + private: VideoConvert::Mode mode; @@ -81,6 +91,9 @@ class Bitmap VideoConvert vc; + mutable char *headerBuffer; + static const size_t sizeofHeaderBuffer; + struct Magic { unsigned char magic_number[2]; diff --git a/src/base/compiler.hh b/src/base/compiler.hh index 3315fb2f7..a95cb791c 100644 --- a/src/base/compiler.hh +++ b/src/base/compiler.hh @@ -42,6 +42,7 @@ #define M5_DUMMY_RETURN #define M5_VAR_USED __attribute__((unused)) #define M5_ATTR_PACKED __attribute__ ((__packed__)) +#define M5_NO_INLINE __attribute__ ((__noinline__)) #elif defined(__SUNPRO_CC) // this doesn't do anything with sun cc, but why not #define M5_ATTR_NORETURN __sun_attr__((__noreturn__)) @@ -50,6 +51,7 @@ #define M5_VAR_USED #define M5_PRAGMA_NORETURN(x) DO_PRAGMA(does_not_return(x)) #define M5_ATTR_PACKED __attribute__ ((__packed__)) +#define M5_NO_INLINE __attribute__ ((__noinline__)) #else #error "Need to define compiler options in base/compiler.hh" #endif diff --git a/src/base/output.cc b/src/base/output.cc index 020247152..1c749e5bf 100644 --- a/src/base/output.cc +++ b/src/base/output.cc @@ -26,11 +26,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Chris Emmons */ #include <sys/stat.h> #include <sys/types.h> +#include <dirent.h> +#include <cassert> #include <cerrno> #include <climits> #include <cstdlib> @@ -46,7 +49,7 @@ using namespace std; OutputDirectory simout; /** - * + * @file This file manages creating / deleting output files for the simulator. */ OutputDirectory::OutputDirectory() {} @@ -73,26 +76,54 @@ OutputDirectory::checkForStdio(const string &name) const ostream * OutputDirectory::openFile(const string &filename, - ios_base::openmode mode) const + ios_base::openmode mode) { if (filename.find(".gz", filename.length()-3) < filename.length()) { ogzstream *file = new ogzstream(filename.c_str(), mode); - if (!file->is_open()) fatal("Cannot open file %s", filename); - + assert(files.find(filename) == files.end()); + files[filename] = file; return file; } else { ofstream *file = new ofstream(filename.c_str(), mode); - if (!file->is_open()) fatal("Cannot open file %s", filename); - + assert(files.find(filename) == files.end()); + files[filename] = file; return file; } } void +OutputDirectory::close(ostream *openStream) { + map_t::iterator i; + for (i = files.begin(); i != files.end(); i++) { + if (i->second != openStream) + continue; + + ofstream *fs = dynamic_cast<ofstream*>(i->second); + if (fs) { + fs->close(); + delete i->second; + break; + } else { + ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); + if (gfs) { + gfs->close(); + delete i->second; + break; + } + } + } + + if (i == files.end()) + fatal("Attempted to close an unregistred file stream"); + + files.erase(i); +} + +void OutputDirectory::setDirectory(const string &d) { if (!dir.empty()) @@ -100,9 +131,9 @@ OutputDirectory::setDirectory(const string &d) dir = d; - // guarantee that directory ends with a '/' - if (dir[dir.size() - 1] != '/') - dir += "/"; + // guarantee that directory ends with a path separator + if (dir[dir.size() - 1] != PATH_SEPARATOR) + dir += PATH_SEPARATOR; } const string & @@ -117,7 +148,7 @@ OutputDirectory::directory() const inline string OutputDirectory::resolve(const string &name) const { - return (name[0] != '/') ? dir + name : name; + return (name[0] != PATH_SEPARATOR) ? dir + name : name; } ostream * @@ -136,20 +167,18 @@ OutputDirectory::create(const string &name, bool binary) } ostream * -OutputDirectory::find(const string &name) +OutputDirectory::find(const string &name) const { ostream *file = checkForStdio(name); if (file) return file; - string filename = resolve(name); - map_t::iterator i = files.find(filename); + const string filename = resolve(name); + map_t::const_iterator i = files.find(filename); if (i != files.end()) return (*i).second; - file = openFile(filename); - files[filename] = file; - return file; + return NULL; } bool @@ -157,3 +186,82 @@ OutputDirectory::isFile(const std::ostream *os) { return os && os != &cerr && os != &cout; } + +bool +OutputDirectory::isFile(const string &name) const +{ + // definitely a file if in our data structure + if (find(name) != NULL) return true; + + struct stat st_buf; + int st = stat(name.c_str(), &st_buf); + return (st == 0) && S_ISREG(st_buf.st_mode); +} + +string +OutputDirectory::createSubdirectory(const string &name) const +{ + const string new_dir = resolve(name); + if (new_dir.find(directory()) == string::npos) + fatal("Attempting to create subdirectory not in m5 output dir\n"); + + // if it already exists, that's ok; otherwise, fail if we couldn't create + if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) + fatal("Failed to create new output subdirectory '%s'\n", new_dir); + + return name + PATH_SEPARATOR; +} + +void +OutputDirectory::remove(const string &name, bool recursive) +{ + const string fname = resolve(name); + + if (fname.find(directory()) == string::npos) + fatal("Attempting to remove file/dir not in output dir\n"); + + if (isFile(fname)) { + // close and release file if we have it open + map_t::iterator itr = files.find(fname); + if (itr != files.end()) { + delete itr->second; + files.erase(itr); + } + + if (::remove(fname.c_str()) != 0) + fatal("Could not erase file '%s'\n", fname); + } else { + // assume 'name' is a directory + if (recursive) { + DIR *dir = opendir(fname.c_str()); + + // silently ignore removal request for non-existent directory + if ((!dir) && (errno == ENOENT)) + return; + + // fail on other errors + if (!dir) { + perror("opendir"); + fatal("Error opening directory for recursive removal '%s'\n", + fname); + } + + struct dirent *de = readdir(dir); + while (de != NULL) { + // ignore files starting with a '.'; user must delete those + // manually if they really want to + if (de->d_name[0] != '.') + remove(name + PATH_SEPARATOR + de->d_name, recursive); + + de = readdir(dir); + } + } + + // try to force recognition that we deleted the files in the directory + sync(); + + if (::remove(fname.c_str()) != 0) { + perror("Warning! 'remove' failed. Could not erase directory."); + } + } +} diff --git a/src/base/output.hh b/src/base/output.hh index 38c63714c..b86e68856 100644 --- a/src/base/output.hh +++ b/src/base/output.hh @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert + * Chris Emmons */ #ifndef __BASE_OUTPUT_HH__ @@ -35,33 +36,147 @@ #include <map> #include <string> +/** Interface for creating files in a gem5 output directory. */ class OutputDirectory { private: + /** File names and associated stream handles */ typedef std::map<std::string, std::ostream *> map_t; + /** Open file streams within this directory */ map_t files; + + /** Name of this directory */ std::string dir; + /** System-specific path separator character */ + static const char PATH_SEPARATOR = '/'; + + /** + * Returns relative file names prepended with name of this directory. + * Returns absolute file names unaltered. + * + * @param name file name to prepend with directory name + * @return file name prepended with base directory name or unaltered + * absolute file name + */ std::string resolve(const std::string &name) const; protected: + /** + * Determines whether given file name corresponds to standard output + * streams. + * + * @param name name of file to check + * @return output stream for standard output or error stream if name + * corresponds to one or the other; NULL otherwise + */ std::ostream *checkForStdio(const std::string &name) const; + + /** Opens a file (optionally compressed). + * + * Will open a file as a compressed stream if filename ends in .gz. + * + * @param filename file to open + * @param mode attributes to open file with + * @return stream pointer to opened file; will cause sim fail on error + */ std::ostream *openFile(const std::string &filename, - std::ios_base::openmode mode = std::ios::trunc) const; + std::ios_base::openmode mode = std::ios::trunc); public: + /** Constructor. */ OutputDirectory(); + + /** Destructor. */ ~OutputDirectory(); + /** + * Sets name of this directory. + * @param dir name of this directory + */ void setDirectory(const std::string &dir); + + /** + * Gets name of this directory. + * @return name of this directory + */ const std::string &directory() const; + /** + * Creates a file in this directory (optionally compressed). + * + * Will open a file as a compressed stream if filename ends in .gz. + * + * @param name name of file to create (without this directory's name + * leading it) + * @param binary true to create a binary file; false otherwise + * @return stream to the opened file + */ std::ostream *create(const std::string &name, bool binary = false); - std::ostream *find(const std::string &name); + /** + * Closes a file stream. + * + * Stream must have been opened through this interface, or sim will fail. + * + * @param openStream open stream to close + */ + void close(std::ostream *openStream); + + /** + * Finds stream associated with a file. + * @param name of file + * @return stream to specified file or NULL if file does not exist + */ + std::ostream *find(const std::string &name) const; + + /** + * Returns true if stream is open and not standard output or error. + * @param os output stream to evaluate + * @return true if os is non-NULL and not cout or cerr + */ static bool isFile(const std::ostream *os); - static inline bool isFile(const std::ostream &os) { return isFile(&os); } + + /** + * Determines whether a file name corresponds to a file in this directory. + * @param name name of file to evaluate + * @return true iff file has been opened in this directory or exists on the + * file system within this directory + */ + bool isFile(const std::string &name) const; + + /** + * Returns true if stream is open and not standard output or error. + * @param os output stream to evaluate + * @return true if os is non-NULL and not cout or cerr + */ + static inline bool isFile(const std::ostream &os) { + return isFile(&os); + } + + /** + * Creates a subdirectory within this directory. + * @param name name of subdirectory + * @return the new subdirectory's name suffixed with a path separator + */ + std::string createSubdirectory(const std::string &name) const; + + /** + * Removes a specified file or subdirectory. + * + * Will cause sim to fail for most errors. However, it will only warn the + * user if a directory could not be removed. This is in place to + * accommodate slow file systems where file deletions within a subdirectory + * may not be recognized quickly enough thereby causing the subsequent call + * to remove the directory to fail (seemingly unempty directory). + * + * @param name name of file or subdirectory to remove; name should not + * be prepended with the name of this directory object + * @param recursive set to true to attempt to recursively delete a + * subdirectory and its contents + */ + void remove(const std::string &name, bool recursive=false); }; extern OutputDirectory simout; diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index f8471f1a1..683ba7fe4 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -674,7 +674,11 @@ initText(const string &filename, bool desc) static bool connected = false; if (!connected) { - text.open(*simout.find(filename)); + ostream *os = simout.find(filename); + if (!os) + os = simout.create(filename); + + text.open(*os); text.descriptions = desc; connected = true; } diff --git a/src/base/trace.cc b/src/base/trace.cc index 1a035d400..fa55e42a9 100644 --- a/src/base/trace.cc +++ b/src/base/trace.cc @@ -64,6 +64,8 @@ void setOutput(const string &filename) { dprintf_stream = simout.find(filename); + if (!dprintf_stream) + dprintf_stream = simout.create(filename); } ObjectMatch ignore; diff --git a/src/base/vnc/VncServer.py b/src/base/vnc/VncServer.py index 21eb3ed28..6b746f2e2 100644 --- a/src/base/vnc/VncServer.py +++ b/src/base/vnc/VncServer.py @@ -43,3 +43,4 @@ class VncServer(SimObject): type = 'VncServer' port = Param.TcpPort(5900, "listen port") number = Param.Int(0, "vnc client number") + frame_capture = Param.Bool(False, "capture changed frames to files") diff --git a/src/base/vnc/convert.cc b/src/base/vnc/convert.cc index cd1502ce6..915a99407 100644 --- a/src/base/vnc/convert.cc +++ b/src/base/vnc/convert.cc @@ -67,7 +67,7 @@ VideoConvert::~VideoConvert() } uint8_t* -VideoConvert::convert(uint8_t *fb) +VideoConvert::convert(const uint8_t *fb) const { switch (inputMode) { case bgr565: @@ -82,7 +82,7 @@ VideoConvert::convert(uint8_t *fb) } uint8_t* -VideoConvert::m565rgb8888(uint8_t *fb, bool bgr) +VideoConvert::m565rgb8888(const uint8_t *fb, bool bgr) const { uint8_t *out = new uint8_t[area() * sizeof(uint32_t)]; uint32_t *out32 = (uint32_t*)out; @@ -113,7 +113,7 @@ VideoConvert::m565rgb8888(uint8_t *fb, bool bgr) uint8_t* -VideoConvert::bgr8888rgb8888(uint8_t *fb) +VideoConvert::bgr8888rgb8888(const uint8_t *fb) const { uint8_t *out = new uint8_t[area() * sizeof(uint32_t)]; uint32_t *out32 = (uint32_t*)out; @@ -136,4 +136,21 @@ VideoConvert::bgr8888rgb8888(uint8_t *fb) return out; } +/* +uint64_t +VideoConvert::getHash(const uint8_t *fb) const +{ + const uint8_t *fb_e = fb + area(); + + uint64_t hash = 1; + while (fb < fb_e - 8) { + hash += *((const uint64_t*)fb); + fb += 8; + } + + while (fb < fb_e) { + hash += *(fb++); + } + return hash; +}*/ diff --git a/src/base/vnc/convert.hh b/src/base/vnc/convert.hh index 68a21d677..17df0747b 100644 --- a/src/base/vnc/convert.hh +++ b/src/base/vnc/convert.hh @@ -44,6 +44,7 @@ #ifndef __BASE_VNC_CONVERT_HH__ #define __BASE_VNC_CONVERT_HH__ +#include <zlib.h> #include "base/bitunion.hh" class VideoConvert @@ -107,12 +108,21 @@ class VideoConvert * @param fb the frame buffer to convert * @return the converted data (user must free) */ - uint8_t* convert(uint8_t *fb); + uint8_t* convert(const uint8_t *fb) const; /** Return the number of pixels that this buffer specifies * @return number of pixels */ - int area() { return width * height; } + int area() const { return width * height; } + + /** + * Returns a hash on the raw data. + * + * @return hash of the buffer + */ + inline uint64_t getHash(const uint8_t *fb) const { + return adler32(0UL, fb, width * height); + } private: @@ -121,7 +131,7 @@ class VideoConvert * @param fb the data to convert * @return converted data */ - uint8_t* bgr8888rgb8888(uint8_t *fb); + uint8_t* bgr8888rgb8888(const uint8_t *fb) const; /** * Convert a bgr565 or rgb565 input to rgb8888. @@ -129,7 +139,7 @@ class VideoConvert * @param bgr true if the input data is bgr565 * @return converted data */ - uint8_t* m565rgb8888(uint8_t *fb, bool bgr); + uint8_t* m565rgb8888(const uint8_t *fb, bool bgr) const; Mode inputMode; Mode outputMode; diff --git a/src/base/vnc/vncserver.cc b/src/base/vnc/vncserver.cc index 18e581bfe..b4a783219 100644 --- a/src/base/vnc/vncserver.cc +++ b/src/base/vnc/vncserver.cc @@ -43,7 +43,10 @@ */ #include <sys/ioctl.h> +#include <sys/stat.h> #include <sys/termios.h> +#include <sys/types.h> +#include <fcntl.h> #include <poll.h> #include <unistd.h> @@ -52,11 +55,14 @@ #include "base/vnc/vncserver.hh" #include "base/atomicio.hh" +#include "base/bitmap.hh" #include "base/misc.hh" +#include "base/output.hh" #include "base/socket.hh" #include "base/trace.hh" #include "debug/VNC.hh" #include "sim/byteswap.hh" +#include "sim/core.hh" using namespace std; @@ -98,14 +104,14 @@ VncServer::VncServer(const Params *p) : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number), dataFd(-1), _videoWidth(1), _videoHeight(1), clientRfb(0), keyboard(NULL), mouse(NULL), sendUpdate(false), videoMode(VideoConvert::UnknownMode), - vc(NULL) + vc(NULL), captureEnabled(p->frame_capture), captureCurrentFrame(0), + captureLastHash(0), captureBitmap(0) { if (p->port) listen(p->port); curState = WaitForProtocolVersion; - // currently we only support this one pixel format // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha) // keep it around for telling the client and making @@ -121,6 +127,14 @@ VncServer::VncServer(const Params *p) pixelFormat.greenshift = 8; pixelFormat.blueshift = 0; + if (captureEnabled) { + // remove existing frame output directory if it exists, then create a + // clean empty directory + const string FRAME_OUTPUT_SUBDIR = "frames_" + name(); + simout.remove(FRAME_OUTPUT_SUBDIR, true); + captureOutputDirectory = simout.createSubdirectory( + FRAME_OUTPUT_SUBDIR); + } DPRINTF(VNC, "Vnc server created at port %d\n", p->port); } @@ -686,6 +700,16 @@ VncServer::setFrameBufferParams(VideoConvert::Mode mode, int width, int height) vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(), videoHeight()); + if (captureEnabled) { + // create bitmap of the frame with new attributes + if (captureBitmap) + delete captureBitmap; + + assert(clientRfb); + captureBitmap = new Bitmap(videoMode, width, height, clientRfb); + assert(captureBitmap); + } + if (dataFd > 0 && clientRfb && curState == NormalPhase) { if (supportsResizeEnc) sendFrameBufferResized(); @@ -702,3 +726,29 @@ VncServerParams::create() { return new VncServer(this); } + +void +VncServer::captureFrameBuffer() +{ + assert(captureBitmap); + + // skip identical frames + uint64_t new_hash = captureBitmap->getHash(); + if (captureLastHash == new_hash) + return; + captureLastHash = new_hash; + + // get the filename for the current frame + char frameFilenameBuffer[64]; + snprintf(frameFilenameBuffer, 64, "fb.%06d.%lld.bmp.gz", + captureCurrentFrame, static_cast<long long int>(curTick())); + const string frameFilename(frameFilenameBuffer); + + // create the compressed framebuffer file + ostream *fb_out = simout.create(captureOutputDirectory + frameFilename, + true); + captureBitmap->write(fb_out); + simout.close(fb_out); + + ++captureCurrentFrame; +} diff --git a/src/base/vnc/vncserver.hh b/src/base/vnc/vncserver.hh index 96dbdedda..33d833f26 100644 --- a/src/base/vnc/vncserver.hh +++ b/src/base/vnc/vncserver.hh @@ -48,6 +48,7 @@ #include <iostream> #include "base/vnc/convert.hh" +#include "base/bitmap.hh" #include "base/circlebuf.hh" #include "base/pollevent.hh" #include "base/socket.hh" @@ -55,6 +56,7 @@ #include "params/VncServer.hh" #include "sim/sim_object.hh" + /** * A device that expects to receive input from the vnc server should derrive * (through mulitple inheritence if necessary from VncKeyboard or VncMouse @@ -316,7 +318,25 @@ class VncServer : public SimObject /** The video converter that transforms data for us */ VideoConvert *vc; + /** Flag indicating whether to capture snapshots of frame buffer or not */ + bool captureEnabled; + + /** Current frame number being captured to a file */ + int captureCurrentFrame; + + /** Directory to store captured frames to */ + std::string captureOutputDirectory; + + /** Computed hash of the last captured frame */ + uint64_t captureLastHash; + + /** Cached bitmap object for writing out frame buffers to file */ + Bitmap *captureBitmap; + protected: + /** Captures the current frame buffer to a file */ + void captureFrameBuffer(); + /** * vnc client Interface */ @@ -449,6 +469,8 @@ class VncServer : public SimObject setDirty() { sendUpdate = true; + if (captureEnabled) + captureFrameBuffer(); sendFrameBufferUpdate(); } diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index b5c203742..50a8501e2 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -167,15 +167,16 @@ class BaseCPU(MemObject): self.icache_port = ic.cpu_side self.dcache_port = dc.cpu_side self._cached_ports = ['icache.mem_side', 'dcache.mem_side'] - if buildEnv['TARGET_ISA'] == 'x86' and iwc and dwc: - self.itb_walker_cache = iwc - self.dtb_walker_cache = dwc - self.itb.walker.port = iwc.cpu_side - self.dtb.walker.port = dwc.cpu_side - self._cached_ports += ["itb_walker_cache.mem_side", \ - "dtb_walker_cache.mem_side"] - elif buildEnv['TARGET_ISA'] == 'arm': - self._cached_ports += ["itb.walker.port", "dtb.walker.port"] + if buildEnv['TARGET_ISA'] in ['x86', 'arm']: + if iwc and dwc: + self.itb_walker_cache = iwc + self.dtb_walker_cache = dwc + self.itb.walker.port = iwc.cpu_side + self.dtb.walker.port = dwc.cpu_side + self._cached_ports += ["itb_walker_cache.mem_side", \ + "dtb_walker_cache.mem_side"] + else: + self._cached_ports += ["itb.walker.port", "dtb.walker.port"] def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None): self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 6e2de0baf..a0785ac10 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -184,7 +184,11 @@ BaseCPU::BaseCPU(Params *p) functionTracingEnabled = false; if (p->function_trace) { - functionTraceStream = simout.find(csprintf("ftrace.%s", name())); + const string fname = csprintf("ftrace.%s", name()); + functionTraceStream = simout.find(fname); + if (!functionTraceStream) + functionTraceStream = simout.create(fname); + currentFunctionStart = currentFunctionEnd = 0; functionEntryTick = p->function_trace_start; diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index 51643c169..1d8950a73 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -142,7 +142,3 @@ class DerivO3CPU(BaseCPU): smtROBThreshold = Param.Int(100, "SMT ROB Threshold Sharing Parameter") smtCommitPolicy = Param.String('RoundRobin', "SMT Commit Policy") - def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None): - BaseCPU.addPrivateSplitL1Caches(self, ic, dc, iwc, dwc) - self.icache.tgts_per_mshr = 20 - self.dcache.tgts_per_mshr = 20 diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index bb5ccc17e..5d3af6c70 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -438,6 +438,12 @@ FullO3CPU<Impl>::regStats() "to idling") .prereq(idleCycles); + quiesceCycles + .name(name() + ".quiesceCycles") + .desc("Total number of cycles that CPU has spent quiesced or waiting " + "for an interrupt") + .prereq(quiesceCycles); + // Number of Instructions simulated // -------------------------------- // Should probably be in Base CPU but need templated @@ -682,6 +688,8 @@ FullO3CPU<Impl>::activateContext(ThreadID tid, int delay) activityRec.activity(); fetch.wakeFromQuiesce(); + quiesceCycles += tickToCycles((curTick() - 1) - lastRunningCycle); + lastActivatedCycle = curTick(); _status = Running; @@ -716,6 +724,9 @@ FullO3CPU<Impl>::suspendContext(ThreadID tid) if ((activeThreads.size() == 1 && !deallocated) || activeThreads.size() == 0) unscheduleTickEvent(); + + DPRINTF(Quiesce, "Suspending Context\n"); + lastRunningCycle = curTick(); _status = Idle; } @@ -1193,6 +1204,8 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) } if (!tickEvent.scheduled()) schedule(tickEvent, nextCycle()); + + lastRunningCycle = curTick(); } template <class Impl> diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index b5654dee1..7580106ad 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -713,6 +713,9 @@ class FullO3CPU : public BaseO3CPU Stats::Scalar timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ Stats::Scalar idleCycles; + /** Stat for total number of cycles the CPU spends descheduled due to a + * quiesce operation or waiting for an interrupt. */ + Stats::Scalar quiesceCycles; /** Stat for the number of committed instructions per thread. */ Stats::Vector committedInsts; /** Stat for the total number of committed instructions. */ diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index 62e4a9c37..942b835f0 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -115,11 +115,13 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list) } -DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff) +DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff, + bool recv_snoops) : Port(dev->name() + "-dmaport", dev), device(dev), sys(s), pendingCount(0), actionInProgress(0), drainEvent(NULL), backoffTime(0), minBackoffDelay(min_backoff), - maxBackoffDelay(max_backoff), inRetry(false), backoffEvent(this) + maxBackoffDelay(max_backoff), inRetry(false), recvSnoops(recv_snoops), + snoopRangeSent(false), backoffEvent(this) { } bool @@ -141,6 +143,12 @@ DmaPort::recvTiming(PacketPtr pkt) pkt->reinitNacked(); queueDma(pkt, true); } else if (pkt->senderState) { + if (recvSnoops) { + if (pkt->isRequest()) { + return true; + } + } + DmaReqState *state; backoffTime >>= 2; diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index a92402bfe..083ab43cb 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -129,20 +129,45 @@ class DmaPort : public Port * it is that it's sending. */ bool inRetry; + /** Port accesses a cache which requires snooping */ + bool recvSnoops; + + /** Records snoop response so we only reply once to a status change */ + bool snoopRangeSent; + virtual bool recvTiming(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt) - { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN } + { + if (recvSnoops) return 0; + + panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN + } virtual void recvFunctional(PacketPtr pkt) - { panic("dma port shouldn't be used for pio access."); } + { + if (recvSnoops) return; + + panic("dma port shouldn't be used for pio access."); + } virtual void recvStatusChange(Status status) - { ; } + { + if (recvSnoops) { + if (status == RangeChange) { + if (!snoopRangeSent) { + snoopRangeSent = true; + sendStatusChange(Port::RangeChange); + } + return; + } + panic("Unexpected recvStatusChange\n"); + } + } virtual void recvRetry() ; virtual void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) - { resp.clear(); snoop = false; } + { resp.clear(); snoop = recvSnoops; } void queueDma(PacketPtr pkt, bool front = false); void sendDma(); @@ -151,7 +176,8 @@ class DmaPort : public Port EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; public: - DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff); + DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff, + bool recv_snoops = false); void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, uint8_t *data, Tick delay, Request::Flags flag = 0); diff --git a/src/dev/sparc/mm_disk.cc b/src/dev/sparc/mm_disk.cc index b86905387..1921f6d96 100644 --- a/src/dev/sparc/mm_disk.cc +++ b/src/dev/sparc/mm_disk.cc @@ -83,7 +83,7 @@ MmDisk::read(PacketPtr pkt) break; case sizeof(uint16_t): memcpy(&d16, diskData + (accessAddr % SectorSize), 2); - pkt->set(htobe(d32)); + pkt->set(htobe(d16)); DPRINTF(IdeDisk, "reading word %#x value= %#x\n", accessAddr, d16); break; case sizeof(uint32_t): diff --git a/src/dev/terminal.cc b/src/dev/terminal.cc index bae4c9194..74d5ddde7 100644 --- a/src/dev/terminal.cc +++ b/src/dev/terminal.cc @@ -102,6 +102,9 @@ Terminal::Terminal(const Params *p) { if (p->output) { outfile = simout.find(p->name); + if (!outfile) + outfile = simout.create(p->name); + outfile->setf(ios::unitbuf); } diff --git a/src/mem/physical.cc b/src/mem/physical.cc index e8b978ec8..d5c4e892f 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -556,7 +556,8 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(_size); if (size() > params()->range.size()) - fatal("Memory size has changed!\n"); + fatal("Memory size has changed! size %lld, param size %lld\n", + size(), params()->range.size()); pmemAddr = (uint8_t *)mmap(NULL, size(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 9576ba1af..b9d355736 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -62,6 +62,13 @@ machine(L1Cache, "AMD Hammer-like protocol") M, AccessPermission:Read_Only, desc="Modified (dirty)"; MM, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)"; + // Base states, locked and ready to service the mandatory queue + IR, AccessPermission:Invalid, desc="Idle"; + SR, AccessPermission:Read_Only, desc="Shared"; + OR, AccessPermission:Read_Only, desc="Owned"; + MR, AccessPermission:Read_Only, desc="Modified (dirty)"; + MMR, AccessPermission:Read_Write, desc="Modified (dirty and locally modified)"; + // Transient States IM, AccessPermission:Busy, "IM", desc="Issued GetX"; SM, AccessPermission:Read_Only, "SM", desc="Issued GetX, we still have a valid copy of the line"; @@ -1217,6 +1224,11 @@ machine(L1Cache, "AMD Hammer-like protocol") stall_and_wait(mandatoryQueue_in, address); } + action(z_stall, "z", desc="stall") { + // do nothing and the special z_stall action will return a protocol stall + // so that the next port is checked + } + action(kd_wakeUpDependents, "kd", desc="wake-up dependents") { wakeUpBuffers(address); } @@ -1246,7 +1258,7 @@ machine(L1Cache, "AMD Hammer-like protocol") zz_stallAndWaitMandatoryQueue; } - transition({IM, SM, ISM, OM, IS, SS, MM_W, M_W, OI, MI, II, IT, ST, OT, MT, MMT, IM_F, SM_F, ISM_F, OM_F, MM_WF, MI_F, MM_F}, L1_to_L2) { + transition({IM, SM, ISM, OM, IS, SS, MM_W, M_W, OI, MI, II, IT, ST, OT, MT, MMT, IM_F, SM_F, ISM_F, OM_F, MM_WF, MI_F, MM_F, IR, SR, OR, MR, MMR}, L1_to_L2) { zz_stallAndWaitMandatoryQueue; } @@ -1259,7 +1271,11 @@ machine(L1Cache, "AMD Hammer-like protocol") } transition({IT, ST, OT, MT, MMT}, {Other_GETX, NC_DMA_GETS, Other_GETS, Merged_GETS, Other_GETS_No_Mig, Invalidate, Flush_line}) { - // stall + z_stall; + } + + transition({IR, SR, OR, MR, MMR}, {Other_GETX, NC_DMA_GETS, Other_GETS, Merged_GETS, Other_GETS_No_Mig, Invalidate}) { + z_stall; } // Transitions moving data between the L1 and L2 caches @@ -1382,33 +1398,33 @@ machine(L1Cache, "AMD Hammer-like protocol") ll_L2toL1Transfer; } - transition(IT, Complete_L2_to_L1, I) { + transition(IT, Complete_L2_to_L1, IR) { j_popTriggerQueue; kd_wakeUpDependents; } - transition(ST, Complete_L2_to_L1, S) { + transition(ST, Complete_L2_to_L1, SR) { j_popTriggerQueue; kd_wakeUpDependents; } - transition(OT, Complete_L2_to_L1, O) { + transition(OT, Complete_L2_to_L1, OR) { j_popTriggerQueue; kd_wakeUpDependents; } - transition(MT, Complete_L2_to_L1, M) { + transition(MT, Complete_L2_to_L1, MR) { j_popTriggerQueue; kd_wakeUpDependents; } - transition(MMT, Complete_L2_to_L1, MM) { + transition(MMT, Complete_L2_to_L1, MMR) { j_popTriggerQueue; kd_wakeUpDependents; } // Transitions from Idle - transition(I, Load, IS) { + transition({I, IR}, Load, IS) { ii_allocateL1DCacheBlock; i_allocateTBE; a_issueGETS; @@ -1416,7 +1432,7 @@ machine(L1Cache, "AMD Hammer-like protocol") k_popMandatoryQueue; } - transition(I, Ifetch, IS) { + transition({I, IR}, Ifetch, IS) { jj_allocateL1ICacheBlock; i_allocateTBE; a_issueGETS; @@ -1424,7 +1440,7 @@ machine(L1Cache, "AMD Hammer-like protocol") k_popMandatoryQueue; } - transition(I, Store, IM) { + transition({I, IR}, Store, IM) { ii_allocateL1DCacheBlock; i_allocateTBE; b_issueGETX; @@ -1432,7 +1448,7 @@ machine(L1Cache, "AMD Hammer-like protocol") k_popMandatoryQueue; } - transition(I, Flush_line, IM_F) { + transition({I, IR}, Flush_line, IM_F) { it_allocateTBE; bf_issueGETF; uu_profileMiss; @@ -1455,14 +1471,19 @@ machine(L1Cache, "AMD Hammer-like protocol") k_popMandatoryQueue; } - transition(S, Store, SM) { + transition(SR, {Load, Ifetch}, S) { + h_load_hit; + k_popMandatoryQueue; + } + + transition({S, SR}, Store, SM) { i_allocateTBE; b_issueGETX; uu_profileMiss; k_popMandatoryQueue; } - transition(S, Flush_line, SM_F) { + transition({S, SR}, Flush_line, SM_F) { i_allocateTBE; bf_issueGETF; uu_profileMiss; @@ -1491,14 +1512,19 @@ machine(L1Cache, "AMD Hammer-like protocol") k_popMandatoryQueue; } - transition(O, Store, OM) { + transition(OR, {Load, Ifetch}, O) { + h_load_hit; + k_popMandatoryQueue; + } + + transition({O, OR}, Store, OM) { i_allocateTBE; b_issueGETX; p_decrementNumberOfMessagesByOne; uu_profileMiss; k_popMandatoryQueue; } - transition(O, Flush_line, OM_F) { + transition({O, OR}, Flush_line, OM_F) { i_allocateTBE; bf_issueGETF; p_decrementNumberOfMessagesByOne; @@ -1530,17 +1556,17 @@ machine(L1Cache, "AMD Hammer-like protocol") } // Transitions from Modified - transition(MM, {Load, Ifetch}) { + transition({MM, MMR}, {Load, Ifetch}, MM) { h_load_hit; k_popMandatoryQueue; } - transition(MM, Store) { + transition({MM, MMR}, Store, MM) { hh_store_hit; k_popMandatoryQueue; } - transition({MM, M}, Flush_line, MM_F) { + transition({MM, M, MMR}, Flush_line, MM_F) { i_allocateTBE; bf_issueGETF; p_decrementNumberOfMessagesByOne; @@ -1587,12 +1613,12 @@ machine(L1Cache, "AMD Hammer-like protocol") } // Transitions from Dirty Exclusive - transition(M, {Load, Ifetch}) { + transition({M, MR}, {Load, Ifetch}, M) { h_load_hit; k_popMandatoryQueue; } - transition(M, Store, MM) { + transition({M, MR}, Store, MM) { hh_store_hit; k_popMandatoryQueue; } diff --git a/src/mem/protocol/Network_test.slicc b/src/mem/protocol/Network_test.slicc index b122b149c..a065a8535 100644 --- a/src/mem/protocol/Network_test.slicc +++ b/src/mem/protocol/Network_test.slicc @@ -3,4 +3,3 @@ include "RubySlicc_interfaces.slicc"; include "Network_test-msg.sm"; include "Network_test-cache.sm"; include "Network_test-dir.sm"; -include "standard_1level_CMP-protocol.sm"; diff --git a/src/mem/ruby/network/topologies/MeshDirCorners.py b/src/mem/ruby/network/topologies/MeshDirCorners.py index f9d302d19..7be8b9101 100644 --- a/src/mem/ruby/network/topologies/MeshDirCorners.py +++ b/src/mem/ruby/network/topologies/MeshDirCorners.py @@ -99,7 +99,7 @@ def makeTopology(nodes, options, IntLink, ExtLink, Router): # Connect the dma nodes to router 0. These should only be DMA nodes. for (i, node) in enumerate(dma_nodes): assert(node.type == 'DMA_Controller') - ext_links.append(ExtLink(ext_node=node, int_node=mesh.routers[0])) + ext_links.append(ExtLink(link_id=link_count, ext_node=node, int_node=mesh.routers[0])) # Create the mesh links. First row (east-west) links then column # (north-south) links diff --git a/src/sim/process.cc b/src/sim/process.cc index 468f42955..c400b72ee 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -350,8 +350,6 @@ Process::fixupStackFault(Addr vaddr) }; return true; } - warn("Not extending stack: address %#x isn't at the end of the stack.", - vaddr); return false; } |