summaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'src/base')
-rw-r--r--src/base/bitfield.hh69
-rw-r--r--src/base/callback.hh122
-rw-r--r--src/base/chunk_generator.hh141
-rw-r--r--src/base/circlebuf.cc213
-rw-r--r--src/base/circlebuf.hh62
-rw-r--r--src/base/compression/lzss_compression.cc171
-rw-r--r--src/base/compression/lzss_compression.hh101
-rw-r--r--src/base/compression/null_compression.hh76
-rw-r--r--src/base/cprintf.cc268
-rw-r--r--src/base/cprintf.hh197
-rw-r--r--src/base/cprintf_formats.hh353
-rw-r--r--src/base/crc.cc114
-rw-r--r--src/base/crc.hh37
-rw-r--r--src/base/date.cc29
-rw-r--r--src/base/dbl_list.hh165
-rw-r--r--src/base/endian.hh41
-rw-r--r--src/base/fast_alloc.cc195
-rw-r--r--src/base/fast_alloc.hh214
-rw-r--r--src/base/fenv.hh52
-rw-r--r--src/base/fifo_buffer.cc40
-rw-r--r--src/base/fifo_buffer.hh86
-rw-r--r--src/base/hashmap.hh85
-rw-r--r--src/base/hostinfo.cc85
-rw-r--r--src/base/hostinfo.hh43
-rw-r--r--src/base/hybrid_pred.cc273
-rw-r--r--src/base/hybrid_pred.hh201
-rw-r--r--src/base/inet.cc207
-rw-r--r--src/base/inet.hh407
-rw-r--r--src/base/inifile.cc433
-rw-r--r--src/base/inifile.hh208
-rw-r--r--src/base/intmath.cc58
-rw-r--r--src/base/intmath.hh230
-rw-r--r--src/base/kgdb.h174
-rw-r--r--src/base/loader/aout_object.cc94
-rw-r--r--src/base/loader/aout_object.hh56
-rw-r--r--src/base/loader/coff_sym.h519
-rw-r--r--src/base/loader/coff_symconst.h200
-rw-r--r--src/base/loader/ecoff_object.cc153
-rw-r--r--src/base/loader/ecoff_object.hh60
-rw-r--r--src/base/loader/elf_object.cc315
-rw-r--r--src/base/loader/elf_object.hh55
-rw-r--r--src/base/loader/exec_aout.h61
-rw-r--r--src/base/loader/exec_ecoff.h110
-rw-r--r--src/base/loader/object_file.cc145
-rw-r--r--src/base/loader/object_file.hh119
-rw-r--r--src/base/loader/symtab.cc137
-rw-r--r--src/base/loader/symtab.hh173
-rw-r--r--src/base/match.cc96
-rw-r--r--src/base/match.hh57
-rw-r--r--src/base/misc.cc124
-rw-r--r--src/base/misc.hh85
-rw-r--r--src/base/mod_num.hh201
-rw-r--r--src/base/mysql.cc110
-rw-r--r--src/base/mysql.hh423
-rw-r--r--src/base/output.cc129
-rw-r--r--src/base/output.hh61
-rw-r--r--src/base/pollevent.cc273
-rw-r--r--src/base/pollevent.hh97
-rw-r--r--src/base/predictor.hh60
-rw-r--r--src/base/random.cc97
-rw-r--r--src/base/random.hh126
-rw-r--r--src/base/range.cc83
-rw-r--r--src/base/range.hh355
-rw-r--r--src/base/refcnt.hh123
-rw-r--r--src/base/remote_gdb.cc1175
-rw-r--r--src/base/remote_gdb.hh209
-rw-r--r--src/base/res_list.hh755
-rw-r--r--src/base/sat_counter.cc268
-rw-r--r--src/base/sat_counter.hh190
-rw-r--r--src/base/sched_list.hh178
-rw-r--r--src/base/socket.cc111
-rw-r--r--src/base/socket.hh49
-rw-r--r--src/base/statistics.cc356
-rw-r--r--src/base/statistics.hh2896
-rw-r--r--src/base/stats/events.cc169
-rw-r--r--src/base/stats/events.hh66
-rw-r--r--src/base/stats/flags.hh73
-rw-r--r--src/base/stats/mysql.cc900
-rw-r--r--src/base/stats/mysql.hh155
-rw-r--r--src/base/stats/mysql_run.hh65
-rw-r--r--src/base/stats/output.hh47
-rw-r--r--src/base/stats/statdb.cc93
-rw-r--r--src/base/stats/statdb.hh74
-rw-r--r--src/base/stats/text.cc736
-rw-r--r--src/base/stats/text.hh77
-rw-r--r--src/base/stats/types.hh49
-rw-r--r--src/base/stats/visit.cc41
-rw-r--r--src/base/stats/visit.hh63
-rw-r--r--src/base/str.cc373
-rw-r--r--src/base/str.hh141
-rw-r--r--src/base/time.cc131
-rw-r--r--src/base/time.hh65
-rw-r--r--src/base/timebuf.hh218
-rw-r--r--src/base/trace.cc350
-rw-r--r--src/base/trace.hh231
-rw-r--r--src/base/traceflags.py316
-rw-r--r--src/base/userinfo.cc41
-rw-r--r--src/base/userinfo.hh36
98 files changed, 20544 insertions, 0 deletions
diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh
new file mode 100644
index 000000000..c59354c7d
--- /dev/null
+++ b/src/base/bitfield.hh
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_BITFIELD_HH__
+#define __BASE_BITFIELD_HH__
+
+#include "sim/host.hh"
+
+/**
+ * Generate a 64-bit mask of 'nbits' 1s, right justified.
+ */
+inline uint64_t
+mask(int nbits)
+{
+ return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1;
+}
+
+
+/**
+ * Extract the bitfield from position 'first' to 'last' (inclusive)
+ * from 'val' and right justify it. MSB is numbered 63, LSB is 0.
+ */
+template <class T>
+inline
+T
+bits(T val, int first, int last)
+{
+ int nbits = first - last + 1;
+ return (val >> last) & mask(nbits);
+}
+
+/**
+ * Sign-extend an N-bit value to 64 bits.
+ */
+template <int N>
+inline
+int64_t
+sext(uint64_t val)
+{
+ int sign_bit = bits(val, N-1, N-1);
+ return sign_bit ? (val | ~mask(N)) : val;
+}
+
+#endif // __BASE_BITFIELD_HH__
diff --git a/src/base/callback.hh b/src/base/callback.hh
new file mode 100644
index 000000000..7b3023505
--- /dev/null
+++ b/src/base/callback.hh
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CALLBACK_HH__
+#define __CALLBACK_HH__
+
+#include <list>
+
+/**
+ * Generic callback class. This base class provides a virtual process
+ * function that gets called when the callback queue is processed.
+ */
+class Callback
+{
+ public:
+ /**
+ * virtualize the destructor to make sure that the correct one
+ * gets called.
+ */
+ virtual ~Callback() {}
+
+ /**
+ * virtual process function that is invoked when the callback
+ * queue is executed.
+ */
+ virtual void process() = 0;
+};
+
+class CallbackQueue
+{
+ protected:
+ /**
+ * Simple typedef for the data structure that stores all of the
+ * callbacks.
+ */
+ typedef std::list<Callback *> queue;
+
+ /**
+ * List of all callbacks. To be called in fifo order.
+ */
+ queue callbacks;
+
+ public:
+ /**
+ * Add a callback to the end of the queue
+ * @param callback the callback to be added to the queue
+ */
+ void add(Callback *callback)
+ {
+ callbacks.push_back(callback);
+ }
+
+ /**
+ * Find out if there are any callbacks in the queue
+ */
+ bool empty() const { return callbacks.empty(); }
+
+ /**
+ * process all callbacks
+ */
+ void process()
+ {
+ queue::iterator i = callbacks.begin();
+ queue::iterator end = callbacks.end();
+
+ while (i != end) {
+ (*i)->process();
+ ++i;
+ }
+ }
+
+ /**
+ * clear the callback queue
+ */
+ void clear()
+ {
+ callbacks.clear();
+ }
+};
+
+/// Helper template class to turn a simple class member function into
+/// a callback.
+template <class T, void (T::* F)()>
+class MakeCallback : public Callback
+{
+ private:
+ T *object;
+
+ public:
+ MakeCallback(T *o)
+ : object(o)
+ { }
+
+ void process() { (object->*F)(); }
+};
+
+#endif // __CALLBACK_HH__
diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh
new file mode 100644
index 000000000..4f708bd4b
--- /dev/null
+++ b/src/base/chunk_generator.hh
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifndef __BASE__CHUNK_GENERATOR_HH__
+#define __BASE__CHUNK_GENERATOR_HH__
+
+/**
+ * @file
+ * Declaration and inline definition of ChunkGenerator object.
+ */
+
+#include <algorithm>
+#include "base/intmath.hh"
+#include "arch/isa_traits.hh" // for Addr
+
+/**
+ * This class takes an arbitrary memory region (address/length pair)
+ * and generates a series of appropriately (e.g. block- or page-)
+ * aligned chunks covering the same region.
+ *
+ * Example usage:
+
+\code
+ for (ChunkGenerator gen(addr, size, chunkSize); !gen.done(); gen.next()) {
+ doSomethingChunky(gen.addr(), gen.size());
+ }
+\endcode
+ */
+class ChunkGenerator
+{
+ private:
+ /** The starting address of the current chunk. */
+ Addr curAddr;
+ /** The starting address of the next chunk (after the current one). */
+ Addr nextAddr;
+ /** The size of the current chunk (in bytes). */
+ int curSize;
+ /** The number of bytes remaining in the region after the current chunk. */
+ int sizeLeft;
+ /** The start address so we can calculate offset in writing block. */
+ const Addr startAddr;
+ /** The maximum chunk size, e.g., the cache block size or page size. */
+ const int chunkSize;
+
+ public:
+ /**
+ * Constructor.
+ * @param startAddr The starting address of the region.
+ * @param totalSize The total size of the region.
+ * @param _chunkSize The size/alignment of chunks into which
+ * the region should be decomposed.
+ */
+ ChunkGenerator(Addr _startAddr, int totalSize, int _chunkSize)
+ : startAddr(_startAddr), chunkSize(_chunkSize)
+ {
+ // chunkSize must be a power of two
+ assert(chunkSize == 0 || isPowerOf2(chunkSize));
+
+ // set up initial chunk.
+ curAddr = startAddr;
+
+ if (chunkSize == 0) //Special Case, if we see 0, assume no chuncking
+ {
+ nextAddr = startAddr + totalSize;
+ }
+ else
+ {
+ // nextAddr should be *next* chunk start
+ nextAddr = roundUp(startAddr, chunkSize);
+ if (curAddr == nextAddr) {
+ // ... even if startAddr is already chunk-aligned
+ nextAddr += chunkSize;
+ }
+ }
+
+ // how many bytes are left between curAddr and the end of this chunk?
+ int left_in_chunk = nextAddr - curAddr;
+ curSize = std::min(totalSize, left_in_chunk);
+ sizeLeft = totalSize - curSize;
+ }
+
+ /** Return starting address of current chunk. */
+ Addr addr() { return curAddr; }
+ /** Return size in bytes of current chunk. */
+ int size() { return curSize; }
+
+ /** Number of bytes we have already chunked up. */
+ int complete() { return curAddr - startAddr; }
+ /**
+ * Are we done? That is, did the last call to next() advance
+ * past the end of the region?
+ * @return True if yes, false if more to go.
+ */
+ bool done() { return (curSize == 0); }
+
+ /**
+ * Advance generator to next chunk.
+ * @return True if successful, false if unsuccessful
+ * (because we were at the last chunk).
+ */
+ bool next()
+ {
+ if (sizeLeft == 0) {
+ curSize = 0;
+ return false;
+ }
+
+ curAddr = nextAddr;
+ curSize = std::min(sizeLeft, chunkSize);
+ sizeLeft -= curSize;
+ nextAddr += curSize;
+ return true;
+ }
+};
+
+#endif // __BASE__CHUNK_GENERATOR_HH__
diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc
new file mode 100644
index 000000000..89bbfd822
--- /dev/null
+++ b/src/base/circlebuf.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include <string>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/circlebuf.hh"
+#include "base/cprintf.hh"
+#include "base/intmath.hh"
+
+using namespace std;
+
+CircleBuf::CircleBuf(int l)
+ : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0)
+{
+ _buf = new char[_buflen];
+}
+
+CircleBuf::~CircleBuf()
+{
+ if (_buf)
+ delete [] _buf;
+}
+
+void
+CircleBuf::dump()
+{
+ cprintf("start = %10d, stop = %10d, buflen = %10d\n",
+ _start, _stop, _buflen);
+ fflush(stdout);
+ ::write(STDOUT_FILENO, _buf, _buflen);
+ ::write(STDOUT_FILENO, "<\n", 2);
+}
+
+void
+CircleBuf::flush()
+{
+ _start = 0;
+ _stop = 0;
+ _rollover = false;
+}
+
+void
+CircleBuf::read(char *b, int len)
+{
+ _size -= len;
+ if (_size < 0)
+ _size = 0;
+
+ if (_stop > _start) {
+ len = min(len, _stop - _start);
+ memcpy(b, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ int endlen = _buflen - _start;
+ if (endlen > len) {
+ memcpy(b, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ memcpy(b, _buf + _start, endlen);
+ _start = min(len - endlen, _stop);
+ memcpy(b + endlen, _buf, _start);
+ }
+ }
+}
+
+void
+CircleBuf::read(int fd, int len)
+{
+ _size -= len;
+ if (_size < 0)
+ _size = 0;
+
+ if (_stop > _start) {
+ len = min(len, _stop - _start);
+ ::write(fd, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ int endlen = _buflen - _start;
+ if (endlen > len) {
+ ::write(fd, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ ::write(fd, _buf + _start, endlen);
+ _start = min(len - endlen, _stop);
+ ::write(fd, _buf, _start);
+ }
+ }
+}
+
+void
+CircleBuf::read(int fd)
+{
+ _size = 0;
+
+ if (_stop > _start) {
+ ::write(fd, _buf + _start, _stop - _start);
+ }
+ else {
+ ::write(fd, _buf + _start, _buflen - _start);
+ ::write(fd, _buf, _stop);
+ }
+
+ _start = _stop;
+}
+
+void
+CircleBuf::read(ostream &out)
+{
+ _size = 0;
+
+ if (_stop > _start) {
+ out.write(_buf + _start, _stop - _start);
+ }
+ else {
+ out.write(_buf + _start, _buflen - _start);
+ out.write(_buf, _stop);
+ }
+
+ _start = _stop;
+}
+
+void
+CircleBuf::readall(int fd)
+{
+ if (_rollover)
+ ::write(fd, _buf + _stop, _buflen - _stop);
+
+ ::write(fd, _buf, _stop);
+ _start = _stop;
+}
+
+void
+CircleBuf::write(char b)
+{
+ write(&b, 1);
+}
+
+void
+CircleBuf::write(const char *b)
+{
+ write(b, strlen(b));
+}
+
+void
+CircleBuf::write(const char *b, int len)
+{
+ if (len <= 0)
+ return;
+
+ _size += len;
+ if (_size > _buflen)
+ _size = _buflen;
+
+ int old_start = _start;
+ int old_stop = _stop;
+
+ if (len >= _buflen) {
+ _start = 0;
+ _stop = _buflen;
+ _rollover = true;
+ memcpy(_buf, b + (len - _buflen), _buflen);
+ return;
+ }
+
+ if (_stop + len <= _buflen) {
+ memcpy(_buf + _stop, b, len);
+ _stop += len;
+ } else {
+ int end_len = _buflen - old_stop;
+ _stop = len - end_len;
+ memcpy(_buf + old_stop, b, end_len);
+ memcpy(_buf, b + end_len, _stop);
+ _rollover = true;
+ }
+
+ if (old_start > old_stop && old_start < _stop ||
+ old_start < old_stop && _stop < old_stop)
+ _start = _stop + 1;
+}
diff --git a/src/base/circlebuf.hh b/src/base/circlebuf.hh
new file mode 100644
index 000000000..8a64cb5f5
--- /dev/null
+++ b/src/base/circlebuf.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CIRCLEBUF_HH__
+#define __CIRCLEBUF_HH__
+
+#include <iosfwd>
+
+class CircleBuf
+{
+ protected:
+ char *_buf;
+ bool _rollover;
+ int _buflen;
+ int _size;
+ int _start;
+ int _stop;
+
+ public:
+ explicit CircleBuf(int l);
+ ~CircleBuf();
+
+ bool empty() const { return _size == 0; }
+ int size() const { return _size; }
+ void dump();
+ void flush();
+ void read(char *b, int len);
+ void read(int fd, int len);
+ void read(int fd);
+ void read(std::ostream &out);
+ void readall(int fd);
+ void write(char b);
+ void write(const char *b);
+ void write(const char *b, int len);
+};
+
+#endif // __CIRCLEBUF_HH__
diff --git a/src/base/compression/lzss_compression.cc b/src/base/compression/lzss_compression.cc
new file mode 100644
index 000000000..3ffdf7e95
--- /dev/null
+++ b/src/base/compression/lzss_compression.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * LZSSCompression definitions.
+ */
+
+#include <assert.h>
+
+#include "base/compression/lzss_compression.hh"
+
+#include "base/misc.hh" //for fatal
+
+void
+LZSSCompression::findSubString(uint8_t *src, int back, int size, uint16_t &L,
+ uint16_t &P)
+{
+ int front = 0;
+ int max_length = size - back;
+ L = 0;
+ P = back - 1;
+ while (front < back) {
+ while (src[front] != src[back] && front < back) ++front;
+ if (front >= back) {
+ return;
+ }
+ int i = 1;
+ while (src[front+i] == src[back+i] && i < max_length) ++i;
+ if (i >= L) {
+ L = i;
+ P = front;
+ }
+ if (src[front+i] != src[back+i-1]) {
+ // can't find a longer substring until past this point.
+ front += i;
+ } else {
+ ++front;
+ }
+ }
+}
+
+int
+LZSSCompression::emitByte(uint8_t *dest, uint8_t byte)
+{
+ if ((byte >> 5 & 0x7) == 0 || (byte >> 5 & 0x7) == 7) {
+ // If the top 3 bits are the same, emit 00<6bits>
+ dest[0] = byte & 0x3f;
+ return 1;
+ } else {
+ // emit 01XXXXXX <8 bits>
+ dest[0] = 0x40;
+ dest[1] = byte;
+ return 2;
+ }
+}
+
+void
+LZSSCompression::emitString(uint8_t *dest, uint16_t P, uint16_t L)
+{
+ // Emit 1<7P> <5P><3L> <8L>
+ dest[0] = 1<<7 | (P >> 5 & 0x7f);
+ dest[1] = ((P & 0x1f) << 3) | (L>>8 & 0x3);
+ dest[2] = L & 0xFF;
+}
+
+int
+LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size)
+{
+ if (size > 4096) {
+ fatal("Compression can only handle block sizes of 4096 bytes or less");
+ }
+
+ // Encode the first byte.
+ int dest_index = emitByte(dest, src[0]);
+ int i = 1;
+ // A 11 bit field
+ uint16_t L;
+ // A 12 bit field
+ uint16_t P = 0;
+
+ while (i < size && dest_index < size) {
+ L = 0;
+
+ if (dest_index+3 >= size) {
+ dest_index = size;
+ continue;
+ }
+
+ if (i == size - 1) {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ continue;
+ }
+ findSubString(src, i, size, L, P);
+ if (L > 1) {
+ // Output the string reference
+ emitString(&dest[dest_index], P, L);
+ dest_index += 3;
+ i = i+L;
+ } else {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ }
+ }
+
+ if (dest_index >= size) {
+ // Have expansion instead of compression, just copy.
+ memcpy(dest,src,size);
+ return size;
+ }
+ return dest_index;
+}
+
+int
+LZSSCompression::uncompress(uint8_t *dest, uint8_t *src, int size)
+{
+ int index = 0;
+ int i = 0;
+ while (i < size) {
+ if (src[i] & 1<<7 ) {
+ // We have a string
+ // Extract P
+ int start = (src[i] & 0x3f)<<5 | ((src[i+1] >> 3) & 0x1f);
+ // Extract L
+ int len = (src[i+1] & 0x07)<<8 | src[i+2];
+ i += 3;
+ for (int j = start; j < start+len; ++j) {
+ dest[index++] = dest[j];
+ }
+ } else {
+ // We have a character
+ if (src[i] & 1<<6) {
+ // Value is in the next byte
+ dest[index++] = src[i+1];
+ i += 2;
+ } else {
+ // just extend the lower 6 bits
+ dest[index++] = (src[i] & 0x3f) | ((src[i] & 1<<5) ? 0xC0 : 0);
+ ++i;
+ }
+ }
+ }
+ return index;
+}
diff --git a/src/base/compression/lzss_compression.hh b/src/base/compression/lzss_compression.hh
new file mode 100644
index 000000000..c136c6d60
--- /dev/null
+++ b/src/base/compression/lzss_compression.hh
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LZSS_COMPRESSION_HH__
+#define __LZSS_COMPRESSION_HH__
+
+/** @file
+ * LZSSCompression declarations.
+ */
+
+#include "sim/host.hh" // for uint8_t
+
+/**
+ * Simple LZSS compression scheme.
+ */
+class LZSSCompression
+{
+ /**
+ * Finds the longest substring for the given offset.
+ * @param src The source block that we search for substrings.
+ * @param back The larger offset.
+ * @param size The size of the source block.
+ * @param L The length of the largest substring.
+ * @param P The starting offset of the largest substring.
+ */
+ void findSubString(uint8_t *src, int back, int size, uint16_t &L,
+ uint16_t &P);
+
+ /**
+ * Emit an encoded byte to the compressed data array. If the 2 high
+ * order bits can be signed extended, use 1 byte encoding, if not use 2
+ * bytes.
+ * @param dest The compressed data.
+ * @param byte The byte to emit.
+ * @return The number of bytes used to encode.
+ */
+ int emitByte(uint8_t *dest, uint8_t byte);
+
+ /**
+ * Emit a string reference to the compressed data array. A string reference
+ * always uses 3 bytes. 1 flag bit, 12 bits for the starting position, and
+ * 11 bits for the length of the string. This allows compression of 4096
+ * byte blocks with string lengths of up to 2048 bytes.
+ * @param dest The compressed data.
+ * @param P The starting position in the uncompressed data.
+ * @param L The length in bytes of the string.
+ */
+ void emitString(uint8_t *dest, uint16_t P, uint16_t L);
+
+ public:
+ /**
+ * Compresses the source block and stores it in the destination block. If
+ * the compressed block grows to larger than the source block, it aborts
+ * and just performs a copy.
+ * @param dest The destination block.
+ * @param src The block to be compressed.
+ * @param size The size of the source block.
+ * @return The size of the compressed block.
+ *
+ * @pre Destination has enough storage to hold the compressed block.
+ */
+ int compress(uint8_t *dest, uint8_t *src, int size);
+
+ /**
+ * Unompresses the source block and stores it in the destination block.
+ * @param dest The destination block.
+ * @param src The block to be uncompressed.
+ * @param size The size of the source block.
+ * @return The size of the uncompressed block.
+ *
+ * @pre Destination has enough storage to hold the uncompressed block.
+ */
+ int uncompress(uint8_t *dest, uint8_t *src, int size);
+};
+
+#endif //__LZSS_COMPRESSION_HH__
diff --git a/src/base/compression/null_compression.hh b/src/base/compression/null_compression.hh
new file mode 100644
index 000000000..5fbcf562b
--- /dev/null
+++ b/src/base/compression/null_compression.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__
+#define __BASE_COMPRESSION_NULL_COMPRESSION_HH__
+
+/**
+ * @file
+ * This file defines a doNothing compression algorithm.
+ */
+
+#include "base/misc.hh" // for fatal()
+#include "sim/host.hh"
+
+
+/**
+ * A dummy compression class to use when no data compression is desired.
+ */
+class NullCompression
+{
+ public:
+ /**
+ * Uncompress the data, causes a fatal since no data should be compressed.
+ * @param dest The output buffer.
+ * @param src The compressed data.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the uncompressed data.
+ */
+ static int uncompress(uint8_t * dest, uint8_t *src, int size)
+ {
+ fatal("Can't uncompress data");
+ }
+
+ /**
+ * Compress the data, just returns the source data.
+ * @param dest The output buffer.
+ * @param src The data to be compressed.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the compressed data.
+ */
+
+ static int compress(uint8_t *dest, uint8_t *src, int size)
+ {
+ memcpy(dest,src,size);
+ return size;
+ }
+};
+
+#endif //__BASE_COMPRESSION_NULL_COMPRESSION_HH__
diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc
new file mode 100644
index 000000000..cf332ebf2
--- /dev/null
+++ b/src/base/cprintf.cc
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "base/cprintf.hh"
+
+using namespace std;
+
+namespace cp {
+
+ArgList::~ArgList()
+{
+ while (!objects.empty()) {
+ delete objects.front();
+ objects.pop_front();
+ }
+}
+
+void
+ArgList::dump(const string &format)
+{
+ list_t::iterator iter = objects.begin();
+ list_t::iterator end = objects.end();
+
+ const char *p = format.c_str();
+
+ stream->fill(' ');
+ stream->flags((ios::fmtflags)0);
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ if (p[1] == '%') {
+ *stream << '%';
+ p += 2;
+ continue;
+ }
+
+ Format fmt;
+ bool done = false;
+ bool end_number = false;
+ bool have_precision = false;
+ int number = 0;
+
+ while (!done) {
+ ++p;
+ if (*p >= '0' && *p <= '9') {
+ if (end_number)
+ continue;
+ } else if (number > 0)
+ end_number = true;
+
+ switch (*p) {
+ case 's':
+ fmt.format = Format::string;
+ done = true;
+ break;
+
+ case 'c':
+ fmt.format = Format::character;
+ done = true;
+ break;
+
+ case 'l':
+ continue;
+
+ case 'p':
+ fmt.format = Format::integer;
+ fmt.base = Format::hex;
+ fmt.alternate_form = true;
+ done = true;
+ break;
+
+ case 'X':
+ fmt.uppercase = true;
+ case 'x':
+ fmt.base = Format::hex;
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'o':
+ fmt.base = Format::oct;
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'd':
+ case 'i':
+ case 'u':
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'G':
+ fmt.uppercase = true;
+ case 'g':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::best;
+ done = true;
+ break;
+
+ case 'E':
+ fmt.uppercase = true;
+ case 'e':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::scientific;
+ done = true;
+ break;
+
+ case 'f':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::fixed;
+ done = true;
+ break;
+
+ case 'n':
+ *stream << "we don't do %n!!!\n";
+ done = true;
+ break;
+
+ case '#':
+ fmt.alternate_form = true;
+ break;
+
+ case '-':
+ fmt.flush_left = true;
+ break;
+
+ case '+':
+ fmt.print_sign = true;
+ break;
+
+ case ' ':
+ fmt.blank_space = true;
+ break;
+
+ case '.':
+ fmt.width = number;
+ fmt.precision = 0;
+ have_precision = true;
+ number = 0;
+ end_number = false;
+ break;
+
+ case '0':
+ if (number == 0) {
+ fmt.fill_zero = true;
+ break;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ number = number * 10 + (*p - '0');
+ break;
+
+ case '%':
+ assert("we shouldn't get here");
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+
+ if (end_number) {
+ if (have_precision)
+ fmt.precision = number;
+ else
+ fmt.width = number;
+
+ end_number = false;
+ number = 0;
+ }
+ }
+
+ if (iter != end)
+ {
+ ios::fmtflags saved_flags = stream->flags();
+ char old_fill = stream->fill();
+ int old_precision = stream->precision();
+
+ (*iter)->process(*stream, fmt);
+
+ stream->flags(saved_flags);
+ stream->fill(old_fill);
+ stream->precision(old_precision);
+
+ ++iter;
+ } else {
+ *stream << "<missing arg for format>";
+ }
+
+ ++p;
+ }
+ break;
+
+ case '\n':
+ *stream << endl;
+ ++p;
+ break;
+ case '\r':
+ ++p;
+ if (*p != '\n')
+ *stream << endl;
+ break;
+
+ default: {
+ size_t len = strcspn(p, "%\n\r\0");
+ stream->write(p, len);
+ p += len;
+ }
+ break;
+ }
+ }
+
+ while (iter != end) {
+ *stream << "<extra arg>";
+ ++iter;
+ }
+}
+
+string
+ArgList::dumpToString(const string &format)
+{
+ stringstream ss;
+
+ dump(ss, format);
+
+ return ss.str();
+}
+
+}
diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh
new file mode 100644
index 000000000..c468c375f
--- /dev/null
+++ b/src/base/cprintf.hh
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPRINTF_HH__
+#define __CPRINTF_HH__
+
+#include <iostream>
+#include <list>
+#include <string>
+
+#include "base/cprintf_formats.hh"
+
+namespace cp {
+
+class ArgList
+{
+ private:
+ class Base
+ {
+ public:
+ virtual ~Base() {}
+ virtual void process(std::ostream &out, Format &fmt) = 0;
+ };
+
+ template <typename T>
+ class Node : public Base
+ {
+ public:
+ const T &data;
+
+ public:
+ Node(const T &d) : data(d) {}
+ virtual void process(std::ostream &out, Format &fmt) {
+ switch (fmt.format) {
+ case Format::character:
+ format_char(out, data, fmt);
+ break;
+
+ case Format::integer:
+ format_integer(out, data, fmt);
+ break;
+
+ case Format::floating:
+ format_float(out, data, fmt);
+ break;
+
+ case Format::string:
+ format_string(out, data, fmt);
+ break;
+
+ default:
+ out << "<bad format>";
+ break;
+ }
+ }
+ };
+
+ typedef std::list<Base *> list_t;
+
+ protected:
+ list_t objects;
+ std::ostream *stream;
+
+ public:
+ ArgList() : stream(&std::cout) {}
+ ~ArgList();
+
+ template<class T>
+ void append(const T &data) {
+ Base *obj = new ArgList::Node<T>(data);
+ objects.push_back(obj);
+ }
+
+ template<class T>
+ void prepend(const T &data) {
+ Base *obj = new ArgList::Node<T>(data);
+ objects.push_front(obj);
+ }
+
+ void dump(const std::string &format);
+ void dump(std::ostream &strm, const std::string &fmt)
+ { stream = &strm; dump(fmt); }
+
+ std::string dumpToString(const std::string &format);
+
+ friend ArgList &operator<<(std::ostream &str, ArgList &list);
+};
+
+template<class T>
+inline ArgList &
+operator,(ArgList &alist, const T &data)
+{
+ alist.append(data);
+ return alist;
+}
+
+class ArgListNull {
+};
+
+inline ArgList &
+operator,(ArgList &alist, ArgListNull)
+{ return alist; }
+
+//
+// cprintf(format, args, ...) prints to cout
+// (analogous to printf())
+//
+inline void
+__cprintf(const std::string &format, ArgList &args)
+{ args.dump(format); delete &args; }
+#define __cprintf__(format, args...) \
+ cp::__cprintf(format, (*(new cp::ArgList), args))
+#define cprintf(args...) \
+ __cprintf__(args, cp::ArgListNull())
+
+//
+// ccprintf(stream, format, args, ...) prints to the specified stream
+// (analogous to fprintf())
+//
+inline void
+__ccprintf(std::ostream &stream, const std::string &format, ArgList &args)
+{ args.dump(stream, format); delete &args; }
+#define __ccprintf__(stream, format, args...) \
+ cp::__ccprintf(stream, format, (*(new cp::ArgList), args))
+#define ccprintf(stream, args...) \
+ __ccprintf__(stream, args, cp::ArgListNull())
+
+//
+// csprintf(format, args, ...) returns a string
+// (roughly analogous to sprintf())
+//
+inline std::string
+__csprintf(const std::string &format, ArgList &args)
+{ std::string s = args.dumpToString(format); delete &args; return s; }
+#define __csprintf__(format, args...) \
+ cp::__csprintf(format, (*(new cp::ArgList), args))
+#define csprintf(args...) \
+ __csprintf__(args, cp::ArgListNull())
+
+template<class T>
+inline ArgList &
+operator<<(ArgList &list, const T &data)
+{
+ list.append(data);
+ return list;
+}
+
+inline ArgList &
+operator<<(std::ostream &str, ArgList &list)
+{
+ list.stream = &str;
+ return list;
+}
+
+class ArgListTemp
+{
+ private:
+ std::string format;
+ ArgList *args;
+
+ public:
+ ArgListTemp(const std::string &f) : format(f) { args = new ArgList; }
+ ~ArgListTemp() { args->dump(format); delete args; }
+
+ operator ArgList *() { return args; }
+};
+
+#define cformat(format) \
+ (*((cp::ArgList *)cp::ArgListTemp(format)))
+}
+
+#endif // __CPRINTF_HH__
diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh
new file mode 100644
index 000000000..05a8723a4
--- /dev/null
+++ b/src/base/cprintf_formats.hh
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPRINTF_FORMATS_HH__
+#define __CPRINTF_FORMATS_HH__
+
+#include <sstream>
+#include <ostream>
+
+namespace cp {
+
+struct Format
+{
+ bool alternate_form;
+ bool flush_left;
+ bool print_sign;
+ bool blank_space;
+ bool fill_zero;
+ bool uppercase;
+ enum { dec, hex, oct } base;
+ enum { none, string, integer, character, floating } format;
+ enum { best, fixed, scientific } float_format;
+ int precision;
+ int width;
+
+ Format() { clear(); }
+
+ void clear()
+ {
+ alternate_form = false;
+ flush_left = false;
+ print_sign = false;
+ blank_space = false;
+ fill_zero = false;
+ uppercase = false;
+ base = dec;
+ format = none;
+ precision = -1;
+ width = 0;
+ }
+};
+
+template <typename T>
+inline void
+_format_char(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_integer(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ switch (fmt.base) {
+ case Format::hex:
+ out.setf(ios::hex, ios::basefield);
+ break;
+
+ case Format::oct:
+ out.setf(ios::oct, ios::basefield);
+ break;
+
+ case Format::dec:
+ out.setf(ios::dec, ios::basefield);
+ break;
+ }
+
+ if (fmt.alternate_form) {
+ if (!fmt.fill_zero)
+ out.setf(ios::showbase);
+ else {
+ switch (fmt.base) {
+ case Format::hex:
+ out << "0x";
+ fmt.width -= 2;
+ break;
+ case Format::oct:
+ out << "0";
+ fmt.width -= 1;
+ break;
+ case Format::dec:
+ break;
+ }
+ }
+ }
+
+ if (fmt.fill_zero)
+ out.fill('0');
+
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.flush_left && !fmt.fill_zero)
+ out.setf(ios::left);
+
+ if (fmt.print_sign)
+ out.setf(ios::showpos);
+
+ if (fmt.uppercase)
+ out.setf(ios::uppercase);
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_float(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ switch (fmt.float_format) {
+ case Format::scientific:
+ if (fmt.precision != -1) {
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.precision == 0)
+ fmt.precision = 1;
+ else
+ out.setf(ios::scientific);
+
+ out.precision(fmt.precision);
+ } else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.uppercase)
+ out.setf(ios::uppercase);
+ break;
+
+ case Format::fixed:
+ if (fmt.precision != -1) {
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ out.setf(ios::fixed);
+ out.precision(fmt.precision);
+ } else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ break;
+
+ default:
+ if (fmt.precision != -1)
+ out.precision(fmt.precision);
+
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ break;
+ }
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_string(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+#if defined(__GNUC__) && (__GNUC__ < 3) || 1
+ if (fmt.width > 0) {
+ std::stringstream foo;
+ foo << data;
+ int flen = foo.str().size();
+
+ if (fmt.width > flen) {
+ char *spaces = new char[fmt.width - flen + 1];
+ memset(spaces, ' ', fmt.width - flen);
+ spaces[fmt.width - flen] = 0;
+
+ if (fmt.flush_left)
+ out << foo.str() << spaces;
+ else
+ out << spaces << foo.str();
+
+ delete [] spaces;
+ } else
+ out << data;
+ } else
+ out << data;
+#else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+ if (fmt.flush_left)
+ out.setf(ios::left);
+
+ out << data;
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// The code below controls the actual usage of formats for various types
+//
+
+//
+// character formats
+//
+template <typename T>
+inline void
+format_char(std::ostream &out, const T &data, Format &fmt)
+{ out << "<bad arg type for char format>"; }
+
+inline void
+format_char(std::ostream &out, char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, signed char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, short data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned short data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, int data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned int data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, long long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned long long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+//
+// integer formats
+//
+template <typename T>
+inline void
+format_integer(std::ostream &out, const T &data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, signed char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+#if 0
+inline void
+format_integer(std::ostream &out, short data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned short data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, int data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned int data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, long long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned long long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+#endif
+
+//
+// floating point formats
+//
+template <typename T>
+inline void
+format_float(std::ostream &out, const T &data, Format &fmt)
+{ out << "<bad arg type for float format>"; }
+
+inline void
+format_float(std::ostream &out, float data, Format &fmt)
+{ _format_float(out, data, fmt); }
+
+inline void
+format_float(std::ostream &out, double data, Format &fmt)
+{ _format_float(out, data, fmt); }
+
+//
+// string formats
+//
+template <typename T>
+inline void
+format_string(std::ostream &out, const T &data, Format &fmt)
+{ _format_string(out, data, fmt); }
+
+inline void
+format_string(std::ostream &out, const std::stringstream &data, Format &fmt)
+{ _format_string(out, data.str(), fmt); }
+
+} // namespace cp
+
+#endif // __CPRINTF_FORMATS_HH__
diff --git a/src/base/crc.cc b/src/base/crc.cc
new file mode 100644
index 000000000..08f039577
--- /dev/null
+++ b/src/base/crc.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1988, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <string>
+
+#include "sim/host.hh"
+#include "base/crc.hh"
+
+#define ETHER_CRC_POLY_LE 0xedb88320
+#define ETHER_CRC_POLY_BE 0x04c11db6
+
+#if 0
+/*
+ * This is for reference. We have a table-driven version
+ * of the little-endian crc32 generator, which is faster
+ * than the double-loop.
+ */
+uint32_t
+crc32le(const uint8_t *buf, size_t len)
+{
+ uint32_t c, crc, carry;
+ size_t i, j;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ c = buf[i];
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01);
+ crc >>= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ ETHER_CRC_POLY_LE);
+ }
+ }
+
+ return (crc);
+}
+#else
+uint32_t
+crc32le(const uint8_t *buf, size_t len)
+{
+ static const uint32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ uint32_t crc;
+ int i;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ crc ^= buf[i];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+
+ return (crc);
+}
+#endif
+
+uint32_t
+crc32be(const uint8_t *buf, size_t len)
+{
+ uint32_t c, crc, carry;
+ size_t i, j;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ c = buf[i];
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ ETHER_CRC_POLY_BE) | carry;
+ }
+ }
+
+ return (crc);
+}
diff --git a/src/base/crc.hh b/src/base/crc.hh
new file mode 100644
index 000000000..6ede07748
--- /dev/null
+++ b/src/base/crc.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_CRC_HH__
+#define __BASE_CRC_HH__
+
+#include "sim/host.hh"
+
+uint32_t crc32be(const uint8_t *buf, size_t len);
+uint32_t crc32le(const uint8_t *buf, size_t len);
+
+#endif // __BASE_CRC_HH__
diff --git a/src/base/date.cc b/src/base/date.cc
new file mode 100644
index 000000000..ba7698c29
--- /dev/null
+++ b/src/base/date.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+const char *compileDate = __DATE__ " " __TIME__;
diff --git a/src/base/dbl_list.hh b/src/base/dbl_list.hh
new file mode 100644
index 000000000..1d06ff576
--- /dev/null
+++ b/src/base/dbl_list.hh
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2000-2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DBL_LIST_HH__
+#define __DBL_LIST_HH__
+
+class DblListEl {
+ DblListEl *next;
+ DblListEl *prev;
+
+ // remove this from list
+ void remove() {
+ prev->next = next;
+ next->prev = prev;
+ }
+
+ // insert this before old_el
+ void insertBefore(DblListEl *old_el) {
+ prev = old_el->prev;
+ next = old_el;
+ prev->next = this;
+ next->prev = this;
+ }
+
+ // insert this after old_el
+ void insertAfter(DblListEl *old_el) {
+ next = old_el->next;
+ prev = old_el;
+ next->prev = this;
+ prev->next = this;
+ }
+
+ friend class DblListBase;
+};
+
+
+//
+// doubly-linked list of DblListEl objects
+//
+class DblListBase {
+ // dummy list head element: dummy.next is head, dummy.prev is tail
+ DblListEl dummy;
+
+ // length counter
+ unsigned length;
+
+ DblListEl *valid_or_null(DblListEl *el) {
+ // make sure users never see the dummy element
+ return (el == &dummy) ? NULL : el;
+ }
+
+ public:
+
+ DblListEl *head() {
+ return valid_or_null(dummy.next);
+ }
+
+ DblListEl *tail() {
+ return valid_or_null(dummy.prev);
+ }
+
+ DblListEl *next(DblListEl *el) {
+ return valid_or_null(el->next);
+ }
+
+ DblListEl *prev(DblListEl *el) {
+ return valid_or_null(el->prev);
+ }
+
+ bool is_empty() {
+ return (dummy.next == &dummy);
+ }
+
+ void remove(DblListEl *el) {
+ el->remove();
+ --length;
+ }
+
+ void insertBefore(DblListEl *new_el, DblListEl *old_el) {
+ new_el->insertBefore(old_el);
+ ++length;
+ }
+
+ void insertAfter(DblListEl *new_el, DblListEl *old_el) {
+ new_el->insertAfter(old_el);
+ ++length;
+ }
+
+ // append to end of list, i.e. as dummy.prev
+ void append(DblListEl *el) {
+ insertBefore(el, &dummy);
+ }
+
+ // prepend to front of list (push), i.e. as dummy.next
+ void prepend(DblListEl *el) {
+ insertAfter(el, &dummy);
+ }
+
+ DblListEl *pop() {
+ DblListEl *hd = head();
+ if (hd != NULL)
+ remove(hd);
+ return hd;
+ }
+
+ // constructor
+ DblListBase() {
+ dummy.next = dummy.prev = &dummy;
+ length = 0;
+ }
+};
+
+
+//
+// Template class serves solely to cast args & return values
+// to appropriate type (T *)
+//
+template<class T> class DblList : private DblListBase {
+
+ public:
+
+ T *head() { return (T *)DblListBase::head(); }
+ T *tail() { return (T *)DblListBase::tail(); }
+
+ T *next(T *el) { return (T *)DblListBase::next(el); }
+ T *prev(T *el) { return (T *)DblListBase::prev(el); }
+
+ bool is_empty() { return DblListBase::is_empty(); }
+
+ void remove(T *el) { DblListBase::remove(el); }
+
+ void append(T *el) { DblListBase::append(el); }
+ void prepend(T *el) { DblListBase::prepend(el); }
+
+ T *pop() { return (T *)DblListBase::pop(); }
+
+ DblList<T>() { }
+};
+
+#endif // __DBL_LIST_HH__
diff --git a/src/base/endian.hh b/src/base/endian.hh
new file mode 100644
index 000000000..499eb50c5
--- /dev/null
+++ b/src/base/endian.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ENDIAN_HH__
+#define __ENDIAN_HH__
+
+#include <arpa/inet.h>
+
+inline bool
+HostBigEndian()
+{
+ int x = 0x11223344;
+ return x == htonl(x);
+}
+
+#endif // __ENDIAN_HH__
diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc
new file mode 100644
index 000000000..6504e07c2
--- /dev/null
+++ b/src/base/fast_alloc.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2000-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.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifndef NO_FAST_ALLOC
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "base/fast_alloc.hh"
+
+void *FastAlloc::freeLists[Num_Buckets];
+
+#ifdef FAST_ALLOC_STATS
+unsigned FastAlloc::newCount[Num_Buckets];
+unsigned FastAlloc::deleteCount[Num_Buckets];
+unsigned FastAlloc::allocCount[Num_Buckets];
+#endif
+
+void *FastAlloc::moreStructs(int bucket)
+{
+ assert(bucket > 0 && bucket < Num_Buckets);
+
+ int sz = bucket * Alloc_Quantum;
+ const int nstructs = Num_Structs_Per_New; // how many to allocate?
+ char *p = ::new char[nstructs * sz];
+
+#ifdef FAST_ALLOC_STATS
+ ++allocCount[bucket];
+#endif
+
+ freeLists[bucket] = p;
+ for (int i = 0; i < (nstructs-2); ++i, p += sz)
+ *(void **)p = p + sz;
+ *(void **)p = 0;
+
+ return (p + sz);
+}
+
+
+#ifdef FAST_ALLOC_DEBUG
+
+#include <typeinfo>
+#include <iostream>
+#include <iomanip>
+#include <map>
+#include <string>
+
+using namespace std;
+
+// count of in-use FastAlloc objects
+int FastAlloc::numInUse;
+
+// dummy head & tail object for doubly linked list of in-use FastAlloc
+// objects
+FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);
+
+// special constructor for dummy head: make inUsePrev & inUseNext
+// point to self
+FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
+{
+ inUsePrev = prev;
+ inUseNext = next;
+}
+
+
+// constructor: marks as in use, add to in-use list
+FastAlloc::FastAlloc()
+{
+ // mark this object in use
+ inUse = true;
+
+ // update count
+ ++numInUse;
+
+ // add to tail of list of in-use objects ("before" dummy head)
+ FastAlloc *myNext = &inUseHead;
+ FastAlloc *myPrev = inUseHead.inUsePrev;
+
+ inUsePrev = myPrev;
+ inUseNext = myNext;
+ myPrev->inUseNext = this;
+ myNext->inUsePrev = this;
+}
+
+// destructor: mark not in use, remove from in-use list
+FastAlloc::~FastAlloc()
+{
+ assert(inUse);
+ inUse = false;
+
+ --numInUse;
+ assert(numInUse >= 0);
+
+ // remove me from in-use list
+ inUsePrev->inUseNext = inUseNext;
+ inUseNext->inUsePrev = inUsePrev;
+}
+
+
+// summarize in-use list
+void
+FastAlloc::dump_summary()
+{
+ map<string, int> typemap;
+
+ for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
+ {
+ ++typemap[typeid(*p).name()];
+ }
+
+ map<string, int>::const_iterator mapiter;
+
+ cout << " count type\n"
+ << " ----- ----\n";
+ for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
+ {
+ cout << setw(6) << mapiter->second << " " << mapiter->first << endl;
+ }
+}
+
+
+// show oldest n items on in-use list
+void
+FastAlloc::dump_oldest(int n)
+{
+ // sanity check: don't want to crash the debugger if you forget to
+ // pass in a parameter
+ if (n < 0 || n > numInUse)
+ {
+ cout << "FastAlloc::dump_oldest: bad arg " << n
+ << " (" << numInUse << " objects in use" << endl;
+ return;
+ }
+
+ for (FastAlloc *p = inUseHead.inUsePrev;
+ p != &inUseHead && n > 0;
+ p = p->inUsePrev, --n)
+ {
+ cout << p << " " << typeid(*p).name() << endl;
+ }
+}
+
+
+//
+// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
+// gdb seems to have trouble with calling C++ functions directly.
+//
+extern "C" void
+fast_alloc_summary()
+{
+ FastAlloc::dump_summary();
+}
+
+extern "C" void
+fast_alloc_oldest(int n)
+{
+ FastAlloc::dump_oldest(n);
+}
+
+#endif
+
+#endif // NO_FAST_ALLOC
diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh
new file mode 100644
index 000000000..54e35f8e0
--- /dev/null
+++ b/src/base/fast_alloc.hh
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2000-2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifndef __FAST_ALLOC_H__
+#define __FAST_ALLOC_H__
+
+#include <stddef.h>
+
+// Fast structure allocator. Designed for small objects that are
+// frequently allocated and deallocated. This code is derived from the
+// 'alloc_struct' package used in WWT and Blizzard. C++ provides a
+// much nicer framework for the same optimization. The package is
+// implemented as a class, FastAlloc. Allocation and deletion are
+// performed using FastAlloc's new and delete operators. Any object
+// that derives from the FastAlloc class will transparently use this
+// allocation package.
+
+// The static allocate() and deallocate() methods can also be called
+// directly if desired.
+
+// In order for derived classes to call delete with the correct
+// structure size even when they are deallocated via a base-type
+// pointer, they must have a virtual destructor. It is sufficient for
+// FastAlloc to declare a virtual destructor (as it does); it is not
+// required for derived classes to declare their own destructor. The
+// compiler will automatically generate a virtual destructor for each
+// derived class. However, it is more efficient if each derived class
+// defines an inline destructor, so that the compiler can statically
+// collapse the destructor call chain back up the inheritance
+// hierarchy.
+
+// Uncomment this #define to track in-use objects
+// (for debugging memory leaks).
+//#define FAST_ALLOC_DEBUG
+
+// Uncomment this #define to count news, deletes, and chunk allocations
+// (by bucket).
+// #define FAST_ALLOC_STATS
+
+#include "config/no_fast_alloc.hh"
+
+#if NO_FAST_ALLOC
+
+class FastAlloc {
+};
+
+#else
+
+class FastAlloc {
+ public:
+
+ static void *allocate(size_t);
+ static void deallocate(void *, size_t);
+
+ void *operator new(size_t);
+ void operator delete(void *, size_t);
+
+#ifdef FAST_ALLOC_DEBUG
+ FastAlloc();
+ FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below
+ virtual ~FastAlloc();
+#else
+ virtual ~FastAlloc() {}
+#endif
+
+ private:
+
+ // Max_Alloc_Size is the largest object that can be allocated with
+ // this class. There's no fundamental limit, but this limits the
+ // size of the freeLists array. Let's not make this really huge
+ // like in Blizzard.
+ static const int Max_Alloc_Size = 512;
+
+ // Alloc_Quantum is the difference in size between adjacent
+ // buckets in the free list array.
+ static const int Log2_Alloc_Quantum = 3;
+ static const int Alloc_Quantum = (1 << Log2_Alloc_Quantum);
+
+ // Num_Buckets = bucketFor(Max_Alloc_Size) + 1
+ static const int Num_Buckets =
+ ((Max_Alloc_Size + Alloc_Quantum - 1) >> Log2_Alloc_Quantum) + 1;
+
+ // when we call new() for more structures, how many should we get?
+ static const int Num_Structs_Per_New = 20;
+
+ static int bucketFor(size_t);
+ static void *moreStructs(int bucket);
+
+ static void *freeLists[Num_Buckets];
+
+#ifdef FAST_ALLOC_STATS
+ static unsigned newCount[Num_Buckets];
+ static unsigned deleteCount[Num_Buckets];
+ static unsigned allocCount[Num_Buckets];
+#endif
+
+#ifdef FAST_ALLOC_DEBUG
+ // per-object debugging fields
+ bool inUse; // in-use flag
+ FastAlloc *inUsePrev; // ptrs to build list of in-use objects
+ FastAlloc *inUseNext;
+
+ // static (global) debugging vars
+ static int numInUse; // count in-use objects
+ static FastAlloc inUseHead; // dummy head for list of in-use objects
+
+ public:
+ // functions to dump debugging info (see fast_alloc.cc for C
+ // versions that might be more agreeable to call from gdb)
+ static void dump_summary();
+ static void dump_oldest(int n);
+#endif
+};
+
+
+inline
+int FastAlloc::bucketFor(size_t sz)
+{
+ return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum;
+}
+
+
+inline
+void *FastAlloc::allocate(size_t sz)
+{
+ int b;
+ void *p;
+
+ if (sz > Max_Alloc_Size)
+ return (void *)::new char[sz];
+
+ b = bucketFor(sz);
+ p = freeLists[b];
+
+ if (p)
+ freeLists[b] = *(void **)p;
+ else
+ p = moreStructs(b);
+
+#ifdef FAST_ALLOC_STATS
+ ++newCount[b];
+#endif
+
+ return p;
+}
+
+
+inline
+void FastAlloc::deallocate(void *p, size_t sz)
+{
+ int b;
+
+ if (sz > Max_Alloc_Size)
+ {
+ ::delete [] (char *)p;
+ return;
+ }
+
+ b = bucketFor(sz);
+ *(void **)p = freeLists[b];
+ freeLists[b] = p;
+#ifdef FAST_ALLOC_STATS
+ ++deleteCount[b];
+#endif
+}
+
+
+inline
+void *FastAlloc::operator new(size_t sz)
+{
+ return allocate(sz);
+}
+
+
+inline
+void FastAlloc::operator delete(void *p, size_t sz)
+{
+ deallocate(p, sz);
+}
+
+#endif // NO_FAST_ALLOC
+
+#endif // __FAST_ALLOC_H__
diff --git a/src/base/fenv.hh b/src/base/fenv.hh
new file mode 100644
index 000000000..3234f5dd3
--- /dev/null
+++ b/src/base/fenv.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_FENV_HH__
+#define __BASE_FENV_HH__
+
+#include "config/use_fenv.hh"
+
+#if USE_FENV
+
+#include <fenv.h>
+
+#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; }
+
+#endif // USE_FENV
+
+
+#endif // __BASE_FENV_HH__
diff --git a/src/base/fifo_buffer.cc b/src/base/fifo_buffer.cc
new file mode 100644
index 000000000..85b306c25
--- /dev/null
+++ b/src/base/fifo_buffer.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/fifo_buffer.hh"
+
+template<class T>
+void
+FifoBuffer<T>::dump()
+{
+ if (buffer->count() > 0)
+ for (iterator i=buffer->tail(); i.notnull(); i=i.prev())
+ i->dump();
+}
+
+
diff --git a/src/base/fifo_buffer.hh b/src/base/fifo_buffer.hh
new file mode 100644
index 000000000..03ce057c7
--- /dev/null
+++ b/src/base/fifo_buffer.hh
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FIFO_BUFFER_HH__
+#define __FIFO_BUFFER_HH__
+
+#include "base/res_list.hh"
+
+
+//
+// The FifoBuffer requires only that the objects to be used have a default
+// constructor and a dump() method
+//
+template<class T>
+class FifoBuffer
+{
+ public:
+ typedef typename res_list<T>::iterator iterator;
+
+ private:
+ res_list<T> *buffer;
+
+ unsigned size;
+
+ public:
+ FifoBuffer(unsigned sz)
+ {
+ buffer = new res_list<T>(sz, true, 0);
+ size = sz;
+ }
+
+ void add(T &item)
+ {
+ assert(buffer->num_free() > 0);
+ buffer->add_head(item);
+ }
+
+ iterator head() { return buffer->head(); }
+ iterator tail() { return buffer->tail(); }
+
+ unsigned count() {return buffer->count();}
+ unsigned free_slots() {return buffer->num_free();}
+
+ T *peek() { return (count() > 0) ? tail().data_ptr() : 0; }
+
+ T remove()
+ {
+ assert(buffer->count() > 0);
+ T rval = *buffer->tail();
+ buffer->remove_tail();
+ return rval;
+ }
+
+ void dump();
+
+ ~FifoBuffer() { delete buffer; }
+};
+
+
+#endif
+
diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh
new file mode 100644
index 000000000..712366829
--- /dev/null
+++ b/src/base/hashmap.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HASHMAP_HH__
+#define __HASHMAP_HH__
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#include <ext/hash_map>
+#else
+#include <hash_map>
+#endif
+
+#include <string>
+
+#include "sim/host.hh"
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+ #define __hash_namespace __gnu_cxx
+#else
+ #define __hash_namespace std
+#endif
+
+namespace m5 {
+ using ::__hash_namespace::hash_multimap;
+ using ::__hash_namespace::hash_map;
+ using ::__hash_namespace::hash;
+}
+
+
+///////////////////////////////////
+// Some default Hashing Functions
+//
+
+namespace __hash_namespace {
+#if !defined(__LP64__) && !defined(__alpha__)
+ template<>
+ struct hash<uint64_t> {
+ size_t operator()(uint64_t r) const {
+ return r;
+ }
+ };
+
+ template<>
+ struct hash<int64_t> {
+ size_t operator()(int64_t r) const {
+ return r;
+ };
+ };
+#endif
+
+ template<>
+ struct hash<std::string> {
+ size_t operator()(const std::string &s) const {
+ return(__stl_hash_string(s.c_str()));
+ }
+ };
+}
+
+
+#endif // __HASHMAP_HH__
diff --git a/src/base/hostinfo.cc b/src/base/hostinfo.cc
new file mode 100644
index 000000000..d42c96732
--- /dev/null
+++ b/src/base/hostinfo.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "base/misc.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+string
+__get_hostname()
+{
+ char host[256];
+ if (gethostname(host, sizeof host) == -1)
+ warn("could not get host name!");
+ return host;
+}
+
+string &
+hostname()
+{
+ static string hostname = __get_hostname();
+ return hostname;
+}
+
+uint64_t
+procInfo(char *filename, char *target)
+{
+ int done = 0;
+ char line[80];
+ char format[80];
+ long usage;
+
+ FILE *fp = fopen(filename, "r");
+
+ while (fp && !feof(fp) && !done) {
+ if (fgets(line, 80, fp)) {
+ if (strncmp(line, target, strlen(target)) == 0) {
+ snprintf(format, sizeof(format), "%s %%ld", target);
+ sscanf(line, format, &usage);
+
+ fclose(fp);
+ return usage ;
+ }
+ }
+ }
+
+ if (fp)
+ fclose(fp);
+
+ return 0;
+}
diff --git a/src/base/hostinfo.hh b/src/base/hostinfo.hh
new file mode 100644
index 000000000..21a6e5475
--- /dev/null
+++ b/src/base/hostinfo.hh
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HOSTINFO_HH__
+#define __HOSTINFO_HH__
+
+#include <string>
+
+#include "sim/host.hh"
+
+std::string &hostname();
+
+uint64_t procInfo(char *filename, char *target);
+
+inline uint64_t memUsage()
+{ return procInfo("/proc/self/status", "VmSize:"); }
+
+#endif // __HOSTINFO_HH__
diff --git a/src/base/hybrid_pred.cc b/src/base/hybrid_pred.cc
new file mode 100644
index 000000000..21cbdb0fd
--- /dev/null
+++ b/src/base/hybrid_pred.cc
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <sstream>
+
+#include "base/hybrid_pred.hh"
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+
+HybridPredictor::HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits,
+ unsigned _global_thresh,
+ bool _reg_individual_stats)
+{
+ stringstream local_name, global_name;
+
+ pred_name = _p_name;
+ one_name = _o_name;
+ zero_name = _z_name;
+ reg_individual_stats = _reg_individual_stats;
+
+ local_name << pred_name.c_str() << ":L";
+ local = new SaturatingCounterPred(local_name.str(), zero_name, one_name,
+ _index_bits, _counter_bits,
+ _zero_change, _one_change, _thresh);
+
+ global_name << pred_name.c_str() << ":G";
+ global = new SaturatingCounterPred(global_name.str(), zero_name, one_name,
+ 0, _global_bits, 1, 1, _global_thresh);
+}
+
+void HybridPredictor::regStats()
+{
+ using namespace Stats;
+
+ string p_name;
+ stringstream description;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+
+ //
+ // Number of predictions
+ //
+ stringstream num_zero_preds;
+ num_zero_preds << p_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ pred_zero
+ .name(num_zero_preds.str())
+ .desc(description.str());
+ description.str("");
+
+ stringstream num_one_preds;
+ num_one_preds << p_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ pred_one
+ .name(num_one_preds.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ stringstream num_zero_correct;
+ num_zero_correct << p_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds" ;
+ correct_pred_zero
+ .name(num_zero_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_correct;
+ num_one_correct << p_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds" ;
+ correct_pred_one
+ .name(num_one_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+
+ //
+ // Number of predictor updates
+ //
+ stringstream num_zero_updates;
+ num_zero_updates << p_name << ":" << zero_name << ":updates" ;
+ description << "number of actual " << zero_name << "s" ;
+ record_zero
+ .name(num_zero_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_updates;
+ num_one_updates << p_name << ":" << one_name << ":updates" ;
+ description << "number of actual " << one_name << "s" ;
+ record_one
+ .name(num_one_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regStats();
+ global->regStats();
+ }
+}
+
+void HybridPredictor::regFormulas()
+{
+ using namespace Stats;
+
+ string p_name;
+ stringstream description;
+ stringstream name;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+ //
+ // Number of predictions
+ //
+ name << p_name << ":predictions" ;
+ total_preds
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ total_preds = pred_one + pred_zero;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << p_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name ;
+ frac_preds_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_zero = 100 * record_zero / total_preds;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name ;
+ frac_preds_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_one = 100 * record_one / total_preds;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << p_name << ":correct_preds" ;
+ total_correct
+ .name(name.str())
+ .desc("total number of correct predictions made")
+ ;
+ total_correct = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+
+ //
+ // Prediction accuracy rates
+ //
+ name << p_name << ":pred_rate";
+ total_accuracy
+ .name(name.str())
+ .desc("fraction of all preds that were correct")
+ ;
+ total_accuracy = 100 * total_correct / total_preds;
+ name.str("");
+
+ name << p_name << ":" << zero_name << ":pred_rate" ;
+ description << "fraction of "<< zero_name <<" preds that were correct";
+ zero_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_accuracy = 100 * correct_pred_zero / pred_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_rate" ;
+ description << "fraction of "<< one_name <<" preds that were correct";
+ one_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_accuracy = 100 * correct_pred_one / pred_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << p_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ zero_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_coverage = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ one_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_coverage = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regFormulas();
+ global->regFormulas();
+ }
+
+}
+
diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh
new file mode 100644
index 000000000..ea4a9d04c
--- /dev/null
+++ b/src/base/hybrid_pred.hh
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+//==========================================================================
+//
+// This predictor takes the AND of a "local" and a "global" predictor
+// in order to determine its prediction.
+//
+//
+//
+//
+
+#ifndef __HYBRID_PRED_HH__
+#define __HYBRID_PRED_HH__
+
+#include <string>
+
+#include "base/sat_counter.hh"
+#include "base/statistics.hh"
+
+class HybridPredictor : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string one_name;
+ std::string zero_name;
+ bool reg_individual_stats;
+
+ SaturatingCounterPred *local;
+ SaturatingCounterPred *global;
+
+ unsigned long max_index;
+
+ //
+ // Stats
+ //
+ Stats::Scalar<> pred_one; //num_one_preds
+ Stats::Scalar<> pred_zero; //num_zero_preds
+ Stats::Scalar<> correct_pred_one; //num_one_correct
+ Stats::Scalar<> correct_pred_zero; //num_zero_correct
+ Stats::Scalar<> record_one; //num_one_updates
+ Stats::Scalar<> record_zero; //num_zero_updates
+
+ Stats::Formula total_preds;
+ Stats::Formula frac_preds_zero;
+ Stats::Formula frac_preds_one;
+ Stats::Formula total_correct;
+ Stats::Formula total_accuracy;
+ Stats::Formula zero_accuracy;
+ Stats::Formula one_accuracy;
+ Stats::Formula zero_coverage;
+ Stats::Formula one_coverage;
+
+ public:
+ HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits, unsigned _global_thresh,
+ bool _reg_individual_stats = false);
+
+ void clear() {
+ global->clear();
+ local->clear();
+ }
+
+ unsigned peek(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ if (l && g)
+ return 1;
+
+ return 0;
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ l = l & 0xFFFF;
+ g = g & 0xFFFF;
+
+ return (l << 16) | g;
+
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+
+ //
+ // This version need only be used if local/global statistics
+ // will be maintained
+ //
+ unsigned predict(unsigned long _index, unsigned &_pdata) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ //
+ // bit 0 => local predictor result
+ // bit 1 => global predictor result
+ //
+ _pdata = 0;
+ if (l)
+ _pdata |= 1;
+ if (g)
+ _pdata |= 2;
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+
+ if (_val) {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_one;
+
+ if (_val == _predicted) {
+ ++correct_pred_one;
+ }
+ } else {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+
+ local->record(_index, _val, (_pdata & 1));
+ global->record(_index, _val, ((_pdata & 2) ? 1 : 0));
+
+
+ if (_val) {
+ ++record_one;
+
+ if (_val == _predicted)
+ ++correct_pred_one;
+ } else {
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // _HYBRID_PRED_HH__
+
diff --git a/src/base/inet.cc b/src/base/inet.cc
new file mode 100644
index 000000000..f2665bd2b
--- /dev/null
+++ b/src/base/inet.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+#include <string>
+
+#include "base/cprintf.hh"
+#include "sim/host.hh"
+#include "base/inet.hh"
+
+using namespace std;
+namespace Net {
+
+EthAddr::EthAddr()
+{
+ memset(data, 0, ETH_ADDR_LEN);
+}
+
+EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN])
+{
+ *data = *ea;
+}
+
+EthAddr::EthAddr(const eth_addr &ea)
+{
+ *data = *ea.data;
+}
+
+EthAddr::EthAddr(const std::string &addr)
+{
+ parse(addr);
+}
+
+const EthAddr &
+EthAddr::operator=(const eth_addr &ea)
+{
+ *data = *ea.data;
+ return *this;
+}
+
+const EthAddr &
+EthAddr::operator=(const std::string &addr)
+{
+ parse(addr);
+ return *this;
+}
+
+void
+EthAddr::parse(const std::string &addr)
+{
+ // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise
+ // the sscanf function won't work.
+ int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1];
+ if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1],
+ &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) {
+ memset(data, 0xff, ETH_ADDR_LEN);
+ return;
+ }
+
+ for (int i = 0; i < ETH_ADDR_LEN; ++i) {
+ if (bytes[i] & ~0xff) {
+ memset(data, 0xff, ETH_ADDR_LEN);
+ return;
+ }
+
+ data[i] = bytes[i];
+ }
+}
+
+string
+EthAddr::string() const
+{
+ stringstream stream;
+ stream << *this;
+ return stream.str();
+}
+
+bool
+operator==(const EthAddr &left, const EthAddr &right)
+{
+ return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN);
+}
+
+ostream &
+operator<<(ostream &stream, const EthAddr &ea)
+{
+ const uint8_t *a = ea.addr();
+ ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
+ return stream;
+}
+
+uint16_t
+cksum(const IpPtr &ptr)
+{
+ int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0);
+ return ip_cksum_carry(sum);
+}
+
+uint16_t
+__tu_cksum(const IpPtr &ip)
+{
+ int tcplen = ip->len() - ip->hlen();
+ int sum = ip_cksum_add(ip->payload(), tcplen, 0);
+ sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination
+ sum += htons(ip->ip_p + tcplen);
+ return ip_cksum_carry(sum);
+}
+
+uint16_t
+cksum(const TcpPtr &tcp)
+{ return __tu_cksum(IpPtr(tcp.packet())); }
+
+uint16_t
+cksum(const UdpPtr &udp)
+{ return __tu_cksum(IpPtr(udp.packet())); }
+
+bool
+IpHdr::options(vector<const IpOpt *> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct ip_hdr);
+ int all = hlen() - sizeof(struct ip_hdr);
+ while (all > 0) {
+ const IpOpt *opt = (const IpOpt *)data;
+ int len = opt->len();
+ if (all < len)
+ return false;
+
+ vec.push_back(opt);
+ all -= len;
+ data += len;
+ }
+
+ return true;
+}
+
+bool
+TcpHdr::options(vector<const TcpOpt *> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct tcp_hdr);
+ int all = off() - sizeof(struct tcp_hdr);
+ while (all > 0) {
+ const TcpOpt *opt = (const TcpOpt *)data;
+ int len = opt->len();
+ if (all < len)
+ return false;
+
+ vec.push_back(opt);
+ all -= len;
+ data += len;
+ }
+
+ return true;
+}
+
+bool
+TcpOpt::sack(vector<SackRange> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct tcp_hdr);
+ int all = len() - offsetof(tcp_opt, opt_data.sack);
+ while (all > 0) {
+ const uint16_t *sack = (const uint16_t *)data;
+ int len = sizeof(uint16_t) * 2;
+ if (all < len) {
+ vec.clear();
+ return false;
+ }
+
+ vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1])));
+ all -= len;
+ data += len;
+ }
+
+ return false;
+}
+
+/* namespace Net */ }
diff --git a/src/base/inet.hh b/src/base/inet.hh
new file mode 100644
index 000000000..e5d0473f9
--- /dev/null
+++ b/src/base/inet.hh
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_INET_HH__
+#define __BASE_INET_HH__
+
+#include <iosfwd>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/range.hh"
+#include "dev/etherpkt.hh"
+#include "sim/host.hh"
+
+#include "dnet/os.h"
+#include "dnet/eth.h"
+#include "dnet/ip.h"
+#include "dnet/ip6.h"
+#include "dnet/addr.h"
+#include "dnet/arp.h"
+#include "dnet/icmp.h"
+#include "dnet/tcp.h"
+#include "dnet/udp.h"
+#include "dnet/intf.h"
+#include "dnet/route.h"
+#include "dnet/fw.h"
+#include "dnet/blob.h"
+#include "dnet/rand.h"
+
+namespace Net {
+
+/*
+ * Ethernet Stuff
+ */
+struct EthAddr : protected eth_addr
+{
+ protected:
+ void parse(const std::string &addr);
+
+ public:
+ EthAddr();
+ EthAddr(const uint8_t ea[ETH_ADDR_LEN]);
+ EthAddr(const eth_addr &ea);
+ EthAddr(const std::string &addr);
+ const EthAddr &operator=(const eth_addr &ea);
+ const EthAddr &operator=(const std::string &addr);
+
+ int size() const { return sizeof(eth_addr); }
+
+ const uint8_t *bytes() const { return &data[0]; }
+ uint8_t *bytes() { return &data[0]; }
+
+ const uint8_t *addr() const { return &data[0]; }
+ bool unicast() const { return data[0] == 0x00; }
+ bool multicast() const { return data[0] == 0x01; }
+ bool broadcast() const { return data[0] == 0xff; }
+ std::string string() const;
+
+ operator uint64_t() const
+ {
+ uint64_t reg = 0;
+ reg |= ((uint64_t)data[0]) << 40;
+ reg |= ((uint64_t)data[1]) << 32;
+ reg |= ((uint64_t)data[2]) << 24;
+ reg |= ((uint64_t)data[3]) << 16;
+ reg |= ((uint64_t)data[4]) << 8;
+ reg |= ((uint64_t)data[5]) << 0;
+ return reg;
+ }
+
+};
+
+std::ostream &operator<<(std::ostream &stream, const EthAddr &ea);
+bool operator==(const EthAddr &left, const EthAddr &right);
+
+struct EthHdr : public eth_hdr
+{
+ uint16_t type() const { return ntohs(eth_type); }
+ const EthAddr &src() const { return *(EthAddr *)&eth_src; }
+ const EthAddr &dst() const { return *(EthAddr *)&eth_dst; }
+
+ int size() const { return sizeof(eth_hdr); }
+
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class EthPtr
+{
+ protected:
+ friend class IpPtr;
+ EthPacketPtr p;
+
+ public:
+ EthPtr() {}
+ EthPtr(const EthPacketPtr &ptr) : p(ptr) { }
+
+ EthHdr *operator->() { return (EthHdr *)p->data; }
+ EthHdr &operator*() { return *(EthHdr *)p->data; }
+ operator EthHdr *() { return (EthHdr *)p->data; }
+
+ const EthHdr *operator->() const { return (const EthHdr *)p->data; }
+ const EthHdr &operator*() const { return *(const EthHdr *)p->data; }
+ operator const EthHdr *() const { return (const EthHdr *)p->data; }
+
+ const EthPtr &operator=(const EthPacketPtr &ptr) { p = ptr; return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+};
+
+/*
+ * IP Stuff
+ */
+struct IpOpt;
+struct IpHdr : public ip_hdr
+{
+ uint8_t version() const { return ip_v; }
+ uint8_t hlen() const { return ip_hl * 4; }
+ uint8_t tos() const { return ip_tos; }
+ uint16_t len() const { return ntohs(ip_len); }
+ uint16_t id() const { return ntohs(ip_id); }
+ uint16_t frag_flags() const { return ntohs(ip_off) >> 13; }
+ uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; }
+ uint8_t ttl() const { return ip_ttl; }
+ uint8_t proto() const { return ip_p; }
+ uint16_t sum() const { return ip_sum; }
+ uint32_t src() const { return ntohl(ip_src); }
+ uint32_t dst() const { return ntohl(ip_dst); }
+
+ void sum(uint16_t sum) { ip_sum = sum; }
+
+ bool options(std::vector<const IpOpt *> &vec) const;
+
+ int size() const { return hlen(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class IpPtr
+{
+ protected:
+ friend class TcpPtr;
+ friend class UdpPtr;
+ EthPacketPtr p;
+
+ const IpHdr *h() const
+ { return (const IpHdr *)(p->data + sizeof(eth_hdr)); }
+ IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); }
+
+ void set(const EthPacketPtr &ptr)
+ {
+ EthHdr *eth = (EthHdr *)ptr->data;
+ if (eth->type() == ETH_TYPE_IP)
+ p = ptr;
+ else
+ p = 0;
+ }
+
+ public:
+ IpPtr() {}
+ IpPtr(const EthPacketPtr &ptr) { set(ptr); }
+ IpPtr(const EthPtr &ptr) { set(ptr.p); }
+ IpPtr(const IpPtr &ptr) : p(ptr.p) { }
+
+ IpHdr *operator->() { return h(); }
+ IpHdr &operator*() { return *h(); }
+ operator IpHdr *() { return h(); }
+
+ const IpHdr *operator->() const { return h(); }
+ const IpHdr &operator*() const { return *h(); }
+ operator const IpHdr *() const { return h(); }
+
+ const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; }
+ const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; }
+ const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const IpPtr &ptr);
+
+struct IpOpt : public ip_opt
+{
+ uint8_t type() const { return opt_type; }
+ uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); }
+ uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); }
+ uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); }
+ uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
+
+ bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); }
+ bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); }
+ bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); }
+
+ const uint8_t *data() const { return opt_data.data8; }
+ void sec(ip_opt_data_sec &sec) const;
+ void lsrr(ip_opt_data_rr &rr) const;
+ void ssrr(ip_opt_data_rr &rr) const;
+ void ts(ip_opt_data_ts &ts) const;
+ uint16_t satid() const { return ntohs(opt_data.satid); }
+ uint16_t mtup() const { return ntohs(opt_data.mtu); }
+ uint16_t mtur() const { return ntohs(opt_data.mtu); }
+ void tr(ip_opt_data_tr &tr) const;
+ const uint32_t *addext() const { return &opt_data.addext[0]; }
+ uint16_t rtralt() const { return ntohs(opt_data.rtralt); }
+ void sdb(std::vector<uint32_t> &vec) const;
+};
+
+/*
+ * TCP Stuff
+ */
+struct TcpOpt;
+struct TcpHdr : public tcp_hdr
+{
+ uint16_t sport() const { return ntohs(th_sport); }
+ uint16_t dport() const { return ntohs(th_dport); }
+ uint32_t seq() const { return ntohl(th_seq); }
+ uint32_t ack() const { return ntohl(th_ack); }
+ uint8_t off() const { return th_off; }
+ uint8_t flags() const { return th_flags & 0x3f; }
+ uint16_t win() const { return ntohs(th_win); }
+ uint16_t sum() const { return th_sum; }
+ uint16_t urp() const { return ntohs(th_urp); }
+
+ void sum(uint16_t sum) { th_sum = sum; }
+
+ bool options(std::vector<const TcpOpt *> &vec) const;
+
+ int size() const { return off(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class TcpPtr
+{
+ protected:
+ EthPacketPtr p;
+ int off;
+
+ const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); }
+ TcpHdr *h() { return (TcpHdr *)(p->data + off); }
+
+ void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; }
+ void set(const IpPtr &ptr)
+ {
+ if (ptr->proto() == IP_PROTO_TCP)
+ set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
+ else
+ set(0, 0);
+ }
+
+ public:
+ TcpPtr() {}
+ TcpPtr(const IpPtr &ptr) { set(ptr); }
+ TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {}
+
+ TcpHdr *operator->() { return h(); }
+ TcpHdr &operator*() { return *h(); }
+ operator TcpHdr *() { return h(); }
+
+ const TcpHdr *operator->() const { return h(); }
+ const TcpHdr &operator*() const { return *h(); }
+ operator const TcpHdr *() const { return h(); }
+
+ const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; }
+ const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const TcpPtr &ptr);
+
+typedef Range<uint16_t> SackRange;
+
+struct TcpOpt : public tcp_opt
+{
+ uint8_t type() const { return opt_type; }
+ uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
+
+ bool isopt(int opt) const { return type() == opt; }
+
+ const uint8_t *data() const { return opt_data.data8; }
+
+ uint16_t mss() const { return ntohs(opt_data.mss); }
+ uint8_t wscale() const { return opt_data.wscale; }
+ bool sack(std::vector<SackRange> &vec) const;
+ uint32_t echo() const { return ntohl(opt_data.echo); }
+ uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); }
+ uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); }
+ uint32_t cc() const { return ntohl(opt_data.cc); }
+ uint8_t cksum() const{ return opt_data.cksum; }
+ const uint8_t *md5() const { return opt_data.md5; }
+
+ int size() const { return len(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+/*
+ * UDP Stuff
+ */
+struct UdpHdr : public udp_hdr
+{
+ uint16_t sport() const { return ntohs(uh_sport); }
+ uint16_t dport() const { return ntohs(uh_dport); }
+ uint16_t len() const { return ntohs(uh_ulen); }
+ uint16_t sum() const { return uh_sum; }
+
+ void sum(uint16_t sum) { uh_sum = sum; }
+
+ int size() const { return sizeof(udp_hdr); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class UdpPtr
+{
+ protected:
+ EthPacketPtr p;
+ int off;
+
+ const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); }
+ UdpHdr *h() { return (UdpHdr *)(p->data + off); }
+
+ void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; }
+ void set(const IpPtr &ptr)
+ {
+ if (ptr->proto() == IP_PROTO_UDP)
+ set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
+ else
+ set(0, 0);
+ }
+
+ public:
+ UdpPtr() {}
+ UdpPtr(const IpPtr &ptr) { set(ptr); }
+ UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {}
+
+ UdpHdr *operator->() { return h(); }
+ UdpHdr &operator*() { return *h(); }
+ operator UdpHdr *() { return h(); }
+
+ const UdpHdr *operator->() const { return h(); }
+ const UdpHdr &operator*() const { return *h(); }
+ operator const UdpHdr *() const { return h(); }
+
+ const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; }
+ const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const UdpPtr &ptr);
+
+/* namespace Net */ }
+
+#endif // __BASE_INET_HH__
diff --git a/src/base/inifile.cc b/src/base/inifile.cc
new file mode 100644
index 000000000..eb5a1335f
--- /dev/null
+++ b/src/base/inifile.cc
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ */
+
+#define USE_CPP
+
+#ifdef USE_CPP
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <fstream>
+#include <iostream>
+
+#include <vector>
+#include <string>
+
+#include "base/inifile.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+IniFile::IniFile()
+{}
+
+IniFile::~IniFile()
+{
+ SectionTable::iterator i = table.begin();
+ SectionTable::iterator end = table.end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+
+#ifdef USE_CPP
+bool
+IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
+{
+ // Open the file just to verify that we can. Otherwise if the
+ // file doesn't exist or has bad permissions the user will get
+ // confusing errors from cpp/g++.
+ ifstream tmpf(file.c_str());
+
+ if (!tmpf.is_open())
+ return false;
+
+ tmpf.close();
+
+ char *cfile = strncpy(new char[file.size() + 1], file.c_str(),
+ file.size());
+ char *dir = dirname(cfile);
+ char *dir_arg = NULL;
+ if (*dir != '.') {
+ string arg = "-I";
+ arg += dir;
+
+ dir_arg = new char[arg.size() + 1];
+ strncpy(dir_arg, arg.c_str(), arg.size());
+ }
+
+ delete [] cfile;
+
+ char tempfile[] = "/tmp/configXXXXXX";
+ int tmp_fd = mkstemp(tempfile);
+
+ int pid = fork();
+
+ if (pid == -1)
+ return false;
+
+ if (pid == 0) {
+ char filename[FILENAME_MAX];
+ string::size_type i = file.copy(filename, sizeof(filename) - 1);
+ filename[i] = '\0';
+
+ int arg_count = cppArgs.size();
+
+ char **args = new char *[arg_count + 20];
+
+ int nextArg = 0;
+ args[nextArg++] = "g++";
+ args[nextArg++] = "-E";
+ args[nextArg++] = "-P";
+ args[nextArg++] = "-nostdinc";
+ args[nextArg++] = "-nostdinc++";
+ args[nextArg++] = "-x";
+ args[nextArg++] = "c++";
+ args[nextArg++] = "-undef";
+
+ for (int i = 0; i < arg_count; i++)
+ args[nextArg++] = cppArgs[i];
+
+ if (dir_arg)
+ args[nextArg++] = dir_arg;
+
+ args[nextArg++] = filename;
+ args[nextArg++] = NULL;
+
+ close(STDOUT_FILENO);
+ if (dup2(tmp_fd, STDOUT_FILENO) == -1)
+ exit(1);
+
+ execvp("g++", args);
+
+ exit(0);
+ }
+
+ int retval;
+ waitpid(pid, &retval, 0);
+
+ delete [] dir_arg;
+
+ // check for normal completion of CPP
+ if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
+ return false;
+
+ close(tmp_fd);
+
+ bool status = false;
+
+ status = load(tempfile);
+
+ unlink(tempfile);
+
+ return status;
+}
+#endif
+
+bool
+IniFile::load(const string &file)
+{
+ ifstream f(file.c_str());
+
+ if (!f.is_open())
+ return false;
+
+ return load(f);
+}
+
+
+const string &
+IniFile::Entry::getValue() const
+{
+ referenced = true;
+ return value;
+}
+
+
+void
+IniFile::Section::addEntry(const std::string &entryName,
+ const std::string &value,
+ bool append)
+{
+ EntryTable::iterator ei = table.find(entryName);
+
+ if (ei == table.end()) {
+ // new entry
+ table[entryName] = new Entry(value);
+ }
+ else if (append) {
+ // append new reult to old entry
+ ei->second->appendValue(value);
+ }
+ else {
+ // override old entry
+ ei->second->setValue(value);
+ }
+}
+
+
+bool
+IniFile::Section::add(const std::string &assignment)
+{
+ string::size_type offset = assignment.find('=');
+ if (offset == string::npos) {
+ // no '=' found
+ cerr << "Can't parse .ini line " << assignment << endl;
+ return false;
+ }
+
+ // if "+=" rather than just "=" then append value
+ bool append = (assignment[offset-1] == '+');
+
+ string entryName = assignment.substr(0, append ? offset-1 : offset);
+ string value = assignment.substr(offset + 1);
+
+ eat_white(entryName);
+ eat_white(value);
+
+ addEntry(entryName, value, append);
+ return true;
+}
+
+
+IniFile::Entry *
+IniFile::Section::findEntry(const std::string &entryName) const
+{
+ referenced = true;
+
+ EntryTable::const_iterator ei = table.find(entryName);
+
+ return (ei == table.end()) ? NULL : ei->second;
+}
+
+
+IniFile::Section *
+IniFile::addSection(const string &sectionName)
+{
+ SectionTable::iterator i = table.find(sectionName);
+
+ if (i != table.end()) {
+ return i->second;
+ }
+ else {
+ // new entry
+ Section *sec = new Section();
+ table[sectionName] = sec;
+ return sec;
+ }
+}
+
+
+IniFile::Section *
+IniFile::findSection(const string &sectionName) const
+{
+ SectionTable::const_iterator i = table.find(sectionName);
+
+ return (i == table.end()) ? NULL : i->second;
+}
+
+
+// Take string of the form "<section>:<parameter>=<value>" and add to
+// database. Return true if successful, false if parse error.
+bool
+IniFile::add(const string &str)
+{
+ // find ':'
+ string::size_type offset = str.find(':');
+ if (offset == string::npos) // no ':' found
+ return false;
+
+ string sectionName = str.substr(0, offset);
+ string rest = str.substr(offset + 1);
+
+ eat_white(sectionName);
+ Section *s = addSection(sectionName);
+
+ return s->add(rest);
+}
+
+bool
+IniFile::load(istream &f)
+{
+ Section *section = NULL;
+
+ while (!f.eof()) {
+ f >> ws; // Eat whitespace
+ if (f.eof()) {
+ break;
+ }
+
+ string line;
+ getline(f, line);
+ if (line.size() == 0)
+ continue;
+
+ eat_end_white(line);
+ int last = line.size() - 1;
+
+ if (line[0] == '[' && line[last] == ']') {
+ string sectionName = line.substr(1, last - 1);
+ eat_white(sectionName);
+ section = addSection(sectionName);
+ continue;
+ }
+
+ if (section == NULL)
+ continue;
+
+ if (!section->add(line))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+IniFile::find(const string &sectionName, const string &entryName,
+ string &value) const
+{
+ Section *section = findSection(sectionName);
+ if (section == NULL)
+ return false;
+
+ Entry *entry = section->findEntry(entryName);
+ if (entry == NULL)
+ return false;
+
+ value = entry->getValue();
+
+ return true;
+}
+
+bool
+IniFile::sectionExists(const string &sectionName) const
+{
+ return findSection(sectionName) != NULL;
+}
+
+
+bool
+IniFile::Section::printUnreferenced(const string &sectionName)
+{
+ bool unref = false;
+ bool search_unref_entries = false;
+ vector<string> unref_ok_entries;
+
+ Entry *entry = findEntry("unref_entries_ok");
+ if (entry != NULL) {
+ tokenize(unref_ok_entries, entry->getValue(), ' ');
+ if (unref_ok_entries.size()) {
+ search_unref_entries = true;
+ }
+ }
+
+ for (EntryTable::iterator ei = table.begin();
+ ei != table.end(); ++ei) {
+ const string &entryName = ei->first;
+ Entry *entry = ei->second;
+
+ if (entryName == "unref_section_ok" ||
+ entryName == "unref_entries_ok")
+ {
+ continue;
+ }
+
+ if (!entry->isReferenced()) {
+ if (search_unref_entries &&
+ (std::find(unref_ok_entries.begin(), unref_ok_entries.end(),
+ entryName) != unref_ok_entries.end()))
+ {
+ continue;
+ }
+
+ cerr << "Parameter " << sectionName << ":" << entryName
+ << " not referenced." << endl;
+ unref = true;
+ }
+ }
+
+ return unref;
+}
+
+
+bool
+IniFile::printUnreferenced()
+{
+ bool unref = false;
+
+ for (SectionTable::iterator i = table.begin();
+ i != table.end(); ++i) {
+ const string &sectionName = i->first;
+ Section *section = i->second;
+
+ if (!section->isReferenced()) {
+ if (section->findEntry("unref_section_ok") == NULL) {
+ cerr << "Section " << sectionName << " not referenced."
+ << endl;
+ unref = true;
+ }
+ }
+ else {
+ if (section->printUnreferenced(sectionName)) {
+ unref = true;
+ }
+ }
+ }
+
+ return unref;
+}
+
+
+void
+IniFile::Section::dump(const string &sectionName)
+{
+ for (EntryTable::iterator ei = table.begin();
+ ei != table.end(); ++ei) {
+ cout << sectionName << ": " << (*ei).first << " => "
+ << (*ei).second->getValue() << "\n";
+ }
+}
+
+void
+IniFile::dump()
+{
+ for (SectionTable::iterator i = table.begin();
+ i != table.end(); ++i) {
+ i->second->dump(i->first);
+ }
+}
diff --git a/src/base/inifile.hh b/src/base/inifile.hh
new file mode 100644
index 000000000..3c6894978
--- /dev/null
+++ b/src/base/inifile.hh
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+#ifndef __INIFILE_HH__
+#define __INIFILE_HH__
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/hashmap.hh"
+
+/**
+ * @file
+ * Declaration of IniFile object.
+ * @todo Change comments to match documentation style.
+ */
+
+///
+/// This class represents the contents of a ".ini" file.
+///
+/// It's basically a two level lookup table: a set of named sections,
+/// where each section is a set of key/value pairs. Section names,
+/// keys, and values are all uninterpreted strings.
+///
+class IniFile
+{
+ protected:
+
+ ///
+ /// A single key/value pair.
+ ///
+ class Entry
+ {
+ std::string value; ///< The entry value.
+ mutable bool referenced; ///< Has this entry been used?
+
+ public:
+ /// Constructor.
+ Entry(const std::string &v)
+ : value(v), referenced(false)
+ {
+ }
+
+ /// Has this entry been used?
+ bool isReferenced() { return referenced; }
+
+ /// Fetch the value.
+ const std::string &getValue() const;
+
+ /// Set the value.
+ void setValue(const std::string &v) { value = v; }
+
+ /// Append the given string to the value. A space is inserted
+ /// between the existing value and the new value. Since this
+ /// operation is typically used with values that are
+ /// space-separated lists of tokens, this keeps the tokens
+ /// separate.
+ void appendValue(const std::string &v) { value += " "; value += v; }
+ };
+
+ ///
+ /// A section.
+ ///
+ class Section
+ {
+ /// EntryTable type. Map of strings to Entry object pointers.
+ typedef m5::hash_map<std::string, Entry *> EntryTable;
+
+ EntryTable table; ///< Table of entries.
+ mutable bool referenced; ///< Has this section been used?
+
+ public:
+ /// Constructor.
+ Section()
+ : table(), referenced(false)
+ {
+ }
+
+ /// Has this section been used?
+ bool isReferenced() { return referenced; }
+
+ /// Add an entry to the table. If an entry with the same name
+ /// already exists, the 'append' parameter is checked If true,
+ /// the new value will be appended to the existing entry. If
+ /// false, the new value will replace the existing entry.
+ void addEntry(const std::string &entryName, const std::string &value,
+ bool append);
+
+ /// Add an entry to the table given a string assigment.
+ /// Assignment should be of the form "param=value" or
+ /// "param+=value" (for append). This funciton parses the
+ /// assignment statment and calls addEntry().
+ /// @retval True for success, false if parse error.
+ bool add(const std::string &assignment);
+
+ /// Find the entry with the given name.
+ /// @retval Pointer to the entry object, or NULL if none.
+ Entry *findEntry(const std::string &entryName) const;
+
+ /// Print the unreferenced entries in this section to cerr.
+ /// Messages can be suppressed using "unref_section_ok" and
+ /// "unref_entries_ok".
+ /// @param sectionName Name of this section, for use in output message.
+ /// @retval True if any entries were printed.
+ bool printUnreferenced(const std::string &sectionName);
+
+ /// Print the contents of this section to cout (for debugging).
+ void dump(const std::string &sectionName);
+ };
+
+ /// SectionTable type. Map of strings to Section object pointers.
+ typedef m5::hash_map<std::string, Section *> SectionTable;
+
+ protected:
+ /// Hash of section names to Section object pointers.
+ SectionTable table;
+
+ /// Look up section with the given name, creating a new section if
+ /// not found.
+ /// @retval Pointer to section object.
+ Section *addSection(const std::string &sectionName);
+
+ /// Look up section with the given name.
+ /// @retval Pointer to section object, or NULL if not found.
+ Section *findSection(const std::string &sectionName) const;
+
+ public:
+ /// Constructor.
+ IniFile();
+
+ /// Destructor.
+ ~IniFile();
+
+ /// Load parameter settings from given istream. This is a helper
+ /// function for load(string) and loadCPP(), which open a file
+ /// and then pass it here.
+ /// @retval True if successful, false if errors were encountered.
+ bool load(std::istream &f);
+
+ /// Load the specified file, passing it through the C preprocessor.
+ /// Parameter settings found in the file will be merged with any
+ /// already defined in this object.
+ /// @param file The path of the file to load.
+ /// @param cppFlags Vector of extra flags to pass to cpp.
+ /// @retval True if successful, false if errors were encountered.
+ bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
+
+ /// Load the specified file.
+ /// Parameter settings found in the file will be merged with any
+ /// already defined in this object.
+ /// @param file The path of the file to load.
+ /// @retval True if successful, false if errors were encountered.
+ bool load(const std::string &file);
+
+ /// Take string of the form "<section>:<parameter>=<value>" or
+ /// "<section>:<parameter>+=<value>" and add to database.
+ /// @retval True if successful, false if parse error.
+ bool add(const std::string &s);
+
+ /// Find value corresponding to given section and entry names.
+ /// Value is returned by reference in 'value' param.
+ /// @retval True if found, false if not.
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value) const;
+
+ /// Determine whether the named section exists in the .ini file.
+ /// Note that the 'Section' class is (intentionally) not public,
+ /// so all clients can do is get a bool that says whether there
+ /// are any values in that section or not.
+ /// @return True if the section exists.
+ bool sectionExists(const std::string &section) const;
+
+ /// Print unreferenced entries in object. Iteratively calls
+ /// printUnreferend() on all the constituent sections.
+ bool printUnreferenced();
+
+ /// Dump contents to cout. For debugging.
+ void dump();
+};
+
+#endif // __INIFILE_HH__
diff --git a/src/base/intmath.cc b/src/base/intmath.cc
new file mode 100644
index 000000000..f1c1651ba
--- /dev/null
+++ b/src/base/intmath.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/intmath.hh"
+
+int
+prevPrime(int n)
+{
+ int decr;
+
+ // If the number is even, let's start with the previous odd number.
+ if (!(n & 1))
+ --n;
+
+ // Lets test for divisibility by 3. Then we will be able to easily
+ // avoid numbers that are divisible by 3 in the future.
+ decr = n % 3;
+ if (decr == 0) {
+ n -= 2;
+ decr = 2;
+ }
+ else if (decr == 1)
+ decr = 4;
+
+ for (;;) {
+ if (isPrime(n))
+ return n;
+ n -= decr;
+ // Toggle between 2 and 4 to prevent trying numbers that are known
+ // to be divisible by 3.
+ decr = 6 - decr;
+ }
+}
diff --git a/src/base/intmath.hh b/src/base/intmath.hh
new file mode 100644
index 000000000..51baddb91
--- /dev/null
+++ b/src/base/intmath.hh
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INTMATH_HH__
+#define __INTMATH_HH__
+
+#include <assert.h>
+
+#include "sim/host.hh"
+
+// Returns the prime number one less than n.
+int prevPrime(int n);
+
+// Determine if a number is prime
+template <class T>
+inline bool
+isPrime(T n)
+{
+ T i;
+
+ if (n == 2 || n == 3)
+ return true;
+
+ // Don't try every odd number to prove if it is a prime.
+ // Toggle between every 2nd and 4th number.
+ // (This is because every 6th odd number is divisible by 3.)
+ for (i = 5; i*i <= n; i += 6) {
+ if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template <class T>
+inline T
+leastSigBit(T n)
+{
+ return n & ~(n - 1);
+}
+
+template <class T>
+inline bool
+isPowerOf2(T n)
+{
+ return n != 0 && leastSigBit(n) == n;
+}
+
+inline int
+floorLog2(unsigned x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+ if (x & 0xffff0000) { y += 16; x >>= 16; }
+ if (x & 0x0000ff00) { y += 8; x >>= 8; }
+ if (x & 0x000000f0) { y += 4; x >>= 4; }
+ if (x & 0x0000000c) { y += 2; x >>= 2; }
+ if (x & 0x00000002) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(unsigned long x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+#if defined(__LP64__)
+ if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; }
+#endif
+ if (x & 0xffff0000) { y += 16; x >>= 16; }
+ if (x & 0x0000ff00) { y += 8; x >>= 8; }
+ if (x & 0x000000f0) { y += 4; x >>= 4; }
+ if (x & 0x0000000c) { y += 2; x >>= 2; }
+ if (x & 0x00000002) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(unsigned long long x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+ if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; }
+ if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; }
+ if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; }
+ if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; }
+ if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; }
+ if (x & ULL(0x0000000000000002)) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(int x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned)x);
+}
+
+inline int
+floorLog2(long x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned long)x);
+}
+
+inline int
+floorLog2(long long x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned long long)x);
+}
+
+template <class T>
+inline int
+ceilLog2(T n)
+{
+ if (n == 1)
+ return 0;
+
+ return floorLog2(n - (T)1) + 1;
+}
+
+template <class T>
+inline T
+floorPow2(T n)
+{
+ return (T)1 << floorLog2(n);
+}
+
+template <class T>
+inline T
+ceilPow2(T n)
+{
+ return (T)1 << ceilLog2(n);
+}
+
+template <class T>
+inline T
+divCeil(T a, T b)
+{
+ return (a + b - 1) / b;
+}
+
+template <class T>
+inline T
+roundUp(T val, int align)
+{
+ T mask = (T)align - 1;
+ return (val + mask) & ~mask;
+}
+
+template <class T>
+inline T
+roundDown(T val, int align)
+{
+ T mask = (T)align - 1;
+ return val & ~mask;
+}
+
+inline bool
+isHex(char c)
+{
+ return c >= '0' && c <= '9' ||
+ c >= 'A' && c <= 'F' ||
+ c >= 'a' && c <= 'f';
+}
+
+inline bool
+isOct(char c)
+{
+ return c >= '0' && c <= '7';
+}
+
+inline bool
+isDec(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+inline int
+hex2Int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+
+ if (c >= 'A' && c <= 'F')
+ return (c - 'A') + 10;
+
+ if (c >= 'a' && c <= 'f')
+ return (c - 'a') + 10;
+
+ return 0;
+}
+
+#endif // __INTMATH_HH__
diff --git a/src/base/kgdb.h b/src/base/kgdb.h
new file mode 100644
index 000000000..104244d0b
--- /dev/null
+++ b/src/base/kgdb.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratories.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)remote-sl.h 8.1 (Berkeley) 6/11/93
+ */
+
+/* $NetBSD: kgdb.h,v 1.4 1998/08/13 02:10:59 eeh Exp $ */
+
+#ifndef __KGDB_H__
+#define __KGDB_H__
+
+/*
+ * Message types.
+ */
+#define KGDB_SIGNAL '?' // last sigal
+#define KGDB_SET_BAUD 'b' // set baud (deprecated)
+#define KGDB_SET_BREAK 'B' // set breakpoint (deprecated)
+#define KGDB_CONT 'c' // resume
+#define KGDB_ASYNC_CONT 'C' // continue with signal
+#define KGDB_DEBUG 'd' // toggle debug flags (deprecated)
+#define KGDB_DETACH 'D' // detach remote gdb
+#define KGDB_REG_R 'g' // read general registers
+#define KGDB_REG_W 'G' // write general registers
+#define KGDB_SET_THREAD 'H' // set thread
+#define KGDB_CYCLE_STEP 'i' // step a single cycle
+#define KGDB_SIG_CYCLE_STEP 'I' // signal then single cycle step
+#define KGDB_KILL 'k' // kill program
+#define KGDB_MEM_R 'm' // read memory
+#define KGDB_MEM_W 'M' // write memory
+#define KGDB_READ_REG 'p' // read register
+#define KGDB_SET_REG 'P' // write register
+#define KGDB_QUERY_VAR 'q' // query variable
+#define KGDB_SET_VAR 'Q' // set variable
+#define KGDB_RESET 'r' // reset system. (Deprecated)
+#define KGDB_STEP 's' // step
+#define KGDB_ASYNC_STEP 'S' // signal and step
+#define KGDB_THREAD_ALIVE 'T' // find out if the thread is alive.
+#define KGDB_TARGET_EXIT 'W' // target exited
+#define KGDB_BINARY_DLOAD 'X' // write memory
+#define KGDB_CLR_HW_BKPT 'z' // remove breakpoint or watchpoint
+#define KGDB_SET_HW_BKPT 'Z' // insert breakpoint or watchpoint
+
+/*
+ * start of frame/end of frame
+ */
+#define KGDB_START '$'
+#define KGDB_END '#'
+#define KGDB_GOODP '+'
+#define KGDB_BADP '-'
+
+/*
+ * Stuff for KGDB.
+ */
+#define KGDB_NUMREGS 66 /* from tm-alpha.h, NUM_REGS */
+#define KGDB_REG_V0 0
+#define KGDB_REG_T0 1
+#define KGDB_REG_T1 2
+#define KGDB_REG_T2 3
+#define KGDB_REG_T3 4
+#define KGDB_REG_T4 5
+#define KGDB_REG_T5 6
+#define KGDB_REG_T6 7
+#define KGDB_REG_T7 8
+#define KGDB_REG_S0 9
+#define KGDB_REG_S1 10
+#define KGDB_REG_S2 11
+#define KGDB_REG_S3 12
+#define KGDB_REG_S4 13
+#define KGDB_REG_S5 14
+#define KGDB_REG_S6 15 /* FP */
+#define KGDB_REG_A0 16
+#define KGDB_REG_A1 17
+#define KGDB_REG_A2 18
+#define KGDB_REG_A3 19
+#define KGDB_REG_A4 20
+#define KGDB_REG_A5 21
+#define KGDB_REG_T8 22
+#define KGDB_REG_T9 23
+#define KGDB_REG_T10 24
+#define KGDB_REG_T11 25
+#define KGDB_REG_RA 26
+#define KGDB_REG_T12 27
+#define KGDB_REG_AT 28
+#define KGDB_REG_GP 29
+#define KGDB_REG_SP 30
+#define KGDB_REG_ZERO 31
+#define KGDB_REG_F0 32
+#define KGDB_REG_F1 33
+#define KGDB_REG_F2 34
+#define KGDB_REG_F3 35
+#define KGDB_REG_F4 36
+#define KGDB_REG_F5 37
+#define KGDB_REG_F6 38
+#define KGDB_REG_F7 39
+#define KGDB_REG_F8 40
+#define KGDB_REG_F9 41
+#define KGDB_REG_F10 42
+#define KGDB_REG_F11 43
+#define KGDB_REG_F12 44
+#define KGDB_REG_F13 45
+#define KGDB_REG_F14 46
+#define KGDB_REG_F15 47
+#define KGDB_REG_F16 48
+#define KGDB_REG_F17 49
+#define KGDB_REG_F18 50
+#define KGDB_REG_F19 51
+#define KGDB_REG_F20 52
+#define KGDB_REG_F21 53
+#define KGDB_REG_F22 54
+#define KGDB_REG_F23 55
+#define KGDB_REG_F24 56
+#define KGDB_REG_F25 57
+#define KGDB_REG_F26 58
+#define KGDB_REG_F27 59
+#define KGDB_REG_F28 60
+#define KGDB_REG_F29 61
+#define KGDB_REG_F30 62
+#define KGDB_REG_F31 63
+#define KGDB_REG_PC 64
+#define KGDB_REG_VFP 65
+
+/* Too much? Must be large enough for register transfer. */
+#define KGDB_BUFLEN 1024
+
+/*
+ * Kernel Entry Vectors. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_KENTRY_INT 0
+#define ALPHA_KENTRY_ARITH 1
+#define ALPHA_KENTRY_MM 2
+#define ALPHA_KENTRY_IF 3
+#define ALPHA_KENTRY_UNA 4
+#define ALPHA_KENTRY_SYS 5
+
+#endif /* __KGDB_H__ */
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc
new file mode 100644
index 000000000..564898ca3
--- /dev/null
+++ b/src/base/loader/aout_object.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/loader/aout_object.hh"
+
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "base/loader/exec_aout.h"
+
+using namespace std;
+
+ObjectFile *
+AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ if (!N_BADMAG(*(aout_exechdr *)data)) {
+ // right now this is only used for Alpha PAL code
+ return new AoutObject(fname, fd, len, data,
+ ObjectFile::Alpha, ObjectFile::UnknownOpSys);
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+AoutObject::AoutObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+{
+ execHdr = (aout_exechdr *)fileData;
+
+ entry = execHdr->entry;
+
+ text.baseAddr = N_TXTADDR(*execHdr);
+ text.size = execHdr->tsize;
+ text.fileImage = fileData + N_TXTOFF(*execHdr);
+
+ data.baseAddr = N_DATADDR(*execHdr);
+ data.size = execHdr->dsize;
+ data.fileImage = fileData + N_DATOFF(*execHdr);
+
+ bss.baseAddr = N_BSSADDR(*execHdr);
+ bss.size = execHdr->bsize;
+ bss.fileImage = NULL;
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+}
+
+
+bool
+AoutObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ // a.out symbols not supported yet
+ return false;
+}
+
+bool
+AoutObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ // a.out symbols not supported yet
+ return false;
+}
diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh
new file mode 100644
index 000000000..aeb710427
--- /dev/null
+++ b/src/base/loader/aout_object.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AOUT_OBJECT_HH__
+#define __AOUT_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+// forward decls: avoid including exec_aout.h here
+struct aout_exechdr;
+
+class AoutObject : public ObjectFile
+{
+ protected:
+ aout_exechdr *execHdr;
+
+ AoutObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~AoutObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __AOUT_OBJECT_HH__
diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h
new file mode 100644
index 000000000..4c6540395
--- /dev/null
+++ b/src/base/loader/coff_sym.h
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/*
+ * Taken from binutils-2.14.90.0.5 include/coff/sym.h
+ */
+
+/* Declarations of internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+#ifndef _SYM_H
+#define _SYM_H
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/*
+ * This file contains the definition of the Third Eye Symbol Table.
+ *
+ * Symbols are assumed to be in 'encounter order' - i.e. the order that
+ * the things they represent were encountered by the compiler/assembler/loader.
+ * EXCEPT for globals! These are assumed to be bunched together,
+ * probably right after the last 'normal' symbol. Globals ARE sorted
+ * in ascending order.
+ *
+ * -----------------------------------------------------------------------
+ * A brief word about Third Eye naming/use conventions:
+ *
+ * All arrays and index's are 0 based.
+ * All "ifooMax" values are the highest legal value PLUS ONE. This makes
+ * them good for allocating arrays, etc. All checks are "ifoo < ifooMax".
+ *
+ * "isym" Index into the SYMbol table.
+ * "ipd" Index into the Procedure Descriptor array.
+ * "ifd" Index into the File Descriptor array.
+ * "iss" Index into String Space.
+ * "cb" Count of Bytes.
+ * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR.
+ * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR.
+ */
+
+
+/*
+ * Symbolic Header (HDR) structure.
+ * As long as all the pointers are set correctly,
+ * we don't care WHAT order the various sections come out in!
+ *
+ * A file produced solely for the use of CDB will probably NOT have
+ * any instructions or data areas in it, as these are available
+ * in the original.
+ */
+
+typedef struct ecoff_symhdr {
+ coff_short magic; /* to verify validity of the table */
+ coff_short vstamp; /* version stamp */
+ coff_int ilineMax; /* number of line number entries */
+ coff_int idnMax; /* max index into dense number table */
+ coff_int ipdMax; /* number of procedures */
+ coff_int isymMax; /* number of local symbols */
+ coff_int ioptMax; /* max index into optimization symbol entries */
+ coff_int iauxMax; /* number of auxillary symbol entries */
+ coff_int issMax; /* max index into local strings */
+ coff_int issExtMax; /* max index into external strings */
+ coff_int ifdMax; /* number of file descriptor entries */
+ coff_int crfd; /* number of relative file descriptor entries */
+ coff_int iextMax; /* max index into external symbols */
+ coff_addr cbLine; /* number of bytes for line number entries */
+ coff_addr cbLineOffset; /* offset to start of line number entries*/
+ coff_addr cbDnOffset; /* offset to start dense number table */
+ coff_addr cbPdOffset; /* offset to procedure descriptor table */
+ coff_addr cbSymOffset; /* offset to start of local symbols*/
+ coff_addr cbOptOffset; /* offset to optimization symbol entries */
+ coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/
+ coff_addr cbSsOffset; /* offset to start of local strings */
+ coff_addr cbSsExtOffset; /* offset to start of external strings */
+ coff_addr cbFdOffset; /* offset to file descriptor table */
+ coff_addr cbRfdOffset; /* offset to relative file descriptor table */
+ coff_addr cbExtOffset; /* offset to start of external symbol entries*/
+ /* If you add machine dependent fields, add them here */
+} HDRR, *pHDRR;
+#define cbHDRR sizeof(HDRR)
+#define hdrNil ((pHDRR)0)
+
+/*
+ * The FDR and PDR structures speed mapping of address <-> name.
+ * They are sorted in ascending memory order and are kept in
+ * memory by CDB at runtime.
+ */
+
+/*
+ * File Descriptor
+ *
+ * There is one of these for EVERY FILE, whether compiled with
+ * full debugging symbols or not. The name of a file should be
+ * the path name given to the compiler. This allows the user
+ * to simply specify the names of the directories where the COMPILES
+ * were done, and we will be able to find their files.
+ * A field whose comment starts with "R - " indicates that it will be
+ * setup at runtime.
+ */
+typedef struct ecoff_fdr {
+ coff_addr adr; /* memory address of beginning of file */
+ coff_addr cbLineOffset; /* byte offset from header for this file ln's */
+ coff_addr cbLine; /* size of lines for this file */
+ coff_addr cbSs; /* number of bytes in the ss */
+ coff_int rss; /* file name (of source, if known) */
+ coff_int issBase; /* file's string space */
+ coff_int isymBase; /* beginning of symbols */
+ coff_int csym; /* count file's of symbols */
+ coff_int ilineBase; /* file's line symbols */
+ coff_int cline; /* count of file's line symbols */
+ coff_int ioptBase; /* file's optimization entries */
+ coff_int copt; /* count of file's optimization entries */
+ coff_int ipdFirst; /* start of procedures for this file */
+ coff_int cpd; /* count of procedures for this file */
+ coff_int iauxBase; /* file's auxiliary entries */
+ coff_int caux; /* count of file's auxiliary entries */
+ coff_int rfdBase; /* index into the file indirect table */
+ coff_int crfd; /* count file indirect entries */
+ unsigned lang: 5; /* language for this file */
+ unsigned fMerge : 1; /* whether this file can be merged */
+ unsigned fReadin : 1; /* true if it was read in (not just created) */
+ unsigned fBigendian : 1;/* if set, was compiled on big endian machine */
+ /* aux's will be in compile host's sex */
+ unsigned glevel : 2; /* level this file was compiled with */
+ unsigned reserved : 22; /* reserved for future use */
+ coff_uint reserved2;
+} FDR, *pFDR;
+#define cbFDR sizeof(FDR)
+#define fdNil ((pFDR)0)
+#define ifdNil -1
+#define ifdTemp 0
+#define ilnNil -1
+
+
+/*
+ * Procedure Descriptor
+ *
+ * There is one of these for EVERY TEXT LABEL.
+ * If a procedure is in a file with full symbols, then isym
+ * will point to the PROC symbols, else it will point to the
+ * global symbol for the label.
+ */
+
+typedef struct pdr {
+ coff_addr adr; /* memory address of start of procedure */
+ coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */
+ coff_int isym; /* start of local symbol entries */
+ coff_int iline; /* start of line number entries*/
+ coff_uint regmask; /* save register mask */
+ coff_int regoffset; /* save register offset */
+ coff_int iopt; /* start of optimization symbol entries*/
+ coff_uint fregmask; /* save floating point register mask */
+ coff_int fregoffset; /* save floating point register offset */
+ coff_int frameoffset; /* frame size */
+ coff_int lnLow; /* lowest line in the procedure */
+ coff_int lnHigh; /* highest line in the procedure */
+ /* These fields are new for 64 bit ECOFF. */
+ unsigned gp_prologue : 8; /* byte size of GP prologue */
+ unsigned gp_used : 1; /* true if the procedure uses GP */
+ unsigned reg_frame : 1; /* true if register frame procedure */
+ unsigned prof : 1; /* true if compiled with -pg */
+ unsigned reserved : 13; /* reserved: must be zero */
+ unsigned localoff : 8; /* offset of local variables from vfp */
+ coff_short framereg; /* frame pointer register */
+ coff_short pcreg; /* offset or reg of return pc */
+} PDR, *pPDR;
+#define cbPDR sizeof(PDR)
+#define pdNil ((pPDR) 0)
+#define ipdNil -1
+
+/*
+ * The structure of the runtime procedure descriptor created by the loader
+ * for use by the static exception system.
+ */
+/*
+ * If 0'd out because exception_info chokes Visual C++ and because there
+ * don't seem to be any references to this structure elsewhere in gdb.
+ */
+#if 0
+typedef struct runtime_pdr {
+ coff_addr adr; /* memory address of start of procedure */
+ coff_uint regmask; /* save register mask */
+ coff_int regoffset; /* save register offset */
+ coff_uint fregmask; /* save floating point register mask */
+ coff_int fregoffset; /* save floating point register offset */
+ coff_int frameoffset; /* frame size */
+ coff_ushort framereg; /* frame pointer register */
+ coff_ushort pcreg; /* offset or reg of return pc */
+ coff_int irpss; /* index into the runtime string table */
+ coff_uint reserved;
+ struct exception_info *exception_info;/* pointer to exception array */
+} RPDR, *pRPDR;
+#define cbRPDR sizeof(RPDR)
+#define rpdNil ((pRPDR) 0)
+#endif
+
+/*
+ * Line Numbers
+ *
+ * Line Numbers are segregated from the normal symbols because they
+ * are [1] smaller , [2] are of no interest to your
+ * average loader, and [3] are never needed in the middle of normal
+ * scanning and therefore slow things down.
+ *
+ * By definition, the first LINER for any given procedure will have
+ * the first line of a procedure and represent the first address.
+ */
+
+typedef coff_int LINER, *pLINER;
+#define lineNil ((pLINER)0)
+#define cbLINER sizeof(LINER)
+#define ilineNil -1
+
+
+
+/*
+ * The Symbol Structure (GFW, to those who Know!)
+ */
+
+typedef struct ecoff_sym {
+ coff_long value; /* value of symbol */
+ coff_int iss; /* index into String Space of name */
+ unsigned st : 6; /* symbol type */
+ unsigned sc : 5; /* storage class - text, data, etc */
+ unsigned reserved : 1; /* reserved */
+ unsigned index : 20; /* index into sym/aux table */
+} SYMR, *pSYMR;
+#define symNil ((pSYMR)0)
+#define cbSYMR sizeof(SYMR)
+#define isymNil -1
+#define indexNil 0xfffff
+#define issNil -1
+#define issNull 0
+
+
+/* The following converts a memory resident string to an iss.
+ * This hack is recognized in SbFIss, in sym.c of the debugger.
+ */
+#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb)))
+
+/* E X T E R N A L S Y M B O L R E C O R D
+ *
+ * Same as the SYMR except it contains file context to determine where
+ * the index is.
+ */
+typedef struct ecoff_extsym {
+ SYMR asym; /* symbol for the external */
+ unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */
+ unsigned cobol_main:1; /* symbol is a cobol main procedure */
+ unsigned weakext:1; /* symbol is weak external */
+ unsigned reserved:29; /* reserved for future use */
+ coff_int ifd; /* where the iss and index fields point into */
+} EXTR, *pEXTR;
+#define extNil ((pEXTR)0)
+#define cbEXTR sizeof(EXTR)
+
+
+/* A U X I L L A R Y T Y P E I N F O R M A T I O N */
+
+/*
+ * Type Information Record
+ */
+typedef struct {
+ unsigned fBitfield : 1; /* set if bit width is specified */
+ unsigned continued : 1; /* indicates additional TQ info in next AUX */
+ unsigned bt : 6; /* basic type */
+ unsigned tq4 : 4;
+ unsigned tq5 : 4;
+ /* ---- 16 bit boundary ---- */
+ unsigned tq0 : 4;
+ unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
+ unsigned tq2 : 4;
+ unsigned tq3 : 4;
+} TIR, *pTIR;
+#define cbTIR sizeof(TIR)
+#define tiNil ((pTIR)0)
+#define itqMax 6
+
+/*
+ * Relative symbol record
+ *
+ * If the rfd field is 4095, the index field indexes into the global symbol
+ * table.
+ */
+
+typedef struct {
+ unsigned rfd : 12; /* index into the file indirect table */
+ unsigned index : 20; /* index int sym/aux/iss tables */
+} RNDXR, *pRNDXR;
+#define cbRNDXR sizeof(RNDXR)
+#define rndxNil ((pRNDXR)0)
+
+/* dense numbers or sometimes called block numbers are stored in this type,
+ * a rfd of 0xffffffff is an index into the global table.
+ */
+typedef struct {
+ coff_uint rfd; /* index into the file table */
+ coff_uint index; /* index int sym/aux/iss tables */
+} DNR, *pDNR;
+#define cbDNR sizeof(DNR)
+#define dnNil ((pDNR)0)
+
+
+
+/*
+ * Auxillary information occurs only if needed.
+ * It ALWAYS occurs in this order when present.
+
+ isymMac used by stProc only
+ TIR type info
+ TIR additional TQ info (if first TIR was not enough)
+ rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange,
+ btTypedef):
+ rsym.index == iaux for btSet or btRange
+ else rsym.index == isym
+ dimLow btRange, btSet
+ dimMac btRange, btSet
+ rndx0 As many as there are tq arrays
+ dimLow0
+ dimHigh0
+ ...
+ rndxMax-1
+ dimLowMax-1
+ dimHighMax-1
+ width in bits if (bit field), width in bits.
+ */
+#define cAuxMax (6 + (idimMax*3))
+
+/* a union of all possible info in the AUX universe */
+typedef union {
+ TIR ti; /* type information record */
+ RNDXR rndx; /* relative index into symbol table */
+ coff_int dnLow; /* low dimension */
+ coff_int dnHigh; /* high dimension */
+ coff_int isym; /* symbol table index (end of proc) */
+ coff_int iss; /* index into string space (not used) */
+ coff_int width; /* width for non-default sized struc fields */
+ coff_int count; /* count of ranges for variant arm */
+} AUXU, *pAUXU;
+#define cbAUXU sizeof(AUXU)
+#define auxNil ((pAUXU)0)
+#define iauxNil -1
+
+
+/*
+ * Optimization symbols
+ *
+ * Optimization symbols contain some overlap information with the normal
+ * symbol table. In particular, the proc information
+ * is somewhat redundant but necessary to easily find the other information
+ * present.
+ *
+ * All of the offsets are relative to the beginning of the last otProc
+ */
+
+typedef struct {
+ unsigned ot: 8; /* optimization type */
+ unsigned value: 24; /* address where we are moving it to */
+ RNDXR rndx; /* points to a symbol or opt entry */
+ coff_ulong offset; /* relative offset this occured */
+} OPTR, *pOPTR;
+#define optNil ((pOPTR) 0)
+#define cbOPTR sizeof(OPTR)
+#define ioptNil -1
+
+/*
+ * File Indirect
+ *
+ * When a symbol is referenced across files the following procedure is used:
+ * 1) use the file index to get the File indirect entry.
+ * 2) use the file indirect entry to get the File descriptor.
+ * 3) add the sym index to the base of that file's sym table
+ *
+ */
+
+typedef coff_long RFDT, *pRFDT;
+#define cbRFDT sizeof(RFDT)
+#define rfdNil -1
+
+/*
+ * The file indirect table in the mips loader is known as an array of FITs.
+ * This is done to keep the code in the loader readable in the area where
+ * these tables are merged. Note this is only a name change.
+ */
+typedef coff_int FIT, *pFIT;
+#define cbFIT sizeof(FIT)
+#define ifiNil -1
+#define fiNil ((pFIT) 0)
+
+#ifdef _LANGUAGE_PASCAL
+#define ifdNil -1
+#define ilnNil -1
+#define ipdNil -1
+#define ilineNil -1
+#define isymNil -1
+#define indexNil 16#fffff
+#define issNil -1
+#define issNull 0
+#define itqMax 6
+#define iauxNil -1
+#define ioptNil -1
+#define rfdNil -1
+#define ifiNil -1
+#endif /* _LANGUAGE_PASCAL */
+
+
+/* Dense numbers
+ *
+ * Rather than use file index, symbol index pairs to represent symbols
+ * and globals, we use dense number so that they can be easily embeded
+ * in intermediate code and the programs that process them can
+ * use direct access tabls instead of hash table (which would be
+ * necesary otherwise because of the sparse name space caused by
+ * file index, symbol index pairs. Dense number are represented
+ * by RNDXRs.
+ */
+
+/*
+ * The following table defines the meaning of each SYM field as
+ * a function of the "st". (scD/B == scData OR scBss)
+ *
+ * Note: the value "isymMac" is used by symbols that have the concept
+ * of enclosing a block of related information. This value is the
+ * isym of the first symbol AFTER the end associated with the primary
+ * symbol. For example if a procedure was at isym==90 and had an
+ * isymMac==155, the associated end would be at isym==154, and the
+ * symbol at 155 would probably (although not necessarily) be the
+ * symbol for the next procedure. This allows rapid skipping over
+ * internal information of various sorts. "stEnd"s ALWAYS have the
+ * isym of the primary symbol that started the block.
+ *
+
+ST SC VALUE INDEX
+-------- ------ -------- ------
+stFile scText address isymMac
+stLabel scText address ---
+stGlobal scD/B address iaux
+stStatic scD/B address iaux
+stParam scAbs offset iaux
+stLocal scAbs offset iaux
+stProc scText address iaux (isymMac is first AUX)
+stStaticProc scText address iaux (isymMac is first AUX)
+
+stMember scNil ordinal --- (if member of enum)
+ (mipsread thinks the case below has a bit, not byte, offset.)
+stMember scNil byte offset iaux (if member of struct/union)
+stMember scBits bit offset iaux (bit field spec)
+
+stBlock scText address isymMac (text block)
+ (the code seems to think that rather than scNil, we see scInfo for
+ the two cases below.)
+stBlock scNil cb isymMac (struct/union member define)
+stBlock scNil cMembers isymMac (enum member define)
+
+ (New types added by SGI to simplify things:)
+stStruct scInfo cb isymMac (struct type define)
+stUnion scInfo cb isymMac (union type define)
+stEnum scInfo cMembers isymMac (enum type define)
+
+stEnd scText address isymStart
+stEnd scNil ------- isymStart (struct/union/enum)
+
+stTypedef scNil ------- iaux
+stRegReloc sc??? value old register number
+stForward sc??? new address isym to original symbol
+
+stConstant scInfo value --- (scalar)
+stConstant scInfo iss --- (complex, e.g. string)
+
+ *
+ */
+#endif
diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h
new file mode 100644
index 000000000..f383c19e6
--- /dev/null
+++ b/src/base/loader/coff_symconst.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/*
+ * Taken from binutils-2.14.90.0.5 include/coff/symconst.h
+ */
+
+/* Declarations of constants for internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/* glevels for field in FDR */
+#define GLEVEL_0 2
+#define GLEVEL_1 1
+#define GLEVEL_2 0 /* for upward compat reasons. */
+#define GLEVEL_3 3
+
+/* magic number fo symheader */
+#define magicSym 0x7009
+/* The Alpha uses this value instead, for some reason. */
+#define magicSym2 0x1992
+
+/* Language codes */
+#define langC 0
+#define langPascal 1
+#define langFortran 2
+#define langAssembler 3 /* one Assembley inst might map to many mach */
+#define langMachine 4
+#define langNil 5
+#define langAda 6
+#define langPl1 7
+#define langCobol 8
+#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */
+#define langCplusplus 9 /* FIXME: Collides with langStdc */
+#define langCplusplusV2 10 /* SGI addition */
+#define langMax 11 /* maximun allowed 32 -- 5 bits */
+
+/* The following are value definitions for the fields in the SYMR */
+
+/*
+ * Storage Classes
+ */
+
+#define scNil 0
+#define scText 1 /* text symbol */
+#define scData 2 /* initialized data symbol */
+#define scBss 3 /* un-initialized data symbol */
+#define scRegister 4 /* value of symbol is register number */
+#define scAbs 5 /* value of symbol is absolute */
+#define scUndefined 6 /* who knows? */
+#define scCdbLocal 7 /* variable's value is IN se->va.?? */
+#define scBits 8 /* this is a bit field */
+#define scCdbSystem 9 /* variable's value is IN CDB's address space */
+#define scDbx 9 /* overlap dbx internal use */
+#define scRegImage 10 /* register value saved on stack */
+#define scInfo 11 /* symbol contains debugger information */
+#define scUserStruct 12 /* address in struct user for current process */
+#define scSData 13 /* load time only small data */
+#define scSBss 14 /* load time only small common */
+#define scRData 15 /* load time only read only data */
+#define scVar 16 /* Var parameter (fortran,pascal) */
+#define scCommon 17 /* common variable */
+#define scSCommon 18 /* small common */
+#define scVarRegister 19 /* Var parameter in a register */
+#define scVariant 20 /* Variant record */
+#define scSUndefined 21 /* small undefined(external) data */
+#define scInit 22 /* .init section symbol */
+#define scBasedVar 23 /* Fortran or PL/1 ptr based var */
+#define scXData 24 /* exception handling data */
+#define scPData 25 /* Procedure section */
+#define scFini 26 /* .fini section */
+#define scRConst 27 /* .rconst section */
+#define scMax 32
+
+
+/*
+ * Symbol Types
+ */
+
+#define stNil 0 /* Nuthin' special */
+#define stGlobal 1 /* external symbol */
+#define stStatic 2 /* static */
+#define stParam 3 /* procedure argument */
+#define stLocal 4 /* local variable */
+#define stLabel 5 /* label */
+#define stProc 6 /* " " Procedure */
+#define stBlock 7 /* beginnning of block */
+#define stEnd 8 /* end (of anything) */
+#define stMember 9 /* member (of anything - struct/union/enum */
+#define stTypedef 10 /* type definition */
+#define stFile 11 /* file name */
+#define stRegReloc 12 /* register relocation */
+#define stForward 13 /* forwarding address */
+#define stStaticProc 14 /* load time only static procs */
+#define stConstant 15 /* const */
+#define stStaParam 16 /* Fortran static parameters */
+ /* These new symbol types have been recently added to SGI machines. */
+#define stStruct 26 /* Beginning of block defining a struct type */
+#define stUnion 27 /* Beginning of block defining a union type */
+#define stEnum 28 /* Beginning of block defining an enum type */
+#define stIndirect 34 /* Indirect type specification */
+ /* Pseudo-symbols - internal to debugger */
+#define stStr 60 /* string */
+#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */
+#define stExpr 62 /* 2+2 vs. 4 */
+#define stType 63 /* post-coersion SER */
+#define stMax 64
+
+/* definitions for fields in TIR */
+
+/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */
+#define tqNil 0 /* bt is what you see */
+#define tqPtr 1 /* pointer */
+#define tqProc 2 /* procedure */
+#define tqArray 3 /* duh */
+#define tqFar 4 /* longer addressing - 8086/8 land */
+#define tqVol 5 /* volatile */
+#define tqConst 6 /* const */
+#define tqMax 8
+
+/* basic types as seen in ti.bt */
+#define btNil 0 /* undefined (also, enum members) */
+#define btAdr 1 /* address - integer same size as pointer */
+#define btChar 2 /* character */
+#define btUChar 3 /* unsigned character */
+#define btShort 4 /* short */
+#define btUShort 5 /* unsigned short */
+#define btInt 6 /* int */
+#define btUInt 7 /* unsigned int */
+#define btLong 8 /* long */
+#define btULong 9 /* unsigned long */
+#define btFloat 10 /* float (real) */
+#define btDouble 11 /* Double (real) */
+#define btStruct 12 /* Structure (Record) */
+#define btUnion 13 /* Union (variant) */
+#define btEnum 14 /* Enumerated */
+#define btTypedef 15 /* defined via a typedef, isymRef points */
+#define btRange 16 /* subrange of int */
+#define btSet 17 /* pascal sets */
+#define btComplex 18 /* fortran complex */
+#define btDComplex 19 /* fortran double complex */
+#define btIndirect 20 /* forward or unnamed typedef */
+#define btFixedDec 21 /* Fixed Decimal */
+#define btFloatDec 22 /* Float Decimal */
+#define btString 23 /* Varying Length Character String */
+#define btBit 24 /* Aligned Bit String */
+#define btPicture 25 /* Picture */
+#define btVoid 26 /* void */
+#define btLongLong 27 /* long long */
+#define btULongLong 28 /* unsigned long long */
+#define btMax 64
diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc
new file mode 100644
index 000000000..80917ee9c
--- /dev/null
+++ b/src/base/loader/ecoff_object.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/loader/ecoff_object.hh"
+#include "base/misc.hh"
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "base/loader/exec_ecoff.h"
+#include "base/loader/coff_sym.h"
+#include "base/loader/coff_symconst.h"
+
+using namespace std;
+
+ObjectFile *
+EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) {
+ // it's Alpha ECOFF
+ return new EcoffObject(fname, fd, len, data,
+ ObjectFile::Alpha, ObjectFile::Tru64);
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+EcoffObject::EcoffObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+{
+ execHdr = (ecoff_exechdr *)fileData;
+ fileHdr = &(execHdr->f);
+ aoutHdr = &(execHdr->a);
+
+ entry = aoutHdr->entry;
+
+ text.baseAddr = aoutHdr->text_start;
+ text.size = aoutHdr->tsize;
+ text.fileImage = fileData + ECOFF_TXTOFF(execHdr);
+
+ data.baseAddr = aoutHdr->data_start;
+ data.size = aoutHdr->dsize;
+ data.fileImage = fileData + ECOFF_DATOFF(execHdr);
+
+ bss.baseAddr = aoutHdr->bss_start;
+ bss.size = aoutHdr->bsize;
+ bss.fileImage = NULL;
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+}
+
+
+bool
+EcoffObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
+ warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+ if (syms->magic != magicSym2) {
+ warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset);
+
+ char *ext_strings = (char *)(fileData + syms->cbSsExtOffset);
+ for (int i = 0; i < syms->iextMax; i++) {
+ ecoff_sym *entry = &(ext_syms[i].asym);
+ if (entry->iss != -1)
+ symtab->insert(entry->value, ext_strings + entry->iss);
+ }
+
+ return true;
+}
+
+bool
+EcoffObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
+ warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+ if (syms->magic != magicSym2) {
+ warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset);
+ char *local_strings = (char *)(fileData + syms->cbSsOffset);
+ ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset);
+
+ for (int i = 0; i < syms->ifdMax; i++) {
+ ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase);
+ char *strings = (char *)(local_strings + fdesc[i].issBase);
+ for (int j = 0; j < fdesc[i].csym; j++) {
+ if (entry[j].st == stGlobal || entry[j].st == stProc)
+ if (entry[j].iss != -1)
+ symtab->insert(entry[j].value, strings + entry[j].iss);
+ }
+ }
+
+ for (int i = 0; i < syms->isymMax; i++) {
+ ecoff_sym *entry = &(local_syms[i]);
+ if (entry->st == stProc)
+ symtab->insert(entry->value, local_strings + entry->iss);
+ }
+
+ return true;
+}
diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh
new file mode 100644
index 000000000..603c70bec
--- /dev/null
+++ b/src/base/loader/ecoff_object.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ECOFF_OBJECT_HH__
+#define __ECOFF_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+// forward decls: avoid including exec_ecoff.h here
+struct ecoff_exechdr;
+struct ecoff_filehdr;
+struct ecoff_aouthdr;
+
+class EcoffObject : public ObjectFile
+{
+ protected:
+ ecoff_exechdr *execHdr;
+ ecoff_filehdr *fileHdr;
+ ecoff_aouthdr *aoutHdr;
+
+ EcoffObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~EcoffObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __ECOFF_OBJECT_HH__
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
new file mode 100644
index 000000000..165501e1c
--- /dev/null
+++ b/src/base/loader/elf_object.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+// Because of the -Wundef flag we have to do this
+#define __LIBELF_INTERNAL__ 0
+// counterintuitive, but the flag below causes libelf to define
+// 64-bit elf types that apparently didn't exist in some older
+// versions of Linux. They seem to be there in 2.4.x, so don't
+// set this now (it causes things to break on 64-bit platforms).
+#define __LIBELF64_LINUX 0
+#define __LIBELF_NEED_LINK_H 0
+#define __LIBELF_SYMBOL_VERSIONS 0
+
+#include "libelf/libelf.h"
+#include "libelf/gelf.h"
+
+#include "base/loader/elf_object.hh"
+#include "base/misc.hh"
+
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "sim/byteswap.hh"
+
+
+using namespace std;
+
+ObjectFile *
+ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ Arch arch = UnknownArch;
+ OpSys opSys = UnknownOpSys;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)data,len);
+ // will only fail if fd is invalid
+ assert(elf != NULL);
+
+ // Check that we actually have a elf file
+ if (gelf_getehdr(elf, &ehdr) ==0) {
+ DPRINTFR(Loader, "Not ELF\n");
+ elf_end(elf);
+ return NULL;
+ } else {
+ //Detect the architecture
+ //Since we don't know how to check for alpha right now, we'll
+ //just assume if it wasn't something else and it's 64 bit, that's
+ //what it must be.
+ if (ehdr.e_machine == EM_SPARC64 ||
+ ehdr.e_machine == EM_SPARC ||
+ ehdr.e_machine == EM_SPARCV9) {
+ arch = ObjectFile::SPARC;
+ } else if (ehdr.e_machine == EM_MIPS
+ && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ arch = ObjectFile::Mips;
+ } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ arch = ObjectFile::Alpha;
+ } else {
+ warn("Unknown architecture: %d\n", ehdr.e_machine);
+ arch = ObjectFile::UnknownArch;
+ }
+
+ //Detect the operating system
+ switch (ehdr.e_ident[EI_OSABI])
+ {
+
+ case ELFOSABI_LINUX:
+ opSys = ObjectFile::Linux;
+ break;
+ case ELFOSABI_SOLARIS:
+ opSys = ObjectFile::Solaris;
+ break;
+ case ELFOSABI_TRU64:
+ opSys = ObjectFile::Tru64;
+ break;
+ default:
+ opSys = ObjectFile::UnknownOpSys;
+ }
+
+ //take a look at the .note.ABI section
+ //It can let us know what's what.
+ if (opSys == ObjectFile::UnknownOpSys) {
+ Elf_Scn *section;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ uint32_t osAbi;;
+ int secIdx = 1;
+
+ // Get the first section
+ section = elf_getscn(elf, secIdx);
+
+ // While there are no more sections
+ while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
+ gelf_getshdr(section, &shdr);
+ if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
+ elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
+ // we have found a ABI note section
+ // Check the 5th 32bit word for OS 0 == linux, 1 == hurd,
+ // 2 == solaris, 3 == freebsd
+ data = elf_rawdata(section, NULL);
+ assert(data->d_buf);
+ if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+ osAbi = htole(((uint32_t*)data->d_buf)[4]);
+ else
+ osAbi = htobe(((uint32_t*)data->d_buf)[4]);
+
+ switch(osAbi) {
+ case 0:
+ opSys = ObjectFile::Linux;
+ break;
+ case 2:
+ opSys = ObjectFile::Solaris;
+ break;
+ }
+ } // if section found
+ if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+ opSys = ObjectFile::Solaris;
+ if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+ opSys = ObjectFile::Solaris;
+
+ section = elf_getscn(elf, ++secIdx);
+ } // while sections
+ }
+
+ elf_end(elf);
+ return new ElfObject(fname, fd, len, data, arch, opSys);
+ }
+}
+
+
+ElfObject::ElfObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+
+{
+ Elf *elf;
+ GElf_Ehdr ehdr;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)fileData,len);
+ // will only fail if fd is invalid
+ assert(elf != NULL);
+
+ // Check that we actually have a elf file
+ if (gelf_getehdr(elf, &ehdr) ==0) {
+ panic("Not ELF, shouldn't be here");
+ }
+
+ entry = ehdr.e_entry;
+
+
+ // initialize segment sizes to 0 in case they're not present
+ text.size = data.size = bss.size = 0;
+
+ for (int i = 0; i < ehdr.e_phnum; ++i) {
+ GElf_Phdr phdr;
+ if (gelf_getphdr(elf, i, &phdr) == 0) {
+ panic("gelf_getphdr failed for section %d", i);
+ }
+
+ // for now we don't care about non-loadable segments
+ if (!(phdr.p_type & PT_LOAD))
+ continue;
+
+ // the headers don't explicitly distinguish text from data,
+ // but empirically the text segment comes first.
+ if (text.size == 0) { // haven't seen text segment yet
+ text.baseAddr = phdr.p_vaddr;
+ text.size = phdr.p_filesz;
+ text.fileImage = fileData + phdr.p_offset;
+ // if there's any padding at the end that's not in the
+ // file, call it the bss. This happens in the "text"
+ // segment if there's only one loadable segment (as for
+ // kernel images).
+ bss.size = phdr.p_memsz - phdr.p_filesz;
+ bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+ bss.fileImage = NULL;
+ } else if (data.size == 0) { // have text, this must be data
+ data.baseAddr = phdr.p_vaddr;
+ data.size = phdr.p_filesz;
+ data.fileImage = fileData + phdr.p_offset;
+ // if there's any padding at the end that's not in the
+ // file, call it the bss. Warn if this happens for both
+ // the text & data segments (should only have one bss).
+ if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
+ warn("Two implied bss segments in file!\n");
+ }
+ bss.size = phdr.p_memsz - phdr.p_filesz;
+ bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+ bss.fileImage = NULL;
+ } else {
+ warn("More than two loadable segments in ELF object.");
+ warn("Ignoring segment @ 0x%x length 0x%x.",
+ phdr.p_vaddr, phdr.p_filesz);
+ }
+ }
+
+ // should have found at least one loadable segment
+ assert(text.size != 0);
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+
+ elf_end(elf);
+
+ // We will actually read the sections when we need to load them
+}
+
+
+bool
+ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
+{
+ Elf *elf;
+ int sec_idx = 1; // there is a 0 but it is nothing, go figure
+ Elf_Scn *section;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ int count, ii;
+ bool found = false;
+ GElf_Sym sym;
+
+ if (!symtab)
+ return false;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)fileData,len);
+
+ assert(elf != NULL);
+
+ // Get the first section
+ section = elf_getscn(elf, sec_idx);
+
+ // While there are no more sections
+ while (section != NULL) {
+ gelf_getshdr(section, &shdr);
+
+ if (shdr.sh_type == SHT_SYMTAB) {
+ found = true;
+ data = elf_getdata(section, NULL);
+ count = shdr.sh_size / shdr.sh_entsize;
+ DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
+
+ // loop through all the symbols, only loading global ones
+ for (ii = 0; ii < count; ++ii) {
+ gelf_getsym(data, ii, &sym);
+ if (GELF_ST_BIND(sym.st_info) == binding) {
+ symtab->insert(sym.st_value,
+ elf_strptr(elf, shdr.sh_link, sym.st_name));
+ }
+ }
+ }
+ ++sec_idx;
+ section = elf_getscn(elf, sec_idx);
+ }
+
+ elf_end(elf);
+
+ return found;
+}
+
+bool
+ElfObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ return loadSomeSymbols(symtab, STB_GLOBAL);
+}
+
+bool
+ElfObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ return loadSomeSymbols(symtab, STB_LOCAL);
+}
diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh
new file mode 100644
index 000000000..72c265edd
--- /dev/null
+++ b/src/base/loader/elf_object.hh
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ELF_OBJECT_HH__
+#define __ELF_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+class ElfObject : public ObjectFile
+{
+ protected:
+
+ /// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
+ bool loadSomeSymbols(SymbolTable *symtab, int binding);
+
+ ElfObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~ElfObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __ELF_OBJECT_HH__
diff --git a/src/base/loader/exec_aout.h b/src/base/loader/exec_aout.h
new file mode 100644
index 000000000..eed44baee
--- /dev/null
+++ b/src/base/loader/exec_aout.h
@@ -0,0 +1,61 @@
+/*
+ * Taken from NetBSD sys/exec_aout.h
+ */
+
+/* $NetBSD: exec_aout.h,v 1.29 2002/12/10 17:14:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1993, 1994 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _SYS_EXEC_AOUT_H_
+#define _SYS_EXEC_AOUT_H_
+
+#ifndef N_PAGSIZ
+#define N_PAGSIZ(ex) (AOUT_LDPGSZ)
+#endif
+
+/* a_magic */
+#define OMAGIC 0407 /* old impure format */
+#define NMAGIC 0410 /* read-only text */
+#define ZMAGIC 0413 /* demand load format */
+
+#define N_ALIGN(ex,x) \
+ (N_GETMAGIC(ex) == ZMAGIC ? \
+ ((x) + AOUT_LDPGSZ - 1) & ~(AOUT_LDPGSZ - 1) : (x))
+
+/* Valid magic number check. */
+#define N_BADMAG(ex) \
+ (N_GETMAGIC(ex) != NMAGIC && N_GETMAGIC(ex) != OMAGIC && \
+ N_GETMAGIC(ex) != ZMAGIC)
+
+//Only alpha will be able to load aout for now
+#include "arch/alpha/aout_machdep.h"
+
+#endif /* !_SYS_EXEC_AOUT_H_ */
diff --git a/src/base/loader/exec_ecoff.h b/src/base/loader/exec_ecoff.h
new file mode 100644
index 000000000..555589806
--- /dev/null
+++ b/src/base/loader/exec_ecoff.h
@@ -0,0 +1,110 @@
+/*
+ * Taken from NetBSD sys/exec_ecoff.h
+ */
+
+/* $NetBSD: exec_ecoff.h,v 1.13 2003/01/18 09:53:18 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Glass.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _SYS_EXEC_ECOFF_H_
+#define _SYS_EXEC_ECOFF_H_
+
+//Only alpha will be able to load ecoff files for now
+#include "arch/alpha/ecoff_machdep.h"
+
+struct ecoff_filehdr {
+ coff_ushort f_magic; /* magic number */
+ coff_ushort f_nscns; /* # of sections */
+ coff_uint f_timdat; /* time and date stamp */
+ coff_ulong f_symptr; /* file offset of symbol table */
+ coff_uint f_nsyms; /* # of symbol table entries */
+ coff_ushort f_opthdr; /* sizeof the optional header */
+ coff_ushort f_flags; /* flags??? */
+};
+
+struct ecoff_aouthdr {
+ coff_ushort magic;
+ coff_ushort vstamp;
+ ECOFF_PAD
+ coff_ulong tsize;
+ coff_ulong dsize;
+ coff_ulong bsize;
+ coff_ulong entry;
+ coff_ulong text_start;
+ coff_ulong data_start;
+ coff_ulong bss_start;
+ ECOFF_MACHDEP;
+};
+
+struct ecoff_scnhdr { /* needed for size info */
+ char s_name[8]; /* name */
+ coff_ulong s_paddr; /* physical addr? for ROMing?*/
+ coff_ulong s_vaddr; /* virtual addr? */
+ coff_ulong s_size; /* size */
+ coff_ulong s_scnptr; /* file offset of raw data */
+ coff_ulong s_relptr; /* file offset of reloc data */
+ coff_ulong s_lnnoptr; /* file offset of line data */
+ coff_ushort s_nreloc; /* # of relocation entries */
+ coff_ushort s_nlnno; /* # of line entries */
+ coff_uint s_flags; /* flags */
+};
+
+struct ecoff_exechdr {
+ struct ecoff_filehdr f;
+ struct ecoff_aouthdr a;
+};
+
+#define ECOFF_HDR_SIZE (sizeof(struct ecoff_exechdr))
+
+#define ECOFF_OMAGIC 0407
+#define ECOFF_NMAGIC 0410
+#define ECOFF_ZMAGIC 0413
+
+#define ECOFF_ROUND(value, by) \
+ (((value) + (by) - 1) & ~((by) - 1))
+
+#define ECOFF_BLOCK_ALIGN(ep, value) \
+ ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_ROUND((value), ECOFF_LDPGSZ) : \
+ (value))
+
+#define ECOFF_TXTOFF(ep) \
+ ((ep)->a.magic == ECOFF_ZMAGIC ? 0 : \
+ ECOFF_ROUND(ECOFF_HDR_SIZE + (ep)->f.f_nscns * \
+ sizeof(struct ecoff_scnhdr), ECOFF_SEGMENT_ALIGNMENT(ep)))
+
+#define ECOFF_DATOFF(ep) \
+ (ECOFF_BLOCK_ALIGN((ep), ECOFF_TXTOFF(ep) + (ep)->a.tsize))
+
+#define ECOFF_SEGMENT_ALIGN(ep, value) \
+ (ECOFF_ROUND((value), ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_LDPGSZ : \
+ ECOFF_SEGMENT_ALIGNMENT(ep))))
+
+#endif /* !_SYS_EXEC_ECOFF_H_ */
diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc
new file mode 100644
index 000000000..c6dfced1d
--- /dev/null
+++ b/src/base/loader/object_file.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2002-2004 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.
+ */
+
+#include <list>
+#include <string>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "base/cprintf.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+
+#include "base/loader/ecoff_object.hh"
+#include "base/loader/aout_object.hh"
+#include "base/loader/elf_object.hh"
+
+#include "mem/translating_port.hh"
+
+using namespace std;
+
+ObjectFile::ObjectFile(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : filename(_filename), descriptor(_fd), fileData(_data), len(_len),
+ arch(_arch), opSys(_opSys)
+{
+}
+
+
+ObjectFile::~ObjectFile()
+{
+ close();
+}
+
+
+bool
+ObjectFile::loadSection(Section *sec, Port *memPort, Addr addrMask)
+{
+ if (sec->size != 0) {
+ Addr addr = sec->baseAddr & addrMask;
+ if (sec->fileImage) {
+ memPort->writeBlob(addr, sec->fileImage, sec->size);
+ }
+ else {
+ // no image: must be bss
+ memPort->memsetBlob(addr, 0, sec->size);
+ }
+ }
+ return true;
+}
+
+
+bool
+ObjectFile::loadSections(Port *memPort, Addr addrMask)
+{
+ return (loadSection(&text, memPort, addrMask)
+ && loadSection(&data, memPort, addrMask)
+ && loadSection(&bss, memPort, addrMask));
+}
+
+
+void
+ObjectFile::close()
+{
+ if (descriptor >= 0) {
+ ::close(descriptor);
+ descriptor = -1;
+ }
+
+ if (fileData) {
+ ::munmap(fileData, len);
+ fileData = NULL;
+ }
+}
+
+
+ObjectFile *
+createObjectFile(const string &fname)
+{
+ // open the file
+ int fd = open(fname.c_str(), O_RDONLY);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ // find the length of the file by seeking to the end
+ size_t len = (size_t)lseek(fd, 0, SEEK_END);
+
+ // mmap the whole shebang
+ uint8_t *fileData =
+ (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+ if (fileData == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+ ObjectFile *fileObj = NULL;
+
+ // figure out what we have here
+ if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ // don't know what it is
+ close(fd);
+ munmap(fileData, len);
+ return NULL;
+}
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
new file mode 100644
index 000000000..b43989cb5
--- /dev/null
+++ b/src/base/loader/object_file.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2002-2004 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.
+ */
+
+#ifndef __OBJECT_FILE_HH__
+#define __OBJECT_FILE_HH__
+
+#include <limits>
+#include <string>
+
+#include "sim/host.hh" // for Addr
+
+class Port;
+class SymbolTable;
+
+class ObjectFile
+{
+ public:
+
+ enum Arch {
+ UnknownArch,
+ Alpha,
+ SPARC,
+ Mips
+ };
+
+ enum OpSys {
+ UnknownOpSys,
+ Tru64,
+ Linux,
+ Solaris
+ };
+
+ protected:
+ const std::string filename;
+ int descriptor;
+ uint8_t *fileData;
+ size_t len;
+
+ Arch arch;
+ OpSys opSys;
+
+ ObjectFile(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~ObjectFile();
+
+ void close();
+
+ virtual bool loadSections(Port *memPort, Addr addrMask =
+ std::numeric_limits<Addr>::max());
+ virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0;
+ virtual bool loadLocalSymbols(SymbolTable *symtab) = 0;
+
+ Arch getArch() const { return arch; }
+ OpSys getOpSys() const { return opSys; }
+
+ protected:
+
+ struct Section {
+ Addr baseAddr;
+ uint8_t *fileImage;
+ size_t size;
+ };
+
+ Addr entry;
+ Addr globalPtr;
+
+ Section text;
+ Section data;
+ Section bss;
+
+ bool loadSection(Section *sec, Port *memPort, Addr addrMask);
+ void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; }
+
+ public:
+ Addr entryPoint() const { return entry; }
+
+ Addr globalPointer() const { return globalPtr; }
+
+ Addr textBase() const { return text.baseAddr; }
+ Addr dataBase() const { return data.baseAddr; }
+ Addr bssBase() const { return bss.baseAddr; }
+
+ size_t textSize() const { return text.size; }
+ size_t dataSize() const { return data.size; }
+ size_t bssSize() const { return bss.size; }
+};
+
+ObjectFile *createObjectFile(const std::string &fname);
+
+
+#endif // __OBJECT_FILE_HH__
diff --git a/src/base/loader/symtab.cc b/src/base/loader/symtab.cc
new file mode 100644
index 000000000..25f54f9bf
--- /dev/null
+++ b/src/base/loader/symtab.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/str.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+SymbolTable *debugSymbolTable = NULL;
+
+void
+SymbolTable::clear()
+{
+ addrTable.clear();
+ symbolTable.clear();
+}
+
+bool
+SymbolTable::insert(Addr address, string symbol)
+{
+ if (symbol.empty())
+ return false;
+
+ if (!addrTable.insert(make_pair(address, symbol)).second)
+ return false;
+
+ if (!symbolTable.insert(make_pair(symbol, address)).second)
+ return false;
+
+ return true;
+}
+
+
+bool
+SymbolTable::load(const string &filename)
+{
+ string buffer;
+ ifstream file(filename.c_str());
+
+ if (!file)
+ fatal("file error: Can't open symbol table file %s\n", filename);
+
+ while (!file.eof()) {
+ getline(file, buffer);
+ if (buffer.empty())
+ continue;
+
+ int idx = buffer.find(',');
+ if (idx == string::npos)
+ return false;
+
+ string address = buffer.substr(0, idx);
+ eat_white(address);
+ if (address.empty())
+ return false;
+
+ string symbol = buffer.substr(idx + 1);
+ eat_white(symbol);
+ if (symbol.empty())
+ return false;
+
+ Addr addr;
+ if (!to_number(address, addr))
+ return false;
+
+ if (!insert(addr, symbol))
+ return false;
+ }
+
+ file.close();
+
+ return true;
+}
+
+void
+SymbolTable::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".size", addrTable.size());
+
+ int i = 0;
+ ATable::const_iterator p, end = addrTable.end();
+ for (p = addrTable.begin(); p != end; ++p) {
+ paramOut(os, csprintf("%s.addr_%d", base, i), p->first);
+ paramOut(os, csprintf("%s.symbol_%d", base, i), p->second);
+ ++i;
+ }
+}
+
+void
+SymbolTable::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ clear();
+ int size;
+ paramIn(cp, section, base + ".size", size);
+ for (int i = 0; i < size; ++i) {
+ Addr addr;
+ std::string symbol;
+
+ paramIn(cp, section, csprintf("%s.addr_%d", base, i), addr);
+ paramIn(cp, section, csprintf("%s.symbol_%d", base, i), symbol);
+ insert(addr, symbol);
+ }
+}
diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh
new file mode 100644
index 000000000..ebcda1345
--- /dev/null
+++ b/src/base/loader/symtab.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SYMTAB_HH__
+#define __SYMTAB_HH__
+
+#include <iosfwd>
+#include <map>
+
+#include "arch/isa_traits.hh" // for Addr
+
+class Checkpoint;
+class SymbolTable
+{
+ public:
+ typedef std::map<Addr, std::string> ATable;
+ typedef std::map<std::string, Addr> STable;
+
+ private:
+ ATable addrTable;
+ STable symbolTable;
+
+ private:
+ bool
+ upperBound(Addr addr, ATable::const_iterator &iter) const
+ {
+ // find first key *larger* than desired address
+ iter = addrTable.upper_bound(addr);
+
+ // if very first key is larger, we're out of luck
+ if (iter == addrTable.begin())
+ return false;
+
+ return true;
+ }
+
+ public:
+ SymbolTable() {}
+ SymbolTable(const std::string &file) { load(file); }
+ ~SymbolTable() {}
+
+ void clear();
+ bool insert(Addr address, std::string symbol);
+ bool load(const std::string &file);
+
+ const ATable &getAddrTable() const { return addrTable; }
+ const STable &getSymbolTable() const { return symbolTable; }
+
+ public:
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+
+ public:
+ bool
+ findSymbol(Addr address, std::string &symbol) const
+ {
+ ATable::const_iterator i = addrTable.find(address);
+ if (i == addrTable.end())
+ return false;
+
+ symbol = (*i).second;
+ return true;
+ }
+
+ bool
+ findAddress(const std::string &symbol, Addr &address) const
+ {
+ STable::const_iterator i = symbolTable.find(symbol);
+ if (i == symbolTable.end())
+ return false;
+
+ address = (*i).second;
+ return true;
+ }
+
+ /// Find the nearest symbol equal to or less than the supplied
+ /// address (e.g., the label for the enclosing function).
+ /// @param address The address to look up.
+ /// @param symbol Return reference for symbol string.
+ /// @param sym_address Return reference for symbol address.
+ /// @param next_sym_address Address of following symbol (for
+ /// determining valid range of symbol).
+ /// @retval True if a symbol was found.
+ bool
+ findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr,
+ Addr &nextaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ nextaddr = i->first;
+ --i;
+ symaddr = i->first;
+ symbol = i->second;
+ return true;
+ }
+
+ /// Overload for findNearestSymbol() for callers who don't care
+ /// about next_sym_address.
+ bool
+ findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ --i;
+ symaddr = i->first;
+ symbol = i->second;
+ return true;
+ }
+
+
+ bool
+ findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ nextaddr = i->first;
+ --i;
+ symaddr = i->first;
+ return true;
+ }
+
+ bool
+ findNearestAddr(Addr addr, Addr &symaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ --i;
+ symaddr = i->first;
+ return true;
+ }
+};
+
+/// Global unified debugging symbol table (for target). Conceptually
+/// there should be one of these per System object for full system,
+/// and per Process object for non-full-system, but so far one big
+/// global one has worked well enough.
+extern SymbolTable *debugSymbolTable;
+
+#endif // __SYMTAB_HH__
diff --git a/src/base/match.cc b/src/base/match.cc
new file mode 100644
index 000000000..4f1f49b57
--- /dev/null
+++ b/src/base/match.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/match.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+ObjectMatch::ObjectMatch()
+{
+}
+
+ObjectMatch::ObjectMatch(const string &expr)
+{
+ setExpression(expr);
+}
+
+void
+ObjectMatch::setExpression(const string &expr)
+{
+ tokens.resize(1);
+ tokenize(tokens[0], expr, '.');
+}
+
+void
+ObjectMatch::setExpression(const vector<string> &expr)
+{
+ if (expr.empty()) {
+ tokens.resize(0);
+ } else {
+ tokens.resize(expr.size());
+ for (int i = 0; i < expr.size(); ++i)
+ tokenize(tokens[i], expr[i], '.');
+ }
+}
+
+/**
+ * @todo this should probably be changed to just use regular
+ * expression code
+ */
+bool
+ObjectMatch::domatch(const string &name) const
+{
+ vector<string> name_tokens;
+ tokenize(name_tokens, name, '.');
+ int ntsize = name_tokens.size();
+
+ int num_expr = tokens.size();
+ for (int i = 0; i < num_expr; ++i) {
+ const vector<string> &token = tokens[i];
+ int jstop = token.size();
+
+ bool match = true;
+ for (int j = 0; j < jstop; ++j) {
+ if (j >= ntsize)
+ break;
+
+ const string &var = token[j];
+ if (var != "*" && var != name_tokens[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match == true)
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/src/base/match.hh b/src/base/match.hh
new file mode 100644
index 000000000..1b0a083a7
--- /dev/null
+++ b/src/base/match.hh
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __BASE_MATCH_HH__
+#define __BASE_MATCH_HH__
+
+#include <string>
+#include <vector>
+
+class ObjectMatch
+{
+ protected:
+ std::vector<std::vector<std::string> > tokens;
+ bool domatch(const std::string &name) const;
+
+ public:
+ ObjectMatch();
+ ObjectMatch(const std::string &expression);
+ void setExpression(const std::string &expression);
+ void setExpression(const std::vector<std::string> &expression);
+ bool match(const std::string &name) const
+ {
+ return tokens.empty() ? false : domatch(name);
+ }
+};
+
+#endif // __BASE_MATCH_HH__
+
diff --git a/src/base/misc.cc b/src/base/misc.cc
new file mode 100644
index 000000000..f3c86827b
--- /dev/null
+++ b/src/base/misc.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "base/cprintf.hh"
+#include "base/hostinfo.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/trace.hh"
+#include "sim/host.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+void
+__panic(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "panic: " + format;
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+ abort();
+}
+
+void
+__fatal(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "fatal: " + format;
+
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+ fmt += "Memory Usage: %ld KBytes\n";
+
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.append(memUsage());
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+ exit(1);
+}
+
+void
+__warn(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "warn: " + format;
+
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+#ifdef VERBOSE_WARN
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+#endif
+
+ args.dump(cerr, fmt);
+ if (simout.isFile(*outputStream))
+ args.dump(*outputStream, fmt);
+
+ delete &args;
+}
diff --git a/src/base/misc.hh b/src/base/misc.hh
new file mode 100644
index 000000000..9255c69c6
--- /dev/null
+++ b/src/base/misc.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MISC_HH__
+#define __MISC_HH__
+
+#include <assert.h>
+#include "base/cprintf.hh"
+
+//
+// This implements a cprintf based panic() function. panic() should
+// be called when something happens that should never ever happen
+// regardless of what the user does (i.e., an acutal m5 bug). panic()
+// calls abort which can dump core or enter the debugger.
+//
+//
+void __panic(const std::string&, cp::ArgList &, const char*, const char*, int)
+ __attribute__((noreturn));
+#define __panic__(format, args...) \
+ __panic(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define panic(args...) \
+ __panic__(args, cp::ArgListNull())
+
+//
+// This implements a cprintf based fatal() function. fatal() should
+// be called when the simulation cannot continue due to some condition
+// that is the user's fault (bad configuration, invalid arguments,
+// etc.) and not a simulator bug. fatal() calls exit(1), i.e., a
+// "normal" exit with an error code, as opposed to abort() like
+// panic() does.
+//
+void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int)
+ __attribute__((noreturn));
+#define __fatal__(format, args...) \
+ __fatal(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define fatal(args...) \
+ __fatal__(args, cp::ArgListNull())
+
+//
+// This implements a cprintf based warn
+//
+void __warn(const std::string&, cp::ArgList &, const char*, const char*, int);
+#define __warn__(format, args...) \
+ __warn(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define warn(args...) \
+ __warn__(args, cp::ArgListNull())
+
+//
+// assert() that prints out the current cycle
+//
+#define m5_assert(TEST) \
+ if (!(TEST)) { \
+ std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \
+ } \
+ assert(TEST);
+
+#endif // __MISC_HH__
diff --git a/src/base/mod_num.hh b/src/base/mod_num.hh
new file mode 100644
index 000000000..fabbb56a9
--- /dev/null
+++ b/src/base/mod_num.hh
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+template<class T, T MV>
+class ModNum {
+ private:
+ T value;
+
+ // Compiler should optimize this
+ void setValue(T n) { value = n % MV; }
+
+ public:
+ ModNum() {}
+ ModNum(T n) { setValue(n); }
+ ModNum(const ModNum<T, MV> &n) : value(n.value) {}
+
+ ModNum operator=(T n) {
+ setValue(n);
+ return *this;
+ }
+
+ const ModNum operator=(ModNum n) {
+ value = n.value;
+ return *this;
+ }
+
+ // Return the value if object used as RHS
+ operator T() const { return value; }
+
+ //
+ // Operator "+="
+ //
+ const ModNum<T, MV> operator+=(ModNum<T, MV> r) {
+ setValue(value + r.value);
+ return *this;
+ }
+
+ const ModNum<T, MV> operator+=(T r) {
+ setValue(value + r);
+ return *this;
+ }
+
+ //
+ // Operator "-="
+ //
+ const ModNum<T, MV> operator-=(ModNum<T, MV> r) {
+ setValue(value - r.value);
+ return *this;
+ }
+
+ const ModNum<T, MV> operator-=(T r) {
+ setValue(value - r);
+ return *this;
+ }
+
+ //
+ // Operator "++"
+ //
+ // PREFIX (like ++a)
+ const ModNum<T, MV> operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ // POSTFIX (like a++)
+ const ModNum<T, MV> operator++(int) {
+ ModNum<T, MV> rv = *this;
+
+ *this += 1;
+
+ return rv;
+ }
+
+ //
+ // Operator "--"
+ //
+ // PREFIX (like --a)
+ const ModNum<T, MV> operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ // POSTFIX (like a--)
+ const ModNum<T, MV> operator--(int) {
+ ModNum<T, MV> rv = *this;
+ *this -= 1;
+ return rv;
+ }
+};
+
+
+//
+// Define operator "+" like this to avoid creating a temporary
+//
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(ModNum<T, MV> l, ModNum<T, MV> r) {
+ l += r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(ModNum<T, MV> l, T r) {
+ l += r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(T l, ModNum<T, MV> r) {
+ r += l;
+ return r;
+}
+
+
+//
+// Define operator "-" like this to avoid creating a temporary
+//
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(ModNum<T, MV> l, ModNum<T, MV> r) {
+ l -= r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(ModNum<T, MV> l, T r) {
+ l -= r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(T l, ModNum<T, MV> r) {
+ r -= l;
+ return r;
+}
+
+
+//
+// Comparison operators
+// (all other cases are handled with conversons)
+//
+template<class T, T MV>
+inline bool
+operator<(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value < r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator>(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value > r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator==(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value == r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator<=(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value <= r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator>=(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value >= r.value;
+}
+
+
diff --git a/src/base/mysql.cc b/src/base/mysql.cc
new file mode 100644
index 000000000..c8d6e933a
--- /dev/null
+++ b/src/base/mysql.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+
+#include "base/mysql.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+namespace MySQL {
+
+inline const char *
+charstar(const string &string)
+{
+ return string.empty() ? NULL : string.c_str();
+}
+
+ostream &
+operator<<(ostream &stream, const Error &error)
+{
+ stream << error.string();
+ return stream;
+}
+
+/*
+ * The connection class
+ */
+Connection::Connection()
+ : valid(false)
+{
+}
+
+Connection::~Connection()
+{
+ if (valid)
+ close();
+}
+
+
+bool
+Connection::connect(const string &xhost, const string &xuser,
+ const string &xpasswd, const string &xdatabase)
+{
+ if (connected())
+ return error.set("Already Connected");
+
+ _host = xhost;
+ _user = xuser;
+ _passwd = xpasswd;
+ _database = xdatabase;
+
+ error.clear();
+
+ mysql_init(&mysql);
+ mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0); // might want to be 1
+ mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "odbc");
+ if (!mysql_real_connect(&mysql, charstar(_host), charstar(_user),
+ charstar(_passwd), charstar(_database),
+ 0, NULL, 0))
+ return error.set(mysql_error(&mysql));
+
+ valid = true;
+ return false;
+}
+
+void
+Connection::close()
+{
+ mysql_close(&mysql);
+}
+
+bool
+Connection::query(const string &sql)
+{
+ DPRINTF(SQL, "Sending SQL query to server:\n%s", sql);
+ error.clear();
+ if (mysql_real_query(&mysql, sql.c_str(), sql.size()))
+ error.set(mysql_error(&mysql));
+
+ return error;
+}
+
+
+/* namespace MySQL */ }
diff --git a/src/base/mysql.hh b/src/base/mysql.hh
new file mode 100644
index 000000000..ae28a9dfb
--- /dev/null
+++ b/src/base/mysql.hh
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_MYSQL_HH__
+#define __BASE_MYSQL_HH__
+
+#define TO_BE_INCLUDED_LATER 0
+
+#include <cassert>
+#include <iosfwd>
+#include <mysql_version.h>
+#include <mysql.h>
+#include <string>
+#include <sstream>
+
+namespace MySQL {
+
+class Error
+{
+ protected:
+ const char *error;
+
+ public:
+ Error() : error(NULL) {}
+
+ Error &clear() { error = NULL; return *this; }
+ Error &set(const char *err) { error = err; return *this; }
+
+ const char *string() const { return error; }
+
+ operator bool() const { return error != NULL; }
+ bool operator!() const { return error == NULL; }
+};
+
+std::ostream &operator<<(std::ostream &stream, const Error &error);
+
+class Result
+{
+ private:
+ MYSQL_RES *result;
+ int *refcount;
+
+ void
+ decref()
+ {
+ if (!refcount)
+ return;
+
+ *refcount -= 1;
+ if (*refcount == 0) {
+ mysql_free_result(result);
+ delete refcount;
+ }
+
+ refcount = NULL;
+ }
+
+ public:
+ Result()
+ : result(0), refcount(NULL)
+ { }
+
+ Result(MYSQL_RES *res)
+ : result(res)
+ {
+ if (result)
+ refcount = new int(1);
+ else
+ refcount = NULL;
+ }
+
+ Result(const Result &result)
+ : result(result.result), refcount(result.refcount)
+ {
+ if (result)
+ *refcount += 1;
+ }
+
+ ~Result()
+ {
+ decref();
+ }
+
+ const Result &
+ operator=(MYSQL_RES *res)
+ {
+ decref();
+ result = res;
+ if (result)
+ refcount = new int(1);
+
+ return *this;
+ }
+
+ const Result &
+ operator=(const Result &res)
+ {
+ decref();
+ result = res.result;
+ refcount = res.refcount;
+ if (result)
+ *refcount += 1;
+
+ return *this;
+ }
+
+ operator bool() const { return result != NULL; }
+ bool operator!() const { return result == NULL; }
+
+ unsigned
+ num_fields()
+ {
+ assert(result);
+ return mysql_num_fields(result);
+ }
+
+ MYSQL_ROW
+ fetch_row()
+ {
+ return mysql_fetch_row(result);
+ }
+
+ unsigned long *
+ fetch_lengths()
+ {
+ return mysql_fetch_lengths(result);
+ }
+};
+
+typedef MYSQL_ROW Row;
+
+class Connection
+{
+ protected:
+ MYSQL mysql;
+ bool valid;
+
+ protected:
+ std::string _host;
+ std::string _user;
+ std::string _passwd;
+ std::string _database;
+
+ public:
+ Connection();
+ virtual ~Connection();
+
+ bool connected() const { return valid; }
+ bool connect(const std::string &host, const std::string &user,
+ const std::string &passwd, const std::string &database);
+ void close();
+
+ public:
+ Error error;
+ operator MYSQL *() { return &mysql; }
+
+ public:
+ bool query(const std::string &sql);
+
+ bool
+ query(const std::stringstream &sql)
+ {
+ return query(sql.str());
+ }
+
+ bool
+ autocommit(bool mode)
+ {
+ return mysql_autocommit(&mysql, mode);
+ }
+
+ bool
+ commit()
+ {
+ return mysql_commit(&mysql);
+ }
+
+ bool
+ rollback()
+ {
+ return mysql_rollback(&mysql);
+ }
+
+ unsigned
+ field_count()
+ {
+ return mysql_field_count(&mysql);
+ }
+
+ unsigned
+ affected_rows()
+ {
+ return mysql_affected_rows(&mysql);
+ }
+
+ unsigned
+ insert_id()
+ {
+ return mysql_insert_id(&mysql);
+ }
+
+
+ Result
+ store_result()
+ {
+ error.clear();
+ Result result = mysql_store_result(&mysql);
+ if (!result)
+ error.set(mysql_error(&mysql));
+
+ return result;
+ }
+};
+
+#if 0
+class BindProxy
+{
+ MYSQL_BIND *bind;
+ BindProxy(MYSQL_BIND *b) : bind(b) {}
+
+ void operator=(bool &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int8_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int16_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_SHORT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int32_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int64_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONGLONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint8_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint16_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_SHORT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint32_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint64_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONGLONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(float &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_FLOAT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(double &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_DOUBLE;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(Time &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_DATE;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(const char *buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind->buffer = buffer;
+ }
+
+ void operator=(const std::string &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind->buffer = (char *)&buffer;
+ bind->length = buffer.length;
+ }
+
+ bool
+ set_null(bool null)
+ {
+ bind->is_null = null;
+ }
+};
+
+class Statement
+{
+ protected:
+ Error &error;
+ MYSQL_STMT *stmt;
+ MYSQL_BIND *bind;
+ int size;
+
+ public:
+ Statement(Connection &mysql)
+ : error(mysql.error), bind(NULL), size(0)
+ {
+ stmt = mysql_stmt_init(mysql);
+ assert(valid() && "mysql_stmt_init(), out of memory\n");
+ }
+
+ ~Statement()
+ {
+ assert(valid());
+ error.clear();
+ if (mysql_stmt_close(stmt))
+ error.set(mysql_stmt_error(stmt));
+
+ if (bind)
+ delete [] bind;
+ }
+
+ bool valid()
+ {
+ return stmt != NULL;
+ }
+
+ void prepare(const std::string &query)
+ {
+ assert(valid());
+ mysql.error.clear();
+ if (mysql_stmt_prepare(mysql, query, strlen(query)))
+ mysql.error.set(mysql_stmt_error(stmt));
+
+ int size = count();
+ bind = new MYSQL_BIND[size];
+ }
+
+ unsigned count()
+ {
+ assert(valid());
+ return mysql_stmt_param_count(stmt);
+ }
+
+ unsigned affected()
+ {
+ assert(valid());
+ return mysql_stmt_affected_rows(stmt);
+ }
+
+ void bind(MYSQL_BIND *bind)
+ {
+ mysql.error.clear();
+ if (mysql_stmt_bind_param(stmt, bind))
+ mysql.error.set(mysql_stmt_error(stmt));
+ }
+
+ BindProxy operator[](int index)
+ {
+ assert(index > 0 && index < N);
+ return &bind[N];
+ }
+
+ operator MYSQL_BIND *()
+ {
+ return bind;
+ }
+
+ void operator()()
+ {
+ assert(valid());
+ error.clear();
+ if (mysql_stmt_execute(stmt))
+ error.set(mysql_stmt_error(stmt));
+ }
+}
+#endif
+
+/* namespace MySQL */ }
+
+#endif // __BASE_MYSQL_HH__
diff --git a/src/base/output.cc b/src/base/output.cc
new file mode 100644
index 000000000..2b1733f21
--- /dev/null
+++ b/src/base/output.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+
+using namespace std;
+
+OutputDirectory simout;
+
+/**
+ *
+ */
+OutputDirectory::OutputDirectory()
+{}
+
+OutputDirectory::~OutputDirectory()
+{}
+
+void
+OutputDirectory::setDirectory(const string &d)
+{
+ if (!dir.empty())
+ panic("Output directory already set!\n");
+
+ dir = d;
+
+ if (dir != ".") {
+ if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST)
+ panic("couldn't make output dir %s: %s\n",
+ dir, strerror(errno));
+ }
+
+ // guarantee that directory ends with a '/'
+ if (dir[dir.size() - 1] != '/')
+ dir += "/";
+}
+
+const string &
+OutputDirectory::directory()
+{
+ if (dir.empty())
+ panic("Output directory not set!");
+
+ return dir;
+}
+
+string
+OutputDirectory::resolve(const string &name)
+{
+ return (name[0] != '/') ? dir + name : name;
+}
+
+ostream *
+OutputDirectory::create(const string &name)
+{
+ if (name == "cerr" || name == "stderr")
+ return &cerr;
+
+ if (name == "cout" || name == "stdout")
+ return &cout;
+
+ ofstream *file = new ofstream(resolve(name).c_str(), ios::trunc);
+ if (!file->is_open())
+ panic("Cannot open file %s", name);
+
+ return file;
+}
+
+ostream *
+OutputDirectory::find(const string &name)
+{
+ if (name == "cerr" || name == "stderr")
+ return &cerr;
+
+ if (name == "cout" || name == "stdout")
+ return &cout;
+
+ string filename = resolve(name);
+ map_t::iterator i = files.find(filename);
+ if (i != files.end())
+ return (*i).second;
+
+ ofstream *file = new ofstream(filename.c_str(), ios::trunc);
+ if (!file->is_open())
+ panic("Cannot open file %s", filename);
+
+ files[filename] = file;
+ return file;
+}
+
+bool
+OutputDirectory::isFile(const std::ostream *os)
+{
+ return os && os != &cerr && os != &cout;
+}
diff --git a/src/base/output.hh b/src/base/output.hh
new file mode 100644
index 000000000..3bbe73e3b
--- /dev/null
+++ b/src/base/output.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_OUTPUT_HH__
+#define __BASE_OUTPUT_HH__
+
+#include <iosfwd>
+#include <map>
+#include <string>
+
+class OutputDirectory
+{
+ private:
+ typedef std::map<std::string, std::ostream *> map_t;
+
+ map_t files;
+ std::string dir;
+
+ public:
+ OutputDirectory();
+ ~OutputDirectory();
+
+ void setDirectory(const std::string &dir);
+ const std::string &directory();
+
+ std::string resolve(const std::string &name);
+ std::ostream *create(const std::string &name);
+ std::ostream *find(const std::string &name);
+
+ static bool isFile(const std::ostream *os);
+ static inline bool isFile(const std::ostream &os) { return isFile(&os); }
+};
+
+extern OutputDirectory simout;
+
+#endif // __BASE_OUTPUT_HH__
diff --git a/src/base/pollevent.cc b/src/base/pollevent.cc
new file mode 100644
index 000000000..99044fc09
--- /dev/null
+++ b/src/base/pollevent.cc
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "sim/async.hh"
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "base/pollevent.hh"
+#include "sim/root.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+PollQueue pollQueue;
+
+/////////////////////////////////////////////////////
+//
+PollEvent::PollEvent(int _fd, int _events)
+ : queue(NULL), enabled(true)
+{
+ pfd.fd = _fd;
+ pfd.events = _events;
+}
+
+PollEvent::~PollEvent()
+{
+ if (queue)
+ queue->remove(this);
+}
+
+void
+PollEvent::disable()
+{
+ if (!enabled) return;
+ enabled = false;
+
+ if (queue)
+ queue->copy();
+}
+
+void
+PollEvent::enable()
+{
+ if (enabled) return;
+ enabled = true;
+
+ if (queue)
+ queue->copy();
+}
+
+void
+PollEvent::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(pfd.fd);
+ SERIALIZE_SCALAR(pfd.events);
+ SERIALIZE_SCALAR(enabled);
+}
+
+void
+PollEvent::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(pfd.fd);
+ UNSERIALIZE_SCALAR(pfd.events);
+ UNSERIALIZE_SCALAR(enabled);
+}
+
+/////////////////////////////////////////////////////
+//
+PollQueue::PollQueue()
+ : poll_fds(NULL), max_size(0), num_fds(0)
+{ }
+
+PollQueue::~PollQueue()
+{
+ removeHandler();
+ for (int i = 0; i < num_fds; i++)
+ setupAsyncIO(poll_fds[0].fd, false);
+
+ delete [] poll_fds;
+}
+
+void
+PollQueue::copy()
+{
+ eventvec_t::iterator i = events.begin();
+ eventvec_t::iterator end = events.end();
+
+ num_fds = 0;
+
+ while (i < end) {
+ if ((*i)->enabled)
+ poll_fds[num_fds++] = (*i)->pfd;
+ ++i;
+ }
+}
+
+void
+PollQueue::remove(PollEvent *event)
+{
+ eventvec_t::iterator i = events.begin();
+ eventvec_t::iterator end = events.end();
+
+ while (i < end) {
+ if (*i == event) {
+ events.erase(i);
+ copy();
+ event->queue = NULL;
+ return;
+ }
+
+ ++i;
+ }
+
+ panic("Event does not exist. Cannot remove.");
+}
+
+void
+PollQueue::schedule(PollEvent *event)
+{
+ if (event->queue)
+ panic("Event already scheduled!");
+
+ event->queue = this;
+ events.push_back(event);
+ setupAsyncIO(event->pfd.fd, true);
+
+ // if we ran out of space in the fd array, double the capacity
+ // if this is the first time that we've scheduled an event, create
+ // the array with an initial size of 16
+ if (++num_fds > max_size) {
+ if (max_size > 0) {
+ delete [] poll_fds;
+ max_size *= 2;
+ } else {
+ max_size = 16;
+ setupHandler();
+ }
+
+ poll_fds = new pollfd[max_size];
+ }
+
+ copy();
+}
+
+void
+PollQueue::service()
+{
+ int ret = poll(poll_fds, num_fds, 0);
+
+ if (ret <= 0)
+ return;
+
+ for (int i = 0; i < num_fds; i++) {
+ int revents = poll_fds[i].revents;
+ if (revents) {
+ events[i]->process(revents);
+ if (--ret <= 0)
+ break;
+ }
+ }
+}
+
+struct sigaction PollQueue::oldio;
+struct sigaction PollQueue::oldalrm;
+bool PollQueue::handler = false;
+
+void
+PollQueue::setupAsyncIO(int fd, bool set)
+{
+ int flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ panic("Could not set up async IO");
+
+ if (set)
+ flags |= FASYNC;
+ else
+ flags &= ~(FASYNC);
+
+ if (fcntl(fd, F_SETFL, flags) == -1)
+ panic("Could not set up async IO");
+
+ if (set) {
+ if (fcntl(fd, F_SETOWN, getpid()) == -1)
+ panic("Could not set up async IO");
+ }
+}
+
+void
+PollQueue::setupHandler()
+{
+ struct sigaction act;
+
+ act.sa_handler = handleIO;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+
+ if (sigaction(SIGIO, &act, &oldio) == -1)
+ panic("could not do sigaction");
+
+ act.sa_handler = handleALRM;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+
+ if (sigaction(SIGALRM, &act, &oldalrm) == -1)
+ panic("could not do sigaction");
+
+ alarm(1);
+
+ handler = true;
+}
+
+void
+PollQueue::removeHandler()
+{
+ if (sigaction(SIGIO, &oldio, NULL) == -1)
+ panic("could not remove handler");
+
+ if (sigaction(SIGIO, &oldalrm, NULL) == -1)
+ panic("could not remove handler");
+}
+
+void
+PollQueue::handleIO(int sig)
+{
+ if (sig != SIGIO)
+ panic("Wrong Handler");
+
+ async_event = true;
+ async_io = true;
+}
+
+void
+PollQueue::handleALRM(int sig)
+{
+ if (sig != SIGALRM)
+ panic("Wrong Handler");
+
+ async_event = true;
+ async_alarm = true;
+ alarm(1);
+}
+
diff --git a/src/base/pollevent.hh b/src/base/pollevent.hh
new file mode 100644
index 000000000..d39931797
--- /dev/null
+++ b/src/base/pollevent.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __POLLEVENT_H__
+#define __POLLEVENT_H__
+
+#include <vector>
+#include <poll.h>
+#include "sim/root.hh"
+
+class Checkpoint;
+class PollQueue;
+
+class PollEvent
+{
+ private:
+ friend class PollQueue;
+
+ protected:
+ pollfd pfd;
+ PollQueue *queue;
+ bool enabled;
+
+ public:
+ PollEvent(int fd, int event);
+ virtual ~PollEvent();
+
+ void disable();
+ void enable();
+ virtual void process(int revent) = 0;
+
+ bool queued() { return queue != 0; }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+class PollQueue
+{
+ private:
+ typedef std::vector<PollEvent *> eventvec_t;
+ eventvec_t events;
+
+ pollfd *poll_fds;
+ int max_size;
+ int num_fds;
+
+ public:
+ PollQueue();
+ ~PollQueue();
+
+ void copy();
+ void remove(PollEvent *event);
+ void schedule(PollEvent *event);
+ void service();
+
+ protected:
+ static bool handler;
+ static struct sigaction oldio;
+ static struct sigaction oldalrm;
+
+ public:
+ static void setupAsyncIO(int fd, bool set);
+ static void handleIO(int);
+ static void handleALRM(int);
+ static void removeHandler();
+ static void setupHandler();
+};
+
+extern PollQueue pollQueue;
+
+#endif // __POLLEVENT_H__
diff --git a/src/base/predictor.hh b/src/base/predictor.hh
new file mode 100644
index 000000000..37aa29989
--- /dev/null
+++ b/src/base/predictor.hh
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+//
+// Abstract base class for a generic predictor
+//
+//
+
+#ifndef __PREDICTOR_HH__
+#define __PREDICTOR_HH__
+
+class GenericPredictor {
+
+ public:
+ virtual void clear() = 0;
+
+ virtual unsigned predict(unsigned long _index) = 0;
+ virtual unsigned predict(unsigned long _index, unsigned &pdata) = 0;
+
+ virtual unsigned peek(unsigned long _index) = 0;
+
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value) = 0;
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value, unsigned _pdata) = 0;
+
+ virtual unsigned value(unsigned long _index) = 0;
+
+ virtual void regStats() = 0;
+ virtual void regFormulas() = 0;
+
+ virtual ~GenericPredictor() {};
+};
+
+#endif // __PREDICTOR_HH__
diff --git a/src/base/random.cc b/src/base/random.cc
new file mode 100644
index 000000000..4aac14101
--- /dev/null
+++ b/src/base/random.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstdlib>
+#include <cmath>
+
+#include "sim/param.hh"
+#include "base/random.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+class RandomContext : public ParamContext
+{
+ public:
+ RandomContext(const string &_iniSection)
+ : ::ParamContext(_iniSection) {}
+ ~RandomContext() {}
+
+ void checkParams();
+};
+
+RandomContext paramContext("random");
+
+Param<unsigned>
+seed(&paramContext, "seed", "seed to random number generator", 1);
+
+void
+RandomContext::checkParams()
+{
+ ::srand48(seed);
+}
+
+long
+getLong()
+{
+ return mrand48();
+}
+
+int64_t
+getUniform(int64_t min, int64_t max)
+{
+ double r;
+ r = drand48() * (max-min) + min;
+ return (int64_t)round(r);
+}
+
+uint64_t
+getUniformPos(uint64_t min, uint64_t max)
+{
+ double r;
+ r = drand48() * (max-min) + min;
+ return (uint64_t)round(r);
+}
+
+
+// idea for generating a double from erand48
+double
+getDouble()
+{
+ union {
+ uint32_t _long[2];
+ uint16_t _short[4];
+ };
+
+ _long[0] = mrand48();
+ _long[1] = mrand48();
+
+ return ldexp((double) _short[0], -48) +
+ ldexp((double) _short[1], -32) +
+ ldexp((double) _short[2], -16);
+}
diff --git a/src/base/random.hh b/src/base/random.hh
new file mode 100644
index 000000000..def7a4bce
--- /dev/null
+++ b/src/base/random.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_RANDOM_HH__
+#define __BASE_RANDOM_HH__
+
+#include "sim/host.hh"
+
+long getLong();
+double getDouble();
+uint64_t getUniformPos(uint64_t min, uint64_t max);
+int64_t getUniform(int64_t min, int64_t max);
+
+template <typename T>
+struct Random;
+
+template<> struct Random<int8_t>
+{
+ static int8_t get()
+ { return getLong() & (int8_t)-1; }
+
+ static int8_t uniform(int8_t min, int8_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint8_t>
+{
+ static uint8_t get()
+ { return getLong() & (uint8_t)-1; }
+
+ static uint8_t uniform(uint8_t min, uint8_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int16_t>
+{
+ static int16_t get()
+ { return getLong() & (int16_t)-1; }
+
+ static int16_t uniform(int16_t min, int16_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint16_t>
+{
+ static uint16_t get()
+ { return getLong() & (uint16_t)-1; }
+
+ static uint16_t uniform(uint16_t min, uint16_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int32_t>
+{
+ static int32_t get()
+ { return (int32_t)getLong(); }
+
+ static int32_t uniform(int32_t min, int32_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint32_t>
+{
+ static uint32_t get()
+ { return (uint32_t)getLong(); }
+
+ static uint32_t uniform(uint32_t min, uint32_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int64_t>
+{
+ static int64_t get()
+ { return (int64_t)getLong() << 32 || (uint64_t)getLong(); }
+
+ static int64_t uniform(int64_t min, int64_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint64_t>
+{
+ static uint64_t get()
+ { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); }
+
+ static uint64_t uniform(uint64_t min, uint64_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<float>
+{
+ static float get()
+ { return getDouble(); }
+};
+
+template<> struct Random<double>
+{
+ static double get()
+ { return getDouble(); }
+};
+
+#endif // __BASE_RANDOM_HH__
diff --git a/src/base/range.cc b/src/base/range.cc
new file mode 100644
index 000000000..a4e50fc4f
--- /dev/null
+++ b/src/base/range.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/intmath.hh"
+#include "base/range.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+template <class T>
+bool
+__x_parse_range(const std::string &str, T &first, T &last)
+{
+ std::vector<std::string> values;
+ tokenize(values, str, ':');
+
+ T thefirst, thelast;
+
+ if (values.size() != 2)
+ return false;
+
+ std::string s = values[0];
+ std::string e = values[1];
+
+ if (!to_number(s, thefirst))
+ return false;
+
+ bool increment = (e[0] == '+');
+ if (increment)
+ e = e.substr(1);
+
+ if (!to_number(e, thelast))
+ return false;
+
+ if (increment)
+ thelast += thefirst - 1;
+
+ first = thefirst;
+ last = thelast;
+
+ return true;
+}
+
+#define RANGE_PARSE(type) \
+template<> bool \
+__parse_range(const std::string &s, type &first, type &last) \
+{ return __x_parse_range(s, first, last); }
+
+RANGE_PARSE(unsigned long long);
+RANGE_PARSE(signed long long);
+RANGE_PARSE(unsigned long);
+RANGE_PARSE(signed long);
+RANGE_PARSE(unsigned int);
+RANGE_PARSE(signed int);
+RANGE_PARSE(unsigned short);
+RANGE_PARSE(signed short);
+RANGE_PARSE(unsigned char);
+RANGE_PARSE(signed char);
diff --git a/src/base/range.hh b/src/base/range.hh
new file mode 100644
index 000000000..4e3e0fd6e
--- /dev/null
+++ b/src/base/range.hh
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_RANGE_HH__
+#define __BASE_RANGE_HH__
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+/**
+ * @param s range string
+ * EndExclusive Ranges are in the following format:
+ * @verbatim
+ * <range> := {<start_val>}:{<end>}
+ * <start> := <end_val> | +<delta>
+ * @endverbatim
+ */
+template <class T>
+bool __parse_range(const std::string &s, T &start, T &end);
+
+template <class T>
+struct Range
+{
+ T start;
+ T end;
+
+ Range() { invalidate(); }
+
+ template <class U>
+ Range(const std::pair<U, U> &r)
+ : start(r.first), end(r.second)
+ {}
+
+ template <class U>
+ Range(const Range<U> &r)
+ : start(r.start), end(r.end)
+ {}
+
+ Range(const std::string &s)
+ {
+ if (!__parse_range(s, start, end))
+ invalidate();
+ }
+
+ template <class U>
+ const Range<T> &operator=(const Range<U> &r)
+ {
+ start = r.start;
+ end = r.end;
+ return *this;
+ }
+
+ template <class U>
+ const Range<T> &operator=(const std::pair<U, U> &r)
+ {
+ start = r.first;
+ end = r.second;
+ return *this;
+ }
+
+ const Range &operator=(const std::string &s)
+ {
+ if (!__parse_range(s, start, end))
+ invalidate();
+ return *this;
+ }
+
+ void invalidate() { start = 1; end = 0; }
+ T size() const { return end - start + 1; }
+ bool valid() const { return start < end; }
+};
+
+template <class T>
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
+{
+ o << '[' << r.start << "," << r.end << ']';
+ return o;
+}
+
+template <class T>
+inline Range<T>
+RangeEx(T start, T end)
+{ return std::make_pair(start, end - 1); }
+
+template <class T>
+inline Range<T>
+RangeIn(T start, T end)
+{ return std::make_pair(start, end); }
+
+template <class T, class U>
+inline Range<T>
+RangeSize(T start, U size)
+{ return std::make_pair(start, start + size - 1); }
+
+////////////////////////////////////////////////////////////////////////
+//
+// Range to Range Comparisons
+//
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are identical.
+ */
+template <class T, class U>
+inline bool
+operator==(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start == range2.start && range1.end == range2.end;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are not identical.
+ */
+template <class T, class U>
+inline bool
+operator!=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start != range2.start || range1.end != range2.end;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2 and does not overlap range1.
+ */
+template <class T, class U>
+inline bool
+operator<(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start < range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2. range1 may overlap range2,
+ * but not extend beyond the end of range2.
+ */
+template <class T, class U>
+inline bool
+operator<=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start <= range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2 and does not overlap range2.
+ */
+template <class T, class U>
+inline bool
+operator>(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start > range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2. range1 may overlap range2,
+ * but not extend beyond the beginning of range2.
+ */
+template <class T, class U>
+inline bool
+operator>=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start >= range2.start;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Position to Range Comparisons
+//
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is within the range.
+ */
+template <class T, class U>
+inline bool
+operator==(const T &pos, const Range<U> &range)
+{
+ return pos >= range.start && pos <= range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is not within the range.
+ */
+template <class T, class U>
+inline bool
+operator!=(const T &pos, const Range<U> &range)
+{
+ return pos < range.start || pos > range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below the range.
+ */
+template <class T, class U>
+inline bool
+operator<(const T &pos, const Range<U> &range)
+{
+ return pos < range.start;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below or in the range.
+ */
+template <class T, class U>
+inline bool
+operator<=(const T &pos, const Range<U> &range)
+{
+ return pos <= range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above the range.
+ */
+template <class T, class U>
+inline bool
+operator>(const T &pos, const Range<U> &range)
+{
+ return pos > range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above or in the range.
+ */
+template <class T, class U>
+inline bool
+operator>=(const T &pos, const Range<U> &range)
+{
+ return pos >= range.start;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Range to Position Comparisons (for symmetry)
+//
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is within the range.
+ */
+template <class T, class U>
+inline bool
+operator==(const Range<T> &range, const U &pos)
+{
+ return pos >= range.start && pos <= range.end;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is not within the range.
+ */
+template <class T, class U>
+inline bool
+operator!=(const Range<T> &range, const U &pos)
+{
+ return pos < range.start || pos > range.end;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above the range.
+ */
+template <class T, class U>
+inline bool
+operator<(const Range<T> &range, const U &pos)
+{
+ return range.end < pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above or in the range.
+ */
+template <class T, class U>
+inline bool
+operator<=(const Range<T> &range, const U &pos)
+{
+ return range.start <= pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range > pos' indicates that position pos is below the range.
+ */
+template <class T, class U>
+inline bool
+operator>(const Range<T> &range, const U &pos)
+{
+ return range.start > pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range >= pos' indicates that position pos is below or in the range.
+ */
+template <class T, class U>
+inline bool
+operator>=(const Range<T> &range, const U &pos)
+{
+ return range.end >= pos;
+}
+
+#endif // __BASE_RANGE_HH__
diff --git a/src/base/refcnt.hh b/src/base/refcnt.hh
new file mode 100644
index 000000000..de589f7c5
--- /dev/null
+++ b/src/base/refcnt.hh
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REFCNT_HH__
+#define __REFCNT_HH__
+
+#include <stddef.h> //For the NULL macro definition
+
+class RefCounted
+{
+ private:
+ int count;
+
+ private:
+ RefCounted(const RefCounted &);
+
+ public:
+ RefCounted() : count(0) {}
+ virtual ~RefCounted() {}
+
+ void incref() { ++count; }
+ void decref() { if (--count <= 0) delete this; }
+};
+
+template <class T>
+class RefCountingPtr
+{
+ protected:
+ T *data;
+
+ void copy(T *d)
+ {
+ data = d;
+ if (data)
+ data->incref();
+ }
+ void del()
+ {
+ if (data)
+ data->decref();
+ }
+ void set(T *d)
+ {
+ if (data == d)
+ return;
+
+ del();
+ copy(d);
+ }
+
+
+ public:
+ RefCountingPtr() : data(NULL) {}
+ RefCountingPtr(T *data) { copy(data); }
+ RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
+ ~RefCountingPtr() { del(); }
+
+ T *operator->() { return data; }
+ T &operator*() { return *data; }
+ T *get() { return data; }
+
+ const T *operator->() const { return data; }
+ const T &operator*() const { return *data; }
+ const T *get() const { return data; }
+
+ RefCountingPtr &operator=(T *p) { set(p); return *this; }
+ RefCountingPtr &operator=(const RefCountingPtr &r)
+ { return operator=(r.data); }
+
+ bool operator!() const { return data == 0; }
+ operator bool() const { return data != 0; }
+};
+
+template<class T>
+bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
+{ return l.get() == r.get(); }
+
+template<class T>
+bool operator==(const RefCountingPtr<T> &l, const T *r)
+{ return l.get() == r; }
+
+template<class T>
+bool operator==(const T &l, const RefCountingPtr<T> &r)
+{ return l == r.get(); }
+
+template<class T>
+bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
+{ return l.get() != r.get(); }
+
+template<class T>
+bool operator!=(const RefCountingPtr<T> &l, const T *r)
+{ return l.get() != r; }
+
+template<class T>
+bool operator!=(const T &l, const RefCountingPtr<T> &r)
+{ return l != r.get(); }
+
+#endif // __REFCNT_HH__
diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
new file mode 100644
index 000000000..41d0c1471
--- /dev/null
+++ b/src/base/remote_gdb.cc
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratories.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
+ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
+ *
+ * Taken from NetBSD
+ *
+ * "Stub" to allow remote cpu to debug over a serial line using gdb.
+ */
+
+#include <sys/signal.h>
+
+#include <string>
+#include <unistd.h>
+
+#include "arch/vtophys.hh"
+#include "base/intmath.hh"
+#include "base/kgdb.h"
+#include "base/remote_gdb.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/static_inst.hh"
+#include "mem/physical.hh"
+#include "mem/port.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+#ifndef NDEBUG
+vector<RemoteGDB *> debuggers;
+int current_debugger = -1;
+
+void
+debugger()
+{
+ if (current_debugger >= 0 && current_debugger < debuggers.size()) {
+ RemoteGDB *gdb = debuggers[current_debugger];
+ if (!gdb->isattached())
+ gdb->listener->accept();
+ if (gdb->isattached())
+ gdb->trap(ALPHA_KENTRY_IF);
+ }
+}
+#endif
+
+///////////////////////////////////////////////////////////
+//
+//
+//
+
+GDBListener::Event::Event(GDBListener *l, int fd, int e)
+ : PollEvent(fd, e), listener(l)
+{}
+
+void
+GDBListener::Event::process(int revent)
+{
+ listener->accept();
+}
+
+GDBListener::GDBListener(RemoteGDB *g, int p)
+ : event(NULL), gdb(g), port(p)
+{
+ assert(!gdb->listener);
+ gdb->listener = this;
+}
+
+GDBListener::~GDBListener()
+{
+ if (event)
+ delete event;
+}
+
+string
+GDBListener::name()
+{
+ return gdb->name() + ".listener";
+}
+
+void
+GDBListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(GDBMisc, "Can't bind port %d\n", port);
+ port++;
+ }
+
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+
+#ifndef NDEBUG
+ gdb->number = debuggers.size();
+ debuggers.push_back(gdb);
+#endif
+
+#ifndef NDEBUG
+ ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
+ curTick, name(), gdb->number, port);
+#else
+ ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
+ curTick, name(), port);
+#endif
+}
+
+void
+GDBListener::accept()
+{
+ if (!listener.islistening())
+ panic("GDBListener::accept(): cannot accept if we're not listening!");
+
+ int sfd = listener.accept(true);
+
+ if (sfd != -1) {
+ if (gdb->isattached())
+ close(sfd);
+ else
+ gdb->attach(sfd);
+ }
+}
+
+///////////////////////////////////////////////////////////
+//
+//
+//
+int digit2i(char);
+char i2digit(int);
+void mem2hex(void *, const void *, int);
+const char *hex2mem(void *, const char *, int);
+Addr hex2i(const char **);
+
+RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
+ : PollEvent(fd, e), gdb(g)
+{}
+
+void
+RemoteGDB::Event::process(int revent)
+{
+ if (revent & POLLIN)
+ gdb->trap(ALPHA_KENTRY_IF);
+ else if (revent & POLLNVAL)
+ gdb->detach();
+}
+
+RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+ : event(NULL), listener(NULL), number(-1), fd(-1),
+ active(false), attached(false),
+ system(_system), pmem(_system->physmem), context(c)
+{
+ memset(gdbregs, 0, sizeof(gdbregs));
+}
+
+RemoteGDB::~RemoteGDB()
+{
+ if (event)
+ delete event;
+}
+
+string
+RemoteGDB::name()
+{
+ return system->name() + ".remote_gdb";
+}
+
+bool
+RemoteGDB::isattached()
+{ return attached; }
+
+void
+RemoteGDB::attach(int f)
+{
+ fd = f;
+
+ event = new Event(this, fd, POLLIN);
+ pollQueue.schedule(event);
+
+ attached = true;
+ DPRINTFN("remote gdb attached\n");
+}
+
+void
+RemoteGDB::detach()
+{
+ attached = false;
+ close(fd);
+ fd = -1;
+
+ pollQueue.remove(event);
+ DPRINTFN("remote gdb detached\n");
+}
+
+const char *
+gdb_command(char cmd)
+{
+ switch (cmd) {
+ case KGDB_SIGNAL: return "KGDB_SIGNAL";
+ case KGDB_SET_BAUD: return "KGDB_SET_BAUD";
+ case KGDB_SET_BREAK: return "KGDB_SET_BREAK";
+ case KGDB_CONT: return "KGDB_CONT";
+ case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT";
+ case KGDB_DEBUG: return "KGDB_DEBUG";
+ case KGDB_DETACH: return "KGDB_DETACH";
+ case KGDB_REG_R: return "KGDB_REG_R";
+ case KGDB_REG_W: return "KGDB_REG_W";
+ case KGDB_SET_THREAD: return "KGDB_SET_THREAD";
+ case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP";
+ case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP";
+ case KGDB_KILL: return "KGDB_KILL";
+ case KGDB_MEM_W: return "KGDB_MEM_W";
+ case KGDB_MEM_R: return "KGDB_MEM_R";
+ case KGDB_SET_REG: return "KGDB_SET_REG";
+ case KGDB_READ_REG: return "KGDB_READ_REG";
+ case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR";
+ case KGDB_SET_VAR: return "KGDB_SET_VAR";
+ case KGDB_RESET: return "KGDB_RESET";
+ case KGDB_STEP: return "KGDB_STEP";
+ case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP";
+ case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE";
+ case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT";
+ case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD";
+ case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT";
+ case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT";
+ case KGDB_START: return "KGDB_START";
+ case KGDB_END: return "KGDB_END";
+ case KGDB_GOODP: return "KGDB_GOODP";
+ case KGDB_BADP: return "KGDB_BADP";
+ default: return "KGDB_UNKNOWN";
+ }
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::acc
+//
+// Determine if the mapping at va..(va+len) is valid.
+//
+bool
+RemoteGDB::acc(Addr va, size_t len)
+{
+ Addr last_va;
+
+ va = TheISA::TruncPage(va);
+ last_va = TheISA::RoundPage(va + len);
+
+ do {
+ if (TheISA::IsK0Seg(va)) {
+ if (va < (TheISA::K0SegBase + pmem->size())) {
+ DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
+ "%#x < K0SEG + size\n", va);
+ return true;
+ } else {
+ DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
+ va);
+ return false;
+ }
+ }
+
+ /**
+ * This code says that all accesses to palcode (instruction and data)
+ * are valid since there isn't a va->pa mapping because palcode is
+ * accessed physically. At some point this should probably be cleaned up
+ * but there is no easy way to do it.
+ */
+
+ if (AlphaISA::PcPAL(va) || va < 0x10000)
+ return true;
+
+ Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20);
+ TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
+ if (!pte.valid()) {
+ DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
+ return false;
+ }
+ va += TheISA::PageBytes;
+ } while (va < last_va);
+
+ DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
+ return true;
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::signal
+//
+// Translate a trap number into a Unix-compatible signal number.
+// (GDB only understands Unix signal numbers.)
+//
+int
+RemoteGDB::signal(int type)
+{
+ switch (type) {
+ case ALPHA_KENTRY_INT:
+ return (SIGTRAP);
+
+ case ALPHA_KENTRY_UNA:
+ return (SIGBUS);
+
+ case ALPHA_KENTRY_ARITH:
+ return (SIGFPE);
+
+ case ALPHA_KENTRY_IF:
+ return (SIGILL);
+
+ case ALPHA_KENTRY_MM:
+ return (SIGSEGV);
+
+ default:
+ panic("unknown signal type");
+ return 0;
+ }
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::getregs
+//
+// Translate the kernel debugger register format into
+// the GDB register format.
+void
+RemoteGDB::getregs()
+{
+ memset(gdbregs, 0, sizeof(gdbregs));
+
+ gdbregs[KGDB_REG_PC] = context->readPC();
+
+ // @todo: Currently this is very Alpha specific.
+ if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
+ }
+ } else {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ gdbregs[i] = context->readIntReg(i);
+ }
+ }
+
+#ifdef KGDB_FP_REGS
+ for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
+ }
+#endif
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::setregs
+//
+// Translate the GDB register format into the kernel
+// debugger register format.
+//
+void
+RemoteGDB::setregs()
+{
+ // @todo: Currently this is very Alpha specific.
+ if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]);
+ }
+ } else {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ context->setIntReg(i, gdbregs[i]);
+ }
+ }
+
+#ifdef KGDB_FP_REGS
+ for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]);
+ }
+#endif
+ context->setPC(gdbregs[KGDB_REG_PC]);
+}
+
+void
+RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
+{
+ DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr);
+
+ bkpt.address = addr;
+ insertHardBreak(addr, 4);
+}
+
+void
+RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
+{
+ DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n",
+ bkpt.address);
+
+
+ removeHardBreak(bkpt.address, 4);
+ bkpt.address = 0;
+}
+
+void
+RemoteGDB::clearSingleStep()
+{
+ DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
+ takenBkpt.address, notTakenBkpt.address);
+
+ if (takenBkpt.address != 0)
+ clearTempBreakpoint(takenBkpt);
+
+ if (notTakenBkpt.address != 0)
+ clearTempBreakpoint(notTakenBkpt);
+}
+
+void
+RemoteGDB::setSingleStep()
+{
+ Addr pc = context->readPC();
+ Addr npc, bpc;
+ bool set_bt = false;
+
+ npc = pc + sizeof(MachInst);
+
+ // User was stopped at pc, e.g. the instruction at pc was not
+ // executed.
+ MachInst inst = read<MachInst>(pc);
+ StaticInstPtr si(inst);
+ if (si->hasBranchTarget(pc, context, bpc)) {
+ // Don't bother setting a breakpoint on the taken branch if it
+ // is the same as the next pc
+ if (bpc != npc)
+ set_bt = true;
+ }
+
+ DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
+ takenBkpt.address, notTakenBkpt.address);
+
+ setTempBreakpoint(notTakenBkpt, npc);
+
+ if (set_bt)
+ setTempBreakpoint(takenBkpt, bpc);
+}
+
+/////////////////////////
+//
+//
+
+uint8_t
+RemoteGDB::getbyte()
+{
+ uint8_t b;
+ ::read(fd, &b, 1);
+ return b;
+}
+
+void
+RemoteGDB::putbyte(uint8_t b)
+{
+ ::write(fd, &b, 1);
+}
+
+// Send a packet to gdb
+void
+RemoteGDB::send(const char *bp)
+{
+ const char *p;
+ uint8_t csum, c;
+
+ DPRINTF(GDBSend, "send: %s\n", bp);
+
+ do {
+ p = bp;
+ putbyte(KGDB_START);
+ for (csum = 0; (c = *p); p++) {
+ putbyte(c);
+ csum += c;
+ }
+ putbyte(KGDB_END);
+ putbyte(i2digit(csum >> 4));
+ putbyte(i2digit(csum));
+ } while ((c = getbyte() & 0x7f) == KGDB_BADP);
+}
+
+// Receive a packet from gdb
+int
+RemoteGDB::recv(char *bp, int maxlen)
+{
+ char *p;
+ int c, csum;
+ int len;
+
+ do {
+ p = bp;
+ csum = len = 0;
+ while ((c = getbyte()) != KGDB_START)
+ ;
+
+ while ((c = getbyte()) != KGDB_END && len < maxlen) {
+ c &= 0x7f;
+ csum += c;
+ *p++ = c;
+ len++;
+ }
+ csum &= 0xff;
+ *p = '\0';
+
+ if (len >= maxlen) {
+ putbyte(KGDB_BADP);
+ continue;
+ }
+
+ csum -= digit2i(getbyte()) * 16;
+ csum -= digit2i(getbyte());
+
+ if (csum == 0) {
+ putbyte(KGDB_GOODP);
+ // Sequence present?
+ if (bp[2] == ':') {
+ putbyte(bp[0]);
+ putbyte(bp[1]);
+ len -= 3;
+ bcopy(bp + 3, bp, len);
+ }
+ break;
+ }
+ putbyte(KGDB_BADP);
+ } while (1);
+
+ DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp);
+
+ return (len);
+}
+
+// Read bytes from kernel address space for debugger.
+bool
+RemoteGDB::read(Addr vaddr, size_t size, char *data)
+{
+ static Addr lastaddr = 0;
+ static size_t lastsize = 0;
+
+ if (vaddr < 10) {
+ DPRINTF(GDBRead, "read: reading memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size);
+
+ context->getVirtPort(context)->readBlob(vaddr, (uint8_t*)data, size);
+
+#if TRACING_ON
+ if (DTRACE(GDBRead)) {
+ if (DTRACE(GDBExtra)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ DPRINTFNR(": %s\n", buf);
+ } else
+ DPRINTFNR("\n");
+ }
+#endif
+
+ return true;
+}
+
+// Write bytes to kernel address space for debugger.
+bool
+RemoteGDB::write(Addr vaddr, size_t size, const char *data)
+{
+ static Addr lastaddr = 0;
+ static size_t lastsize = 0;
+
+ if (vaddr < 10) {
+ DPRINTF(GDBWrite, "write: writing memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ if (DTRACE(GDBWrite)) {
+ DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
+ if (DTRACE(GDBExtra)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ DPRINTFNR(": %s\n", buf);
+ } else
+ DPRINTFNR("\n");
+ }
+
+ context->getVirtPort(context)->writeBlob(vaddr, (uint8_t*)data, size);
+
+#ifdef IMB
+ alpha_pal_imb();
+#endif
+
+ return true;
+}
+
+
+PCEventQueue *RemoteGDB::getPcEventQueue()
+{
+ return &system->pcEventQueue;
+}
+
+
+RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
+ : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
+ gdb(_gdb), refcount(0)
+{
+ DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
+}
+
+void
+RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+{
+ DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
+
+ if (xc == gdb->context)
+ gdb->trap(ALPHA_KENTRY_INT);
+}
+
+bool
+RemoteGDB::insertSoftBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ return insertHardBreak(addr, len);
+}
+
+bool
+RemoteGDB::removeSoftBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ return removeHardBreak(addr, len);
+}
+
+bool
+RemoteGDB::insertHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
+
+ HardBreakpoint *&bkpt = hardBreakMap[addr];
+ if (bkpt == 0)
+ bkpt = new HardBreakpoint(this, addr);
+
+ bkpt->refcount++;
+
+ return true;
+}
+
+bool
+RemoteGDB::removeHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
+
+ break_iter_t i = hardBreakMap.find(addr);
+ if (i == hardBreakMap.end())
+ return false;
+
+ HardBreakpoint *hbp = (*i).second;
+ if (--hbp->refcount == 0) {
+ delete hbp;
+ hardBreakMap.erase(i);
+ }
+
+ return true;
+}
+
+const char *
+break_type(char c)
+{
+ switch(c) {
+ case '0': return "software breakpoint";
+ case '1': return "hardware breakpoint";
+ case '2': return "write watchpoint";
+ case '3': return "read watchpoint";
+ case '4': return "access watchpoint";
+ default: return "unknown breakpoint/watchpoint";
+ }
+}
+
+// This function does all command processing for interfacing to a
+// remote gdb. Note that the error codes are ignored by gdb at
+// present, but might eventually become meaningful. (XXX) It might
+// makes sense to use POSIX errno values, because that is what the
+// gdb/remote.c functions want to return.
+bool
+RemoteGDB::trap(int type)
+{
+ uint64_t val;
+ size_t datalen, len;
+ char data[KGDB_BUFLEN + 1];
+ char buffer[sizeof(gdbregs) * 2 + 256];
+ char temp[KGDB_BUFLEN];
+ const char *p;
+ char command, subcmd;
+ string var;
+ bool ret;
+
+ if (!attached)
+ return false;
+
+ DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n",
+ context->readPC(), context->readNextPC());
+
+ clearSingleStep();
+
+ /*
+ * The first entry to this function is normally through
+ * a breakpoint trap in kgdb_connect(), in which case we
+ * must advance past the breakpoint because gdb will not.
+ *
+ * On the first entry here, we expect that gdb is not yet
+ * listening to us, so just enter the interaction loop.
+ * After the debugger is "active" (connected) it will be
+ * waiting for a "signaled" message from us.
+ */
+ if (!active)
+ active = true;
+ else
+ // Tell remote host that an exception has occurred.
+ snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
+ send(buffer);
+
+ // Stick frame regs into our reg cache.
+ getregs();
+
+ for (;;) {
+ datalen = recv(data, sizeof(data));
+ data[sizeof(data) - 1] = 0; // Sentinel
+ command = data[0];
+ subcmd = 0;
+ p = data + 1;
+ switch (command) {
+
+ case KGDB_SIGNAL:
+ // if this command came from a running gdb, answer it --
+ // the other guy has no way of knowing if we're in or out
+ // of this loop when he issues a "remote-signal".
+ snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
+ send(buffer);
+ continue;
+
+ case KGDB_REG_R:
+ if (2 * sizeof(gdbregs) > sizeof(buffer))
+ panic("buffer too small");
+
+ mem2hex(buffer, gdbregs, sizeof(gdbregs));
+ send(buffer);
+ continue;
+
+ case KGDB_REG_W:
+ p = hex2mem(gdbregs, p, sizeof(gdbregs));
+ if (p == NULL || *p != '\0')
+ send("E01");
+ else {
+ setregs();
+ send("OK");
+ }
+ continue;
+
+#if 0
+ case KGDB_SET_REG:
+ val = hex2i(&p);
+ if (*p++ != '=') {
+ send("E01");
+ continue;
+ }
+ if (val < 0 && val >= KGDB_NUMREGS) {
+ send("E01");
+ continue;
+ }
+
+ gdbregs[val] = hex2i(&p);
+ setregs();
+ send("OK");
+
+ continue;
+#endif
+
+ case KGDB_MEM_R:
+ val = hex2i(&p);
+ if (*p++ != ',') {
+ send("E02");
+ continue;
+ }
+ len = hex2i(&p);
+ if (*p != '\0') {
+ send("E03");
+ continue;
+ }
+ if (len > sizeof(buffer)) {
+ send("E04");
+ continue;
+ }
+ if (!acc(val, len)) {
+ send("E05");
+ continue;
+ }
+
+ if (read(val, (size_t)len, (char *)buffer)) {
+ mem2hex(temp, buffer, len);
+ send(temp);
+ } else {
+ send("E05");
+ }
+ continue;
+
+ case KGDB_MEM_W:
+ val = hex2i(&p);
+ if (*p++ != ',') {
+ send("E06");
+ continue;
+ }
+ len = hex2i(&p);
+ if (*p++ != ':') {
+ send("E07");
+ continue;
+ }
+ if (len > datalen - (p - data)) {
+ send("E08");
+ continue;
+ }
+ p = hex2mem(buffer, p, sizeof(buffer));
+ if (p == NULL) {
+ send("E09");
+ continue;
+ }
+ if (!acc(val, len)) {
+ send("E0A");
+ continue;
+ }
+ if (write(val, (size_t)len, (char *)buffer))
+ send("OK");
+ else
+ send("E0B");
+ continue;
+
+ case KGDB_SET_THREAD:
+ subcmd = *p++;
+ val = hex2i(&p);
+ if (val == 0)
+ send("OK");
+ else
+ send("E01");
+ continue;
+
+ case KGDB_DETACH:
+ case KGDB_KILL:
+ active = false;
+ clearSingleStep();
+ detach();
+ goto out;
+
+ case KGDB_ASYNC_CONT:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_CONT:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_ASYNC_STEP:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_STEP:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_CLR_HW_BKPT:
+ subcmd = *p++;
+ if (*p++ != ',') send("E0D");
+ val = hex2i(&p);
+ if (*p++ != ',') send("E0D");
+ len = hex2i(&p);
+
+ DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
+ break_type(subcmd), val, len);
+
+ ret = false;
+
+ switch (subcmd) {
+ case '0': // software breakpoint
+ ret = removeSoftBreak(val, len);
+ break;
+
+ case '1': // hardware breakpoint
+ ret = removeHardBreak(val, len);
+ break;
+
+ case '2': // write watchpoint
+ case '3': // read watchpoint
+ case '4': // access watchpoint
+ default: // unknown
+ send("");
+ break;
+ }
+
+ send(ret ? "OK" : "E0C");
+ continue;
+
+ case KGDB_SET_HW_BKPT:
+ subcmd = *p++;
+ if (*p++ != ',') send("E0D");
+ val = hex2i(&p);
+ if (*p++ != ',') send("E0D");
+ len = hex2i(&p);
+
+ DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
+ break_type(subcmd), val, len);
+
+ ret = false;
+
+ switch (subcmd) {
+ case '0': // software breakpoint
+ ret = insertSoftBreak(val, len);
+ break;
+
+ case '1': // hardware breakpoint
+ ret = insertHardBreak(val, len);
+ break;
+
+ case '2': // write watchpoint
+ case '3': // read watchpoint
+ case '4': // access watchpoint
+ default: // unknown
+ send("");
+ break;
+ }
+
+ send(ret ? "OK" : "E0C");
+ continue;
+
+ case KGDB_QUERY_VAR:
+ var = string(p, datalen - 1);
+ if (var == "C")
+ send("QC0");
+ else
+ send("");
+ continue;
+
+ case KGDB_SET_BAUD:
+ case KGDB_SET_BREAK:
+ case KGDB_DEBUG:
+ case KGDB_CYCLE_STEP:
+ case KGDB_SIG_CYCLE_STEP:
+ case KGDB_READ_REG:
+ case KGDB_SET_VAR:
+ case KGDB_RESET:
+ case KGDB_THREAD_ALIVE:
+ case KGDB_TARGET_EXIT:
+ case KGDB_BINARY_DLOAD:
+ // Unsupported command
+ DPRINTF(GDBMisc, "Unsupported command: %s\n",
+ gdb_command(command));
+ DDUMP(GDBMisc, (uint8_t *)data, datalen);
+ send("");
+ continue;
+
+ default:
+ // Unknown command.
+ DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
+ command, command);
+ send("");
+ continue;
+
+
+ }
+ }
+
+ out:
+ return true;
+}
+
+// Convert a hex digit into an integer.
+// This returns -1 if the argument passed is no valid hex digit.
+int
+digit2i(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else if (c >= 'A' && c <= 'F')
+
+ return (c - 'A' + 10);
+ else
+ return (-1);
+}
+
+// Convert the low 4 bits of an integer into an hex digit.
+char
+i2digit(int n)
+{
+ return ("0123456789abcdef"[n & 0x0f]);
+}
+
+// Convert a byte array into an hex string.
+void
+mem2hex(void *vdst, const void *vsrc, int len)
+{
+ char *dst = (char *)vdst;
+ const char *src = (const char *)vsrc;
+
+ while (len--) {
+ *dst++ = i2digit(*src >> 4);
+ *dst++ = i2digit(*src++);
+ }
+ *dst = '\0';
+}
+
+// Convert an hex string into a byte array.
+// This returns a pointer to the character following the last valid
+// hex digit. If the string ends in the middle of a byte, NULL is
+// returned.
+const char *
+hex2mem(void *vdst, const char *src, int maxlen)
+{
+ char *dst = (char *)vdst;
+ int msb, lsb;
+
+ while (*src && maxlen--) {
+ msb = digit2i(*src++);
+ if (msb < 0)
+ return (src - 1);
+ lsb = digit2i(*src++);
+ if (lsb < 0)
+ return (NULL);
+ *dst++ = (msb << 4) | lsb;
+ }
+ return (src);
+}
+
+// Convert an hex string into an integer.
+// This returns a pointer to the character following the last valid
+// hex digit.
+Addr
+hex2i(const char **srcp)
+{
+ const char *src = *srcp;
+ Addr r = 0;
+ int nibble;
+
+ while ((nibble = digit2i(*src)) >= 0) {
+ r *= 16;
+ r += nibble;
+ src++;
+ }
+ *srcp = src;
+ return (r);
+}
+
diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh
new file mode 100644
index 000000000..b7abf5116
--- /dev/null
+++ b/src/base/remote_gdb.hh
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REMOTE_GDB_HH__
+#define __REMOTE_GDB_HH__
+
+#include <map>
+
+#include "base/kgdb.h"
+#include "cpu/pc_event.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+
+class System;
+class ExecContext;
+class PhysicalMemory;
+
+class GDBListener;
+class RemoteGDB
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ private:
+ friend void debugger();
+ friend class GDBListener;
+
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ RemoteGDB *gdb;
+
+ public:
+ Event(RemoteGDB *g, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+ GDBListener *listener;
+ int number;
+
+ protected:
+ int fd;
+ uint64_t gdbregs[KGDB_NUMREGS];
+
+ protected:
+#ifdef notyet
+ label_t recover;
+#endif
+ bool active;
+ bool attached;
+
+ System *system;
+ PhysicalMemory *pmem;
+ ExecContext *context;
+
+ protected:
+ uint8_t getbyte();
+ void putbyte(uint8_t b);
+
+ int recv(char *data, int len);
+ void send(const char *data);
+
+ protected:
+ // Machine memory
+ bool read(Addr addr, size_t size, char *data);
+ bool write(Addr addr, size_t size, const char *data);
+
+ template <class T> T read(Addr addr);
+ template <class T> void write(Addr addr, T data);
+
+ public:
+ RemoteGDB(System *system, ExecContext *context);
+ ~RemoteGDB();
+
+ void replaceExecContext(ExecContext *xc) { context = xc; }
+
+ void attach(int fd);
+ void detach();
+ bool isattached();
+
+ bool acc(Addr addr, size_t len);
+ static int signal(int type);
+ bool trap(int type);
+
+ protected:
+ void getregs();
+ void setregs();
+
+ void clearSingleStep();
+ void setSingleStep();
+
+ PCEventQueue *getPcEventQueue();
+
+ protected:
+ class HardBreakpoint : public PCEvent
+ {
+ private:
+ RemoteGDB *gdb;
+
+ public:
+ int refcount;
+
+ public:
+ HardBreakpoint(RemoteGDB *_gdb, Addr addr);
+ std::string name() { return gdb->name() + ".hwbkpt"; }
+
+ virtual void process(ExecContext *xc);
+ };
+ friend class HardBreakpoint;
+
+ typedef std::map<Addr, HardBreakpoint *> break_map_t;
+ typedef break_map_t::iterator break_iter_t;
+ break_map_t hardBreakMap;
+
+ bool insertSoftBreak(Addr addr, size_t len);
+ bool removeSoftBreak(Addr addr, size_t len);
+ bool insertHardBreak(Addr addr, size_t len);
+ bool removeHardBreak(Addr addr, size_t len);
+
+ protected:
+ struct TempBreakpoint {
+ Addr address; // set here
+ MachInst bkpt_inst; // saved instruction at bkpt
+ int init_count; // number of times to skip bkpt
+ int count; // current count
+ };
+
+ TempBreakpoint notTakenBkpt;
+ TempBreakpoint takenBkpt;
+
+ void clearTempBreakpoint(TempBreakpoint &bkpt);
+ void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr);
+
+ public:
+ std::string name();
+};
+
+template <class T>
+inline T
+RemoteGDB::read(Addr addr)
+{
+ T temp;
+ read(addr, sizeof(T), (char *)&temp);
+ return temp;
+}
+
+template <class T>
+inline void
+RemoteGDB::write(Addr addr, T data)
+{ write(addr, sizeof(T), (const char *)&data); }
+
+class GDBListener
+{
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ GDBListener *listener;
+
+ public:
+ Event(GDBListener *l, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+
+ protected:
+ ListenSocket listener;
+ RemoteGDB *gdb;
+ int port;
+
+ public:
+ GDBListener(RemoteGDB *g, int p);
+ ~GDBListener();
+
+ void accept();
+ void listen();
+ std::string name();
+};
+
+#endif /* __REMOTE_GDB_H__ */
diff --git a/src/base/res_list.hh b/src/base/res_list.hh
new file mode 100644
index 000000000..960ed108e
--- /dev/null
+++ b/src/base/res_list.hh
@@ -0,0 +1,755 @@
+/*
+ * 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.
+ */
+
+#ifndef __RES_LIST_HH__
+#define __RES_LIST_HH__
+
+#include "base/cprintf.hh"
+#include <assert.h>
+
+#define DEBUG_REMOVE 0
+
+#define DEBUG_MEMORY 0
+//#define DEBUG_MEMORY DEBUG
+
+class res_list_base
+{
+#if DEBUG_MEMORY
+ protected:
+ static long long allocated_elements;
+ static long long allocated_lists;
+
+ public:
+ long long get_elements(void) {
+ return allocated_elements;
+ }
+ long long get_lists(void) {
+ return allocated_lists;
+ }
+
+#endif
+};
+
+#if DEBUG_MEMORY
+extern void what_the(void);
+#endif
+
+template<class T>
+class res_list : public res_list_base
+{
+ public:
+ class iterator;
+
+ class res_element
+ {
+ res_element *next;
+ res_element *prev;
+ T *data;
+ bool allocate_data;
+
+ public:
+ // always adds to the END of the list
+ res_element(res_element *_prev, bool allocate);
+ ~res_element();
+ void dump(void);
+
+ friend class res_list<T>;
+ friend class res_list<T>::iterator;
+ };
+
+ class iterator
+ {
+ private:
+ res_element *p;
+
+ friend class res_list<T>;
+
+ public:
+ // Constructors
+ iterator(res_element *q) : p(q) {}
+ iterator(void) { p=0; };
+
+ void dump(void);
+ T* data_ptr(void);
+ res_element *res_el_ptr(void) { return p;}
+ void point_to(T &d) { p->data = &d; }
+
+ iterator next(void) { return iterator(p->next); }
+ iterator prev(void) { return iterator(p->prev); }
+ bool operator== (iterator x) { return (x.p == this->p); }
+ bool operator != (iterator x) { return (x.p != this->p); }
+ T &operator * (void) { return *(p->data); }
+ T* operator -> (void) { return p->data; }
+ bool isnull(void) { return (p==0); }
+ bool notnull(void) { return (p!=0); }
+ };
+
+ private:
+ iterator unused_elements;
+ iterator head_ptr;
+ iterator tail_ptr;
+
+ unsigned base_elements;
+ unsigned extra_elements;
+ unsigned active_elements;
+ bool allocate_storage;
+ unsigned build_size;
+
+ int remove_count;
+
+ //
+ // Allocate new elements, and assign them to the unused_elements
+ // list.
+ //
+ unsigned allocate_elements(unsigned num, bool allocate_storage);
+
+ public:
+ //
+ // List Constructor
+ //
+ res_list(unsigned size, bool alloc_storage = false,
+ unsigned build_sz = 5);
+
+ //
+ // List Destructor
+ //
+ ~res_list();
+
+ iterator head(void) {return head_ptr;};
+ iterator tail(void) {return tail_ptr;};
+
+ unsigned num_free(void) { return size() - count(); }
+ unsigned size(void) { return base_elements + extra_elements; }
+ unsigned count(void) { return active_elements; }
+ bool empty(void) { return count() == 0; }
+ bool full(void);
+
+ //
+ // Insert with data copy
+ //
+ iterator insert_after(iterator prev, T *d);
+ iterator insert_after(iterator prev, T &d);
+ iterator insert_before(iterator prev, T *d);
+ iterator insert_before(iterator prev, T &d);
+
+ //
+ // Insert new list element (no data copy)
+ //
+ iterator insert_after(iterator prev);
+ iterator insert_before(iterator prev);
+
+ iterator add_tail(T *d) { return insert_after(tail_ptr, d); }
+ iterator add_tail(T &d) { return insert_after(tail_ptr, d); }
+ iterator add_tail(void) { return insert_after(tail_ptr); }
+ iterator add_head(T *d) { return insert_before(head_ptr, d); }
+ iterator add_head(T &d) { return insert_before(head_ptr, d); }
+ iterator add_head(void) { return insert_before(head_ptr); }
+
+ iterator remove(iterator q);
+ iterator remove_head(void) {return remove(head_ptr);}
+ iterator remove_tail(void) {return remove(tail_ptr);}
+
+ bool in_list(iterator j);
+ void free_extras(void);
+ void clear(void);
+ void dump(void);
+ void raw_dump(void);
+};
+
+template <class T>
+inline
+res_list<T>::res_element::res_element(res_element *_prev, bool allocate)
+{
+ allocate_data = allocate;
+ prev = _prev;
+ next = 0;
+
+ if (prev)
+ prev->next = this;
+
+ if (allocate)
+ data = new T;
+ else
+ data = 0;
+
+#if DEBUG_MEMORY
+ ++allocated_elements;
+#endif
+}
+
+template <class T>
+inline
+res_list<T>::res_element::~res_element(void)
+{
+ if (prev)
+ prev->next = next;
+
+ if (next)
+ next->prev = prev;
+
+ if (allocate_data)
+ delete data;
+
+#if DEBUG_MEMORY
+ --allocated_elements;
+#endif
+}
+
+template <class T>
+inline void
+res_list<T>::res_element::dump(void)
+{
+ cprintf(" prev = %#x\n", prev);
+ cprintf(" next = %#x\n", next);
+ cprintf(" data = %#x\n", data);
+}
+
+template <class T>
+inline void
+res_list<T>::iterator::dump(void)
+{
+ if (p && p->data)
+ p->data->dump();
+ else {
+ if (!p)
+ cprintf(" Null Pointer\n");
+ else
+ cprintf(" Null 'data' Pointer\n");
+ }
+}
+
+template <class T>
+inline T *
+res_list<T>::iterator::data_ptr(void)
+{
+ if (p)
+ return p->data;
+ else
+ return 0;
+}
+
+
+//
+// Allocate new elements, and assign them to the unused_elements
+// list.
+//
+template <class T>
+inline unsigned
+res_list<T>::allocate_elements(unsigned num, bool allocate_storage)
+{
+ res_element *pnew, *plast = 0, *pfirst=0;
+
+ for (int i=0; i<num; ++i) {
+ pnew = new res_element(plast, allocate_storage);
+ if (i==0)
+ pfirst = pnew;
+ plast = pnew;
+ }
+
+ if (unused_elements.notnull()) {
+ // Add these new elements to the front of the list
+ plast->next = unused_elements.res_el_ptr();
+ unused_elements.res_el_ptr()->prev = plast;
+ }
+
+ unused_elements = iterator(pfirst);
+
+ return num;
+}
+
+template <class T>
+inline
+res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz)
+{
+#if DEBUG_MEMORY
+ ++allocated_lists;
+#endif
+ extra_elements = 0;
+ active_elements = 0;
+ build_size = build_sz;
+ allocate_storage = alloc_storage;
+ remove_count = 0;
+
+ // Create the new elements
+ base_elements = allocate_elements(size, alloc_storage);
+
+ // The list of active elements
+ head_ptr = iterator(0);
+ tail_ptr = iterator(0);
+}
+
+//
+// List Destructor
+//
+template <class T>
+inline
+res_list<T>::~res_list(void)
+{
+ iterator n;
+
+#if DEBUG_MEMORY
+ --allocated_lists;
+#endif
+
+ // put everything into the unused list
+ clear();
+
+ // rudely delete all the res_elements
+ for (iterator p = unused_elements;
+ p.notnull();
+ p = n) {
+
+ n = p.next();
+
+ // delete the res_element
+ // (it will take care of deleting the data)
+ delete p.res_el_ptr();
+ }
+}
+
+template <class T>
+inline bool
+res_list<T>::full(void)
+{
+ if (build_size)
+ return false;
+ else
+ return unused_elements.isnull();
+}
+
+//
+// Insert with data copy
+//
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev, T *d)
+{
+ iterator p;
+
+ if (!allocate_storage)
+ this->panic("Can't copy data... not allocating storage");
+
+ p = insert_after(prev);
+ if (p.notnull())
+ *p = *d;
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev, T &d)
+{
+ iterator p;
+
+ p = insert_after(prev);
+ if (p.notnull()) {
+
+ if (allocate_storage) {
+ // if we allocate storage, then copy the contents of the
+ // specified object to our object
+ *p = d;
+ }
+ else {
+ // if we don't allocate storage, then we just want to
+ // point to the specified object
+ p.point_to(d);
+ }
+ }
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev)
+{
+
+#if DEBUG_MEMORY
+ if (active_elements > 2*base_elements) {
+ what_the();
+ }
+#endif
+
+ // If we have no unused elements, make some more
+ if (unused_elements.isnull()) {
+
+ if (build_size == 0) {
+ return 0; // No space left, and can't allocate more....
+ }
+
+ extra_elements += allocate_elements(build_size, allocate_storage);
+ }
+
+ // grab the first unused element
+ res_element *p = unused_elements.res_el_ptr();
+
+ unused_elements = unused_elements.next();
+
+ ++active_elements;
+
+ // Insert the new element
+ if (head_ptr.isnull()) {
+ //
+ // Special case #1: Empty List
+ //
+ head_ptr = p;
+ tail_ptr = p;
+ p->prev = 0;
+ p->next = 0;
+ }
+ else if (prev.isnull()) {
+ //
+ // Special case #2: Insert at head
+ //
+
+ // our next ptr points to old head element
+ p->next = head_ptr.res_el_ptr();
+
+ // our element becomes the new head element
+ head_ptr = p;
+
+ // no previous element for the head
+ p->prev = 0;
+
+ // old head element points back to this element
+ p->next->prev = p;
+ }
+ else if (prev.next().isnull()) {
+ //
+ // Special case #3 Insert at tail
+ //
+
+ // our prev pointer points to old tail element
+ p->prev = tail_ptr.res_el_ptr();
+
+ // our element becomes the new tail
+ tail_ptr = p;
+
+ // no next element for the tail
+ p->next = 0;
+
+ // old tail element point to this element
+ p->prev->next = p;
+ }
+ else {
+ //
+ // Normal insertion (after prev)
+ //
+ p->prev = prev.res_el_ptr();
+ p->next = prev.next().res_el_ptr();
+
+ prev.res_el_ptr()->next = p;
+ p->next->prev = p;
+ }
+
+ return iterator(p);
+}
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_before(iterator next, T &d)
+{
+ iterator p;
+
+ p = insert_before(next);
+ if (p.notnull()) {
+
+ if (allocate_storage) {
+ // if we allocate storage, then copy the contents of the
+ // specified object to our object
+ *p = d;
+ }
+ else {
+ // if we don't allocate storage, then we just want to
+ // point to the specified object
+ p.point_to(d);
+ }
+ }
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_before(iterator next)
+{
+
+#if DEBUG_MEMORY
+ if (active_elements > 2*base_elements) {
+ what_the();
+ }
+#endif
+
+ // If we have no unused elements, make some more
+ if (unused_elements.isnull()) {
+
+ if (build_size == 0) {
+ return 0; // No space left, and can't allocate more....
+ }
+
+ extra_elements += allocate_elements(build_size, allocate_storage);
+ }
+
+ // grab the first unused element
+ res_element *p = unused_elements.res_el_ptr();
+
+ unused_elements = unused_elements.next();
+
+ ++active_elements;
+
+ // Insert the new element
+ if (head_ptr.isnull()) {
+ //
+ // Special case #1: Empty List
+ //
+ head_ptr = p;
+ tail_ptr = p;
+ p->prev = 0;
+ p->next = 0;
+ }
+ else if (next.isnull()) {
+ //
+ // Special case #2 Insert at tail
+ //
+
+ // our prev pointer points to old tail element
+ p->prev = tail_ptr.res_el_ptr();
+
+ // our element becomes the new tail
+ tail_ptr = p;
+
+ // no next element for the tail
+ p->next = 0;
+
+ // old tail element point to this element
+ p->prev->next = p;
+ }
+ else if (next.prev().isnull()) {
+ //
+ // Special case #3: Insert at head
+ //
+
+ // our next ptr points to old head element
+ p->next = head_ptr.res_el_ptr();
+
+ // our element becomes the new head element
+ head_ptr = p;
+
+ // no previous element for the head
+ p->prev = 0;
+
+ // old head element points back to this element
+ p->next->prev = p;
+ }
+ else {
+ //
+ // Normal insertion (before next)
+ //
+ p->next = next.res_el_ptr();
+ p->prev = next.prev().res_el_ptr();
+
+ next.res_el_ptr()->prev = p;
+ p->prev->next = p;
+ }
+
+ return iterator(p);
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::remove(iterator q)
+{
+ res_element *p = q.res_el_ptr();
+ iterator n = 0;
+
+ // Handle the special cases
+ if (active_elements == 1) { // This is the only element
+ head_ptr = 0;
+ tail_ptr = 0;
+ }
+ else if (q == head_ptr) { // This is the head element
+ head_ptr = q.next();
+ head_ptr.res_el_ptr()->prev = 0;
+
+ n = head_ptr;
+ }
+ else if (q == tail_ptr) { // This is the tail element
+ tail_ptr = q.prev();
+ tail_ptr.res_el_ptr()->next = 0;
+ }
+ else { // This is between two elements
+ p->prev->next = p->next;
+ p->next->prev = p->prev;
+
+ // Get the "next" element for return
+ n = p->next;
+ }
+
+ --active_elements;
+
+ // Put this element back onto the unused list
+ p->next = unused_elements.res_el_ptr();
+ p->prev = 0;
+ if (p->next) { // NULL if unused list is empty
+ p->next->prev = p;
+ }
+
+ if (!allocate_storage) {
+ p->data = 0;
+ }
+
+ unused_elements = q;
+
+ // A little "garbage collection"
+ if (++remove_count > 10) {
+ // free_extras();
+ remove_count = 0;
+ }
+
+#if DEBUG_REMOVE
+ unsigned unused_count = 0;
+ for (iterator i=unused_elements;
+ i.notnull();
+ i = i.next()) {
+
+ ++unused_count;
+ }
+
+ assert((active_elements+unused_count) == (base_elements+extra_elements));
+#endif
+
+ return iterator(n);
+}
+
+
+template <class T>
+inline bool
+res_list<T>::in_list(iterator j)
+{
+ iterator i;
+
+ for (i=head(); i.notnull(); i=i.next()) {
+ if (j.res_el_ptr() == i.res_el_ptr()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <class T>
+inline void
+res_list<T>::free_extras(void)
+{
+ unsigned num_unused = base_elements + extra_elements - active_elements;
+ unsigned to_free = extra_elements;
+ res_element *p;
+
+
+ if (extra_elements != 0) {
+ //
+ // Free min(extra_elements, # unused elements)
+ //
+ if (extra_elements > num_unused) {
+ to_free = num_unused;
+ }
+
+ p = unused_elements.res_el_ptr();
+ for (int i=0; i<to_free; ++i) {
+ res_element *q = p->next;
+
+ delete p;
+
+ p = q;
+ }
+
+ // update the unused element pointer to point to the first
+ // element that wasn't deleted.
+ unused_elements = iterator(p);
+
+ // Update the number of extra elements
+ extra_elements -= to_free;
+ }
+
+ return;
+}
+
+
+template <class T>
+inline void
+res_list<T>::clear(void)
+{
+ iterator i,n;
+
+ for (i=head_ptr; i.notnull(); i=n) {
+ n = i.next();
+ remove(i);
+ }
+
+ free_extras();
+}
+
+template <class T>
+inline void
+res_list<T>::dump(void)
+{
+ for (iterator i=head(); !i.isnull(); i=i.next())
+ i->dump();
+}
+
+template <class T>
+inline void
+res_list<T>::raw_dump(void)
+{
+ int j = 0;
+ res_element *p;
+ for (iterator i=head(); !i.isnull(); i=i.next()) {
+ cprintf("Element %d:\n", j);
+
+ if (i.notnull()) {
+ p = i.res_el_ptr();
+ cprintf(" points to res_element @ %#x\n", p);
+ p->dump();
+ cprintf(" Data Element:\n");
+ i->dump();
+ }
+ else {
+ cprintf(" NULL iterator!\n");
+ }
+
+ ++j;
+ }
+
+}
+
+#endif // __RES_LIST_HH__
diff --git a/src/base/sat_counter.cc b/src/base/sat_counter.cc
new file mode 100644
index 000000000..7920f6c81
--- /dev/null
+++ b/src/base/sat_counter.cc
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+
+#include "base/sat_counter.hh"
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+
+using namespace std;
+
+
+SaturatingCounterPred::SaturatingCounterPred(string p_name,
+ string z_name,
+ string o_name,
+ unsigned _index_bits,
+ unsigned _counter_bits,
+ unsigned _zero_change,
+ unsigned _one_change,
+ unsigned _thresh,
+ unsigned _init_value)
+{
+ pred_name = p_name;
+ zero_name = z_name;
+ one_name = o_name;
+
+ index_bits = _index_bits;
+ counter_bits = _counter_bits;
+ zero_change = _zero_change;
+ one_change = _one_change;
+ thresh = _thresh;
+ init_value = _init_value;
+
+ max_index = (1 << index_bits) - 1;
+ max_value = (1 << counter_bits) - 1;
+
+ table = new unsigned[max_index + 1];
+
+ // Initialize with the right parameters & clear the counter
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+}
+
+void SaturatingCounterPred::regStats()
+{
+ using namespace Stats;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ predicted_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ predicted_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds";
+ correct_pred_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds";
+ correct_pred_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":" << zero_name << ":updates";
+ description << "number of actual " << zero_name << "s";
+ record_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":updates";
+ description << "number of actual " << one_name << "s";
+ record_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+}
+
+void SaturatingCounterPred::regFormulas()
+{
+ using namespace Stats;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":predictions";
+ preds_total
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ preds_total = predicted_zero + predicted_one;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << pred_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name;
+ pred_frac_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_zero = 100 * predicted_zero / preds_total;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name;
+ pred_frac_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_one = 100 * predicted_one / preds_total;
+ description.str("");
+ name.str("");
+
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":correct_preds";
+ correct_total
+ .name(name.str())
+ .desc("total correct predictions made")
+ ;
+ correct_total = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":updates";
+ updates_total
+ .name(name.str())
+ .desc("total number of updates")
+ ;
+ updates_total = record_zero + record_one;
+ name.str("");
+
+ //
+ // Prediction accuracy rates
+ //
+ name << pred_name << ":pred_rate";
+ pred_rate
+ .name(name.str())
+ .desc("correct fraction of all preds")
+ ;
+ pred_rate = correct_total / updates_total;
+ name.str("");
+
+ name << pred_name << ":" << zero_name << ":pred_rate";
+ description << "fraction of " << zero_name << " preds that were correct";
+ frac_correct_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_zero = 100 * correct_pred_zero /
+ (correct_pred_zero + record_one - correct_pred_one);
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_rate";
+ description << "fraction of " << one_name << " preds that were correct";
+ frac_correct_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_one = 100 * correct_pred_one /
+ (correct_pred_one + record_zero - correct_pred_zero);
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << pred_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ coverage_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_zero = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ coverage_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_one = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh
new file mode 100644
index 000000000..d7be17b6f
--- /dev/null
+++ b/src/base/sat_counter.hh
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#ifndef __SAT_COUNTER_HH__
+#define __SAT_COUNTER_HH__
+
+#include <string>
+
+#include "base/predictor.hh"
+
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+//
+//
+// A simple saturating counter predictor
+//
+//
+class SaturatingCounterPred : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string zero_name;
+ std::string one_name;
+
+ unsigned index_bits;
+ unsigned counter_bits;
+ unsigned zero_change;
+ unsigned one_change;
+ unsigned thresh;
+ unsigned init_value;
+
+ unsigned max_value; // maximum counter value
+
+ unsigned long max_index; // also the index mask value
+ unsigned *table;
+
+ // Statistics
+ Stats::Scalar<> predicted_one; // Total predictions of one, preds_one
+ Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
+ Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
+ Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+
+ Stats::Scalar<> record_zero; //updates_zero
+ Stats::Scalar<> record_one; //updates_one
+
+ Stats::Formula preds_total;
+ Stats::Formula pred_frac_zero;
+ Stats::Formula pred_frac_one;
+ Stats::Formula correct_total;
+ Stats::Formula updates_total;
+ Stats::Formula pred_rate;
+ Stats::Formula frac_correct_zero;
+ Stats::Formula frac_correct_one;
+ Stats::Formula coverage_zero;
+ Stats::Formula coverage_one;
+
+ private:
+ bool pred_one(unsigned &counter) { return counter > thresh; }
+ bool pred_zero(unsigned &counter) { return counter <= thresh; }
+
+ void update_one(unsigned &counter) {
+
+ if (one_change)
+ counter += one_change;
+ else
+ counter = 0;
+
+ // check for wrap
+ if (counter > max_value)
+ counter = max_value;
+ }
+
+ void update_zero(unsigned &counter) {
+ if (zero_change) {
+ // check for wrap
+ if (counter < zero_change)
+ counter = 0;
+ else
+ counter -= zero_change;
+ } else
+ counter = 0;
+ }
+
+
+ public:
+
+ SaturatingCounterPred(std::string p_name,
+ std::string z_name, std::string o_name,
+ unsigned _index_bits, unsigned _counter_bits = 2,
+ unsigned _zero_change = 1, unsigned _one_change = 1,
+ unsigned _thresh = 1, unsigned _init_value = 0);
+
+ void clear() {
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+ }
+
+ // Record the ACTUAL result... and indicate whether the prediction
+ // corresponding to this event was correct
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+ record(_index, _val, _predicted);
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+ unsigned long index = _index & max_index;
+
+ if (_val) {
+ update_one(table[index]);
+ ++record_one;
+
+ if (_predicted)
+ ++correct_pred_one;
+ } else {
+ update_zero(table[index]);
+ ++record_zero;
+
+ if (!_predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ return table[index];
+ }
+
+
+ unsigned predict(unsigned long _index, unsigned &pdata) {
+ return predict(_index);
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index])) {
+ ++predicted_one;
+ return 1;
+ }
+
+ ++predicted_zero;
+ return 0;
+ }
+
+ // No internal state is changed here
+ unsigned peek(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index]))
+ return 1;
+
+ return 0;
+ }
+
+
+ //=======================================================
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // __SAT_COUNTER_HH__
diff --git a/src/base/sched_list.hh b/src/base/sched_list.hh
new file mode 100644
index 000000000..f794e3514
--- /dev/null
+++ b/src/base/sched_list.hh
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SCHED_LIST_HH
+#define SCHED_LIST_HH
+
+#include <list>
+#include "base/intmath.hh"
+#include "base/misc.hh"
+
+
+// Any types you use this class for must be covered here...
+namespace {
+ void ClearEntry(int &i) { i = 0; };
+ void ClearEntry(unsigned &i) { i = 0; };
+ void ClearEntry(double &i) { i = 0; };
+ template <class T> void ClearEntry(std::list<T> &l) { l.clear(); };
+};
+
+
+//
+// this is a special list type that allows the user to insert elements at a
+// specified positive offset from the "current" element, but only allow them
+// be extracted from the "current" element
+//
+
+
+template <class T>
+class SchedList
+{
+ T *data_array;
+ unsigned position;
+ unsigned size;
+ unsigned mask;
+
+ public:
+ SchedList(unsigned size);
+ SchedList(void);
+
+ void init(unsigned size);
+
+ T &operator[](unsigned offset);
+
+ void advance(void);
+
+ void clear(void);
+};
+
+
+
+//
+// Constructor
+//
+template<class T>
+SchedList<T>::SchedList(unsigned _size)
+{
+ size = _size;
+
+ // size must be a power of two
+ if (!isPowerOf2(size)) {
+ panic("SchedList: size must be a power of two");
+ }
+
+ if (size < 2) {
+ panic("SchedList: you don't want a list that small");
+ }
+
+ // calculate the bit mask for the modulo operation
+ mask = size - 1;
+
+ data_array = new T[size];
+
+ if (!data_array) {
+ panic("SchedList: could not allocate memory");
+ }
+
+ clear();
+}
+
+template<class T>
+SchedList<T>::SchedList(void)
+{
+ data_array = 0;
+ size = 0;
+}
+
+
+template<class T> void
+SchedList<T>::init(unsigned _size)
+{
+ size = _size;
+
+ if (!data_array) {
+ // size must be a power of two
+ if (size & (size-1)) {
+ panic("SchedList: size must be a power of two");
+ }
+
+ if (size < 2) {
+ panic("SchedList: you don't want a list that small");
+ }
+
+ // calculate the bit mask for the modulo operation
+ mask = size - 1;
+
+ data_array = new T[size];
+
+ if (!data_array) {
+ panic("SchedList: could not allocate memory");
+ }
+
+ clear();
+ }
+}
+
+
+template<class T> void
+SchedList<T>::advance(void)
+{
+ ClearEntry(data_array[position]);
+
+ // position = (++position % size);
+ position = ++position & mask;
+}
+
+
+template<class T> void
+SchedList<T>::clear(void)
+{
+ for (unsigned i=0; i<size; ++i) {
+ ClearEntry(data_array[i]);
+ }
+
+ position = 0;
+}
+
+
+template<class T> T&
+SchedList<T>::operator[](unsigned offset)
+{
+ if (offset >= size) {
+ panic("SchedList: can't access element beyond current pointer");
+ }
+
+ // unsigned p = (position + offset) % size;
+ unsigned p = (position + offset) & mask;
+
+ return data_array[p];
+}
+
+
+
+#endif
diff --git a/src/base/socket.cc b/src/base/socket.cc
new file mode 100644
index 000000000..45a60e7e3
--- /dev/null
+++ b/src/base/socket.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "base/socket.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+ListenSocket::ListenSocket()
+ : listening(false), fd(-1)
+{}
+
+ListenSocket::~ListenSocket()
+{
+ if (fd != -1)
+ close(fd);
+}
+
+// Create a socket and configure it for listening
+bool
+ListenSocket::listen(int port, bool reuse)
+{
+ if (listening)
+ panic("Socket already listening!");
+
+ fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ panic("Can't create socket:%s !", strerror(errno));
+
+ if (reuse) {
+ int i = 1;
+ if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
+ sizeof(i)) < 0)
+ panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!");
+ }
+
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ sockaddr.sin_port = htons(port);
+ int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
+ if (ret != 0) {
+ if (ret == -1 && errno != EADDRINUSE)
+ panic("ListenSocket(listen): bind() failed!");
+ return false;
+ }
+
+ if (::listen(fd, 1) == -1)
+ panic("ListenSocket(listen): listen() failed!");
+
+ listening = true;
+
+ return true;
+}
+
+
+// Open a connection. Accept will block, so if you don't want it to,
+// make sure a connection is ready before you call accept.
+int
+ListenSocket::accept(bool nodelay)
+{
+ struct sockaddr_in sockaddr;
+ socklen_t slen = sizeof (sockaddr);
+ int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
+ if (sfd != -1 && nodelay) {
+ int i = 1;
+ ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
+ }
+
+ return sfd;
+}
diff --git a/src/base/socket.hh b/src/base/socket.hh
new file mode 100644
index 000000000..848405c09
--- /dev/null
+++ b/src/base/socket.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKET_HH__
+#define __SOCKET_HH__
+
+class ListenSocket
+{
+ protected:
+ bool listening;
+ int fd;
+
+ public:
+ ListenSocket();
+ virtual ~ListenSocket();
+
+ virtual int accept(bool nodelay = false);
+ virtual bool listen(int port, bool reuse = true);
+
+ int getfd() const { return fd; }
+ bool islistening() const { return listening; }
+};
+
+#endif //__SOCKET_HH__
diff --git a/src/base/statistics.cc b/src/base/statistics.cc
new file mode 100644
index 000000000..20de46347
--- /dev/null
+++ b/src/base/statistics.cc
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iomanip>
+#include <fstream>
+#include <list>
+#include <map>
+#include <string>
+
+#include "base/callback.hh"
+#include "base/cprintf.hh"
+#include "base/hostinfo.hh"
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "base/trace.hh"
+#include "base/stats/statdb.hh"
+#include "config/stats_binning.hh"
+
+using namespace std;
+
+namespace Stats {
+
+StatData *
+DataAccess::find() const
+{
+ return Database::find(const_cast<void *>((const void *)this));
+}
+
+const StatData *
+getStatData(const void *stat)
+{
+ return Database::find(const_cast<void *>(stat));
+}
+
+void
+DataAccess::map(StatData *data)
+{
+ Database::regStat(this, data);
+}
+
+StatData *
+DataAccess::statData()
+{
+ StatData *ptr = find();
+ assert(ptr);
+ return ptr;
+}
+
+const StatData *
+DataAccess::statData() const
+{
+ const StatData *ptr = find();
+ assert(ptr);
+ return ptr;
+}
+
+void
+DataAccess::setInit()
+{
+ statData()->flags |= init;
+}
+
+void
+DataAccess::setPrint()
+{
+ Database::regPrint(this);
+}
+
+StatData::StatData()
+ : flags(none), precision(-1), prereq(0)
+{
+ static int count = 0;
+ id = count++;
+}
+
+StatData::~StatData()
+{
+}
+
+bool
+StatData::less(StatData *stat1, StatData *stat2)
+{
+ const string &name1 = stat1->name;
+ const string &name2 = stat2->name;
+
+ vector<string> v1;
+ vector<string> v2;
+
+ tokenize(v1, name1, '.');
+ tokenize(v2, name2, '.');
+
+ int last = min(v1.size(), v2.size()) - 1;
+ for (int i = 0; i < last; ++i)
+ if (v1[i] != v2[i])
+ return v1[i] < v2[i];
+
+ // Special compare for last element.
+ if (v1[last] == v2[last])
+ return v1.size() < v2.size();
+ else
+ return v1[last] < v2[last];
+
+ return false;
+}
+
+bool
+StatData::baseCheck() const
+{
+ if (!(flags & init)) {
+#ifdef DEBUG
+ cprintf("this is stat number %d\n", id);
+#endif
+ panic("Not all stats have been initialized");
+ return false;
+ }
+
+ if ((flags & print) && name.empty()) {
+ panic("all printable stats must be named");
+ return false;
+ }
+
+ return true;
+}
+
+
+void
+FormulaBase::result(VResult &vec) const
+{
+ if (root)
+ vec = root->result();
+}
+
+Result
+FormulaBase::total() const
+{
+ return root ? root->total() : 0.0;
+}
+
+size_t
+FormulaBase::size() const
+{
+ if (!root)
+ return 0;
+ else
+ return root->size();
+}
+
+bool
+FormulaBase::binned() const
+{
+ return root && root->binned();
+}
+
+void
+FormulaBase::reset()
+{
+}
+
+bool
+FormulaBase::zero() const
+{
+ VResult vec;
+ result(vec);
+ for (int i = 0; i < vec.size(); ++i)
+ if (vec[i] != 0.0)
+ return false;
+ return true;
+}
+
+void
+FormulaBase::update(StatData *)
+{
+}
+
+string
+FormulaBase::str() const
+{
+ return root ? root->str() : "";
+}
+
+Formula::Formula()
+{
+ setInit();
+}
+
+Formula::Formula(Temp r)
+{
+ root = r;
+ assert(size());
+}
+
+const Formula &
+Formula::operator=(Temp r)
+{
+ assert(!root && "Can't change formulas");
+ root = r;
+ assert(size());
+ return *this;
+}
+
+const Formula &
+Formula::operator+=(Temp r)
+{
+ if (root)
+ root = NodePtr(new BinaryNode<std::plus<Result> >(root, r));
+ else
+ root = r;
+ assert(size());
+ return *this;
+}
+
+MainBin::MainBin(const string &name)
+ : _name(name), mem(NULL), memsize(-1)
+{
+ Database::regBin(this, name);
+}
+
+MainBin::~MainBin()
+{
+ if (mem)
+ delete [] mem;
+}
+
+char *
+MainBin::memory(off_t off)
+{
+ if (memsize == -1)
+ memsize = ceilPow2((size_t) offset());
+
+ if (!mem) {
+ mem = new char[memsize];
+ memset(mem, 0, memsize);
+ }
+
+ assert(offset() <= size());
+ return mem + off;
+}
+
+void
+check()
+{
+ typedef Database::stat_list_t::iterator iter_t;
+
+ iter_t i, end = Database::stats().end();
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ assert(data);
+ if (!data->check() || !data->baseCheck())
+ panic("stat check failed for %s\n", data->name);
+ }
+
+ int j = 0;
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ if (!(data->flags & print))
+ data->name = "__Stat" + to_string(j++);
+ }
+
+ Database::stats().sort(StatData::less);
+
+#if STATS_BINNING
+ if (MainBin::curBin() == NULL) {
+ static MainBin mainBin("main bin");
+ mainBin.activate();
+ }
+#endif
+
+ if (i == end)
+ return;
+
+ iter_t last = i;
+ ++i;
+
+ for (i = Database::stats().begin(); i != end; ++i) {
+ if ((*i)->name == (*last)->name)
+ panic("same name used twice! name=%s\n", (*i)->name);
+
+ last = i;
+ }
+}
+
+CallbackQueue resetQueue;
+
+void
+reset()
+{
+ // reset non-binned stats
+ Database::stat_list_t::iterator i = Database::stats().begin();
+ Database::stat_list_t::iterator end = Database::stats().end();
+ while (i != end) {
+ StatData *data = *i;
+ if (!data->binned())
+ data->reset();
+ ++i;
+ }
+
+ // save the bin so we can go back to where we were
+ MainBin *orig = MainBin::curBin();
+
+ // reset binned stats
+ Database::bin_list_t::iterator bi = Database::bins().begin();
+ Database::bin_list_t::iterator be = Database::bins().end();
+ while (bi != be) {
+ MainBin *bin = *bi;
+ bin->activate();
+
+ i = Database::stats().begin();
+ while (i != end) {
+ StatData *data = *i;
+ if (data->binned())
+ data->reset();
+ ++i;
+ }
+ ++bi;
+ }
+
+ // restore bin
+ MainBin::curBin() = orig;
+
+ resetQueue.process();
+}
+
+void
+registerResetCallback(Callback *cb)
+{
+ resetQueue.add(cb);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/statistics.hh b/src/base/statistics.hh
new file mode 100644
index 000000000..dd507c091
--- /dev/null
+++ b/src/base/statistics.hh
@@ -0,0 +1,2896 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Declaration of Statistics objects.
+ */
+
+/**
+* @todo
+*
+* Generalized N-dimensinal vector
+* documentation
+* key stats
+* interval stats
+* -- these both can use the same function that prints out a
+* specific set of stats
+* VectorStandardDeviation totals
+* Document Namespaces
+*/
+#ifndef __BASE_STATISTICS_HH__
+#define __BASE_STATISTICS_HH__
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/cprintf.hh"
+#include "base/intmath.hh"
+#include "base/refcnt.hh"
+#include "base/str.hh"
+#include "base/stats/bin.hh"
+#include "base/stats/flags.hh"
+#include "base/stats/visit.hh"
+#include "base/stats/types.hh"
+#include "config/stats_binning.hh"
+#include "sim/host.hh"
+
+class Callback;
+
+/** The current simulated cycle. */
+extern Tick curTick;
+
+/* A namespace for all of the Statistics */
+namespace Stats {
+
+/* Contains the statistic implementation details */
+//////////////////////////////////////////////////////////////////////
+//
+// Statistics Framework Base classes
+//
+//////////////////////////////////////////////////////////////////////
+struct StatData
+{
+ /** The name of the stat. */
+ std::string name;
+ /** The description of the stat. */
+ std::string desc;
+ /** The formatting flags. */
+ StatFlags flags;
+ /** The display precision. */
+ int precision;
+ /** A pointer to a prerequisite Stat. */
+ const StatData *prereq;
+ /**
+ * A unique stat ID for each stat in the simulator.
+ * Can be used externally for lookups as well as for debugging.
+ */
+ int id;
+
+ StatData();
+ virtual ~StatData();
+
+ /**
+ * @return true if the stat is binned.
+ */
+ virtual bool binned() const = 0;
+
+ /**
+ * Reset the corresponding stat to the default state.
+ */
+ virtual void reset() = 0;
+
+ /**
+ * @return true if this stat has a value and satisfies its
+ * requirement as a prereq
+ */
+ virtual bool zero() const = 0;
+
+ /**
+ * Check that this stat has been set up properly and is ready for
+ * use
+ * @return true for success
+ */
+ virtual bool check() const = 0;
+ bool baseCheck() const;
+
+ /**
+ * Visitor entry for outputing statistics data
+ */
+ virtual void visit(Visit &visitor) = 0;
+
+ /**
+ * Checks if the first stat's name is alphabetically less than the second.
+ * This function breaks names up at periods and considers each subname
+ * separately.
+ * @param stat1 The first stat.
+ * @param stat2 The second stat.
+ * @return stat1's name is alphabetically before stat2's
+ */
+ static bool less(StatData *stat1, StatData *stat2);
+};
+
+class ScalarData : public StatData
+{
+ public:
+ virtual Counter value() const = 0;
+ virtual Result result() const = 0;
+ virtual Result total() const = 0;
+ virtual void visit(Visit &visitor) { visitor.visit(*this); }
+};
+
+template <class Stat>
+class ScalarStatData : public ScalarData
+{
+ protected:
+ Stat &s;
+
+ public:
+ ScalarStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual Counter value() const { return s.value(); }
+ virtual Result result() const { return s.result(); }
+ virtual Result total() const { return s.total(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+};
+
+struct VectorData : public StatData
+{
+ /** Names and descriptions of subfields. */
+ mutable std::vector<std::string> subnames;
+ mutable std::vector<std::string> subdescs;
+
+ virtual size_t size() const = 0;
+ virtual const VCounter &value() const = 0;
+ virtual const VResult &result() const = 0;
+ virtual Result total() const = 0;
+ void update()
+ {
+ if (!subnames.empty()) {
+ int s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+
+ if (subdescs.size() < s)
+ subdescs.resize(s);
+ }
+ }
+};
+
+template <class Stat>
+class VectorStatData : public VectorData
+{
+ protected:
+ Stat &s;
+ mutable VCounter cvec;
+ mutable VResult rvec;
+
+ public:
+ VectorStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void reset() { s.reset(); }
+
+ virtual size_t size() const { return s.size(); }
+ virtual VCounter &value() const
+ {
+ s.value(cvec);
+ return cvec;
+ }
+ virtual const VResult &result() const
+ {
+ s.result(rvec);
+ return rvec;
+ }
+ virtual Result total() const { return s.total(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct DistDataData
+{
+ Counter min_val;
+ Counter max_val;
+ Counter underflow;
+ Counter overflow;
+ VCounter cvec;
+ Counter sum;
+ Counter squares;
+ Counter samples;
+
+ Counter min;
+ Counter max;
+ Counter bucket_size;
+ int size;
+ bool fancy;
+};
+
+struct DistData : public StatData
+{
+ /** Local storage for the entry values, used for printing. */
+ DistDataData data;
+};
+
+template <class Stat>
+class DistStatData : public DistData
+{
+ protected:
+ Stat &s;
+
+ public:
+ DistStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct VectorDistData : public StatData
+{
+ std::vector<DistDataData> data;
+
+ /** Names and descriptions of subfields. */
+ mutable std::vector<std::string> subnames;
+ mutable std::vector<std::string> subdescs;
+
+ /** Local storage for the entry values, used for printing. */
+ mutable VResult rvec;
+
+ virtual size_t size() const = 0;
+ void update()
+ {
+ int s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+
+ if (subdescs.size() < s)
+ subdescs.resize(s);
+ }
+};
+
+template <class Stat>
+class VectorDistStatData : public VectorDistData
+{
+ protected:
+ Stat &s;
+ typedef typename Stat::bin_t bin_t;
+
+ public:
+ VectorDistStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return bin_t::binned; }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual size_t size() const { return s.size(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct Vector2dData : public StatData
+{
+ /** Names and descriptions of subfields. */
+ std::vector<std::string> subnames;
+ std::vector<std::string> subdescs;
+ std::vector<std::string> y_subnames;
+
+ /** Local storage for the entry values, used for printing. */
+ mutable VCounter cvec;
+ mutable int x;
+ mutable int y;
+
+ void update()
+ {
+ if (subnames.size() < x)
+ subnames.resize(x);
+ }
+};
+
+template <class Stat>
+class Vector2dStatData : public Vector2dData
+{
+ protected:
+ Stat &s;
+ typedef typename Stat::bin_t bin_t;
+
+ public:
+ Vector2dStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return bin_t::binned; }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+
+class DataAccess
+{
+ protected:
+ StatData *find() const;
+ void map(StatData *data);
+
+ StatData *statData();
+ const StatData *statData() const;
+
+ void setInit();
+ void setPrint();
+};
+
+template <class Parent, class Child, template <class> class Data>
+class Wrap : public Child
+{
+ protected:
+ Parent &self() { return *reinterpret_cast<Parent *>(this); }
+
+ protected:
+ Data<Child> *statData()
+ {
+ StatData *__data = DataAccess::statData();
+ Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data);
+ assert(ptr);
+ return ptr;
+ }
+
+ public:
+ const Data<Child> *statData() const
+ {
+ const StatData *__data = DataAccess::statData();
+ const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data);
+ assert(ptr);
+ return ptr;
+ }
+
+ protected:
+ /**
+ * Copy constructor, copies are not allowed.
+ */
+ Wrap(const Wrap &stat);
+ /**
+ * Can't copy stats.
+ */
+ void operator=(const Wrap &);
+
+ public:
+ Wrap()
+ {
+ map(new Data<Child>(*this));
+ }
+
+ /**
+ * Set the name and marks this stat to print at the end of simulation.
+ * @param name The new name.
+ * @return A reference to this stat.
+ */
+ Parent &name(const std::string &_name)
+ {
+ Data<Child> *data = this->statData();
+ data->name = _name;
+ this->setPrint();
+ return this->self();
+ }
+
+ /**
+ * Set the description and marks this stat to print at the end of
+ * simulation.
+ * @param desc The new description.
+ * @return A reference to this stat.
+ */
+ Parent &desc(const std::string &_desc)
+ {
+ this->statData()->desc = _desc;
+ return this->self();
+ }
+
+ /**
+ * Set the precision and marks this stat to print at the end of simulation.
+ * @param p The new precision
+ * @return A reference to this stat.
+ */
+ Parent &precision(int _precision)
+ {
+ this->statData()->precision = _precision;
+ return this->self();
+ }
+
+ /**
+ * Set the flags and marks this stat to print at the end of simulation.
+ * @param f The new flags.
+ * @return A reference to this stat.
+ */
+ Parent &flags(StatFlags _flags)
+ {
+ this->statData()->flags |= _flags;
+ return this->self();
+ }
+
+ /**
+ * Set the prerequisite stat and marks this stat to print at the end of
+ * simulation.
+ * @param prereq The prerequisite stat.
+ * @return A reference to this stat.
+ */
+ template <class Stat>
+ Parent &prereq(const Stat &prereq)
+ {
+ this->statData()->prereq = prereq.statData();
+ return this->self();
+ }
+};
+
+template <class Parent, class Child, template <class Child> class Data>
+class WrapVec : public Wrap<Parent, Child, Data>
+{
+ public:
+ // The following functions are specific to vectors. If you use them
+ // in a non vector context, you will get a nice compiler error!
+
+ /**
+ * Set the subfield name for the given index, and marks this stat to print
+ * at the end of simulation.
+ * @param index The subfield index.
+ * @param name The new name of the subfield.
+ * @return A reference to this stat.
+ */
+ Parent &subname(int index, const std::string &name)
+ {
+ std::vector<std::string> &subn = this->statData()->subnames;
+ if (subn.size() <= index)
+ subn.resize(index + 1);
+ subn[index] = name;
+ return this->self();
+ }
+
+ /**
+ * Set the subfield description for the given index and marks this stat to
+ * print at the end of simulation.
+ * @param index The subfield index.
+ * @param desc The new description of the subfield
+ * @return A reference to this stat.
+ */
+ Parent &subdesc(int index, const std::string &desc)
+ {
+ std::vector<std::string> &subd = this->statData()->subdescs;
+ if (subd.size() <= index)
+ subd.resize(index + 1);
+ subd[index] = desc;
+
+ return this->self();
+ }
+
+};
+
+template <class Parent, class Child, template <class Child> class Data>
+class WrapVec2d : public WrapVec<Parent, Child, Data>
+{
+ public:
+ /**
+ * @warning This makes the assumption that if you're gonna subnames a 2d
+ * vector, you're subnaming across all y
+ */
+ Parent &ysubnames(const char **names)
+ {
+ Data<Child> *data = this->statData();
+ data->y_subnames.resize(this->y);
+ for (int i = 0; i < this->y; ++i)
+ data->y_subnames[i] = names[i];
+ return this->self();
+ }
+ Parent &ysubname(int index, const std::string subname)
+ {
+ Data<Child> *data = this->statData();
+ assert(index < this->y);
+ data->y_subnames.resize(this->y);
+ data->y_subnames[index] = subname.c_str();
+ return this->self();
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Simple Statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Templatized storage and interface for a simple scalar stat.
+ */
+struct StatStor
+{
+ public:
+ /** The paramaters for this storage type, none for a scalar. */
+ struct Params { };
+
+ private:
+ /** The statistic value. */
+ Counter data;
+
+ public:
+ /**
+ * Builds this storage element and calls the base constructor of the
+ * datatype.
+ */
+ StatStor(const Params &) : data(Counter()) {}
+
+ /**
+ * The the stat to the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void set(Counter val, const Params &p) { data = val; }
+ /**
+ * Increment the stat by the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void inc(Counter val, const Params &p) { data += val; }
+ /**
+ * Decrement the stat by the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void dec(Counter val, const Params &p) { data -= val; }
+ /**
+ * Return the value of this stat as its base type.
+ * @param p The params of this storage type.
+ * @return The value of this stat.
+ */
+ Counter value(const Params &p) const { return data; }
+ /**
+ * Return the value of this stat as a result type.
+ * @param p The parameters of this storage type.
+ * @return The value of this stat.
+ */
+ Result result(const Params &p) const { return (Result)data; }
+ /**
+ * Reset stat value to default
+ */
+ void reset() { data = Counter(); }
+
+ /**
+ * @return true if zero value
+ */
+ bool zero() const { return data == Counter(); }
+};
+
+/**
+ * Templatized storage and interface to a per-cycle average stat. This keeps
+ * a current count and updates a total (count * cycles) when this count
+ * changes. This allows the quick calculation of a per cycle count of the item
+ * being watched. This is good for keeping track of residencies in structures
+ * among other things.
+ * @todo add lateny to the stat and fix binning.
+ */
+struct AvgStor
+{
+ public:
+ /** The paramaters for this storage type */
+ struct Params
+ {
+ /**
+ * The current count. We stash this here because the current
+ * value is not a binned value.
+ */
+ Counter current;
+ };
+
+ private:
+ /** The total count for all cycles. */
+ mutable Result total;
+ /** The cycle that current last changed. */
+ mutable Tick last;
+
+ public:
+ /**
+ * Build and initializes this stat storage.
+ */
+ AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); }
+
+ /**
+ * Set the current count to the one provided, update the total and last
+ * set values.
+ * @param val The new count.
+ * @param p The parameters for this storage.
+ */
+ void set(Counter val, Params &p) {
+ total += p.current * (curTick - last);
+ last = curTick;
+ p.current = val;
+ }
+
+ /**
+ * Increment the current count by the provided value, calls set.
+ * @param val The amount to increment.
+ * @param p The parameters for this storage.
+ */
+ void inc(Counter val, Params &p) { set(p.current + val, p); }
+
+ /**
+ * Deccrement the current count by the provided value, calls set.
+ * @param val The amount to decrement.
+ * @param p The parameters for this storage.
+ */
+ void dec(Counter val, Params &p) { set(p.current - val, p); }
+
+ /**
+ * Return the current count.
+ * @param p The parameters for this storage.
+ * @return The current count.
+ */
+ Counter value(const Params &p) const { return p.current; }
+
+ /**
+ * Return the current average.
+ * @param p The parameters for this storage.
+ * @return The current average.
+ */
+ Result result(const Params &p) const
+ {
+ total += p.current * (curTick - last);
+ last = curTick;
+ return (Result)(total + p.current) / (Result)(curTick + 1);
+ }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ total = 0;
+ last = curTick;
+ }
+
+ /**
+ * @return true if zero value
+ */
+ bool zero() const { return total == 0.0; }
+};
+
+/**
+ * Implementation of a scalar stat. The type of stat is determined by the
+ * Storage template. The storage for this stat is held within the Bin class.
+ * This allows for breaking down statistics across multiple bins easily.
+ */
+template <class Storage, class Bin>
+class ScalarBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template Bin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage object for this stat.
+ */
+ Storage *data() { return bin.data(params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage object for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(*_params);
+ }
+
+ public:
+ /**
+ * Return the current value of this stat as its base type.
+ * @return The current value.
+ */
+ Counter value() const { return data()->value(params); }
+
+ public:
+ /**
+ * Create and initialize this stat, register it with the database.
+ */
+ ScalarBase()
+ {
+ bin.init(params);
+ }
+
+ public:
+ // Common operators for stats
+ /**
+ * Increment the stat by 1. This calls the associated storage object inc
+ * function.
+ */
+ void operator++() { data()->inc(1, params); }
+ /**
+ * Decrement the stat by 1. This calls the associated storage object dec
+ * function.
+ */
+ void operator--() { data()->dec(1, params); }
+
+ /** Increment the stat by 1. */
+ void operator++(int) { ++*this; }
+ /** Decrement the stat by 1. */
+ void operator--(int) { --*this; }
+
+ /**
+ * Set the data value to the given value. This calls the associated storage
+ * object set function.
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { data()->set(v, params); }
+
+ /**
+ * Increment the stat by the given value. This calls the associated
+ * storage object inc function.
+ * @param v The value to add.
+ */
+ template <typename U>
+ void operator+=(const U &v) { data()->inc(v, params); }
+
+ /**
+ * Decrement the stat by the given value. This calls the associated
+ * storage object dec function.
+ * @param v The value to substract.
+ */
+ template <typename U>
+ void operator-=(const U &v) { data()->dec(v, params); }
+
+ /**
+ * Return the number of elements, always 1 for a scalar.
+ * @return 1.
+ */
+ size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+
+ bool check() const { return bin.initialized(); }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ Counter value() { return data()->value(params); }
+
+ Result result() { return data()->result(params); }
+
+ Result total() { return result(); }
+
+ bool zero() { return result() == 0.0; }
+
+};
+
+class ProxyData : public ScalarData
+{
+ public:
+ virtual void visit(Visit &visitor) { visitor.visit(*this); }
+ virtual bool binned() const { return false; }
+ virtual std::string str() const { return to_string(value()); }
+ virtual size_t size() const { return 1; }
+ virtual bool zero() const { return value() == 0; }
+ virtual bool check() const { return true; }
+ virtual void reset() { }
+};
+
+template <class T>
+class ValueProxy : public ProxyData
+{
+ private:
+ T *scalar;
+
+ public:
+ ValueProxy(T &val) : scalar(&val) {}
+ virtual Counter value() const { return *scalar; }
+ virtual Result result() const { return *scalar; }
+ virtual Result total() const { return *scalar; }
+};
+
+template <class T>
+class FunctorProxy : public ProxyData
+{
+ private:
+ T *functor;
+
+ public:
+ FunctorProxy(T &func) : functor(&func) {}
+ virtual Counter value() const { return (*functor)(); }
+ virtual Result result() const { return (*functor)(); }
+ virtual Result total() const { return (*functor)(); }
+};
+
+class ValueBase : public DataAccess
+{
+ private:
+ ProxyData *proxy;
+
+ public:
+ ValueBase() : proxy(NULL) { }
+ ~ValueBase() { if (proxy) delete proxy; }
+
+ template <class T>
+ void scalar(T &value)
+ {
+ proxy = new ValueProxy<T>(value);
+ setInit();
+ }
+
+ template <class T>
+ void functor(T &func)
+ {
+ proxy = new FunctorProxy<T>(func);
+ setInit();
+ }
+
+ Counter value() { return proxy->value(); }
+ Result result() const { return proxy->result(); }
+ Result total() const { return proxy->total(); };
+ size_t size() const { return proxy->size(); }
+
+ bool binned() const { return proxy->binned(); }
+ std::string str() const { return proxy->str(); }
+ bool zero() const { return proxy->zero(); }
+ bool check() const { return proxy != NULL; }
+ void reset() { }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Vector Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <class Storage, class Bin>
+class ScalarProxy;
+
+/**
+ * Implementation of a vector of stats. The type of stat is determined by the
+ * Storage class. @sa ScalarBase
+ */
+template <class Storage, class Bin>
+class VectorBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin for the given index.
+ * @param index The vector index to access.
+ * @return The storage object at the given index.
+ */
+ Storage *data(int index) { return bin.data(index, params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin
+ * for the given index.
+ * @param index The vector index to access.
+ * @return A const pointer to the storage object at the given index.
+ */
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ void value(VCounter &vec) const
+ {
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->value(params);
+ }
+
+ /**
+ * Copy the values to a local vector and return a reference to it.
+ * @return A reference to a vector of the stat values.
+ */
+ void result(VResult &vec) const
+ {
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->result(params);
+ }
+
+ /**
+ * @return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+
+ /**
+ * Return a total of all entries in this vector.
+ * @return The total of all vector entries.
+ */
+ Result total() const {
+ Result total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->result(params);
+ return total;
+ }
+
+ /**
+ * @return the number of elements in this vector.
+ */
+ size_t size() const { return bin.size(); }
+
+ bool zero() const
+ {
+ for (int i = 0; i < size(); ++i)
+ if (data(i)->zero())
+ return true;
+ return false;
+ }
+
+ bool check() const { return bin.initialized(); }
+ void reset() { bin.reset(); }
+
+ public:
+ VectorBase() {}
+
+ /** Friend this class with the associated scalar proxy. */
+ friend class ScalarProxy<Storage, Bin>;
+
+ /**
+ * Return a reference (ScalarProxy) to the stat at the given index.
+ * @param index The vector index to access.
+ * @return A reference of the stat.
+ */
+ ScalarProxy<Storage, Bin> operator[](int index);
+
+ void update(StatData *data) {}
+};
+
+const StatData * getStatData(const void *stat);
+
+/**
+ * A proxy class to access the stat at a given index in a VectorBase stat.
+ * Behaves like a ScalarBase.
+ */
+template <class Storage, class Bin>
+class ScalarProxy
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ private:
+ /** Pointer to the bin in the parent VectorBase. */
+ bin_t *bin;
+ /** Pointer to the params in the parent VectorBase. */
+ params_t *params;
+ /** The index to access in the parent VectorBase. */
+ int index;
+ /** Keep a pointer to the original stat so was can get data */
+ void *stat;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage from the bin for this stat.
+ */
+ Storage *data() { return bin->data(index, *params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(bin);
+ params_t *_params = const_cast<params_t *>(params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ /**
+ * Return the current value of this stat as its base type.
+ * @return The current value.
+ */
+ Counter value() const { return data()->value(*params); }
+
+ /**
+ * Return the current value of this statas a result type.
+ * @return The current value.
+ */
+ Result result() const { return data()->result(*params); }
+
+ public:
+ /**
+ * Create and initialize this proxy, do not register it with the database.
+ * @param b The bin to use.
+ * @param p The params to use.
+ * @param i The index to access.
+ */
+ ScalarProxy(bin_t &b, params_t &p, int i, void *s)
+ : bin(&b), params(&p), index(i), stat(s) {}
+ /**
+ * Create a copy of the provided ScalarProxy.
+ * @param sp The proxy to copy.
+ */
+ ScalarProxy(const ScalarProxy &sp)
+ : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {}
+ /**
+ * Set this proxy equal to the provided one.
+ * @param sp The proxy to copy.
+ * @return A reference to this proxy.
+ */
+ const ScalarProxy &operator=(const ScalarProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ index = sp.index;
+ stat = sp.stat;
+ return *this;
+ }
+
+ public:
+ // Common operators for stats
+ /**
+ * Increment the stat by 1. This calls the associated storage object inc
+ * function.
+ */
+ void operator++() { data()->inc(1, *params); }
+ /**
+ * Decrement the stat by 1. This calls the associated storage object dec
+ * function.
+ */
+ void operator--() { data()->dec(1, *params); }
+
+ /** Increment the stat by 1. */
+ void operator++(int) { ++*this; }
+ /** Decrement the stat by 1. */
+ void operator--(int) { --*this; }
+
+ /**
+ * Set the data value to the given value. This calls the associated storage
+ * object set function.
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { data()->set(v, *params); }
+
+ /**
+ * Increment the stat by the given value. This calls the associated
+ * storage object inc function.
+ * @param v The value to add.
+ */
+ template <typename U>
+ void operator+=(const U &v) { data()->inc(v, *params); }
+
+ /**
+ * Decrement the stat by the given value. This calls the associated
+ * storage object dec function.
+ * @param v The value to substract.
+ */
+ template <typename U>
+ void operator-=(const U &v) { data()->dec(v, *params); }
+
+ /**
+ * Return the number of elements, always 1 for a scalar.
+ * @return 1.
+ */
+ size_t size() const { return 1; }
+
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies aren't printed/binned
+ */
+ bool binned() const { return false; }
+
+ /**
+ * This stat has no state. Nothing to reset
+ */
+ void reset() { }
+
+ public:
+ const StatData *statData() const { return getStatData(stat); }
+ std::string str() const
+ {
+ return csprintf("%s[%d]", this->statData()->name, index);
+
+ }
+};
+
+template <class Storage, class Bin>
+inline ScalarProxy<Storage, Bin>
+VectorBase<Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return ScalarProxy<Storage, Bin>(bin, params, index, this);
+}
+
+template <class Storage, class Bin>
+class VectorProxy;
+
+template <class Storage, class Bin>
+class Vector2dBase : public DataAccess
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ size_t x;
+ size_t y;
+ bin_t bin;
+ params_t params;
+
+ protected:
+ Storage *data(int index) { return bin.data(index, params); }
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ Vector2dBase() {}
+
+ void update(Vector2dData *data)
+ {
+ int size = this->size();
+ data->cvec.resize(size);
+ for (int i = 0; i < size; ++i)
+ data->cvec[i] = this->data(i)->value(params);
+ }
+
+ std::string ysubname(int i) const { return (*this->y_subnames)[i]; }
+
+ friend class VectorProxy<Storage, Bin>;
+ VectorProxy<Storage, Bin> operator[](int index);
+
+ size_t size() const { return bin.size(); }
+ bool zero() const { return data(0)->value(params) == 0.0; }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ bool check() { return bin.initialized(); }
+};
+
+template <class Storage, class Bin>
+class VectorProxy
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int offset;
+ int len;
+ void *stat;
+
+ private:
+ mutable VResult *vec;
+
+ Storage *data(int index) {
+ assert(index < len);
+ return bin->data(offset + index, *params);
+ }
+
+ const Storage *data(int index) const {
+ bin_t *_bin = const_cast<bin_t *>(bin);
+ params_t *_params = const_cast<params_t *>(params);
+ return _bin->data(offset + index, *_params);
+ }
+
+ public:
+ const VResult &result() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new VResult(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->result(*params);
+
+ return *vec;
+ }
+
+ Result total() const {
+ Result total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->result(*params);
+ return total;
+ }
+
+ public:
+ VectorProxy(bin_t &b, params_t &p, int o, int l, void *s)
+ : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL)
+ {
+ }
+
+ VectorProxy(const VectorProxy &sp)
+ : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len),
+ stat(sp.stat), vec(NULL)
+ {
+ }
+
+ ~VectorProxy()
+ {
+ if (vec)
+ delete vec;
+ }
+
+ const VectorProxy &operator=(const VectorProxy &sp)
+ {
+ bin = sp.bin;
+ params = sp.params;
+ offset = sp.offset;
+ len = sp.len;
+ stat = sp.stat;
+ if (vec)
+ delete vec;
+ vec = NULL;
+ return *this;
+ }
+
+ ScalarProxy<Storage, Bin> operator[](int index)
+ {
+ assert (index >= 0 && index < size());
+ return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat);
+ }
+
+ size_t size() const { return len; }
+
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies aren't printed/binned
+ */
+ bool binned() const { return false; }
+
+ /**
+ * This stat has no state. Nothing to reset.
+ */
+ void reset() { }
+};
+
+template <class Storage, class Bin>
+inline VectorProxy<Storage, Bin>
+Vector2dBase<Storage, Bin>::operator[](int index)
+{
+ int offset = index * y;
+ assert (index >= 0 && offset < size());
+ return VectorProxy<Storage, Bin>(bin, params, offset, y, this);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Non formula statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Templatized storage and interface for a distrbution stat.
+ */
+struct DistStor
+{
+ public:
+ /** The parameters for a distribution stat. */
+ struct Params
+ {
+ /** The minimum value to track. */
+ Counter min;
+ /** The maximum value to track. */
+ Counter max;
+ /** The number of entries in each bucket. */
+ Counter bucket_size;
+ /** The number of buckets. Equal to (max-min)/bucket_size. */
+ int size;
+ };
+ enum { fancy = false };
+
+ private:
+ /** The smallest value sampled. */
+ Counter min_val;
+ /** The largest value sampled. */
+ Counter max_val;
+ /** The number of values sampled less than min. */
+ Counter underflow;
+ /** The number of values sampled more than max. */
+ Counter overflow;
+ /** The current sum. */
+ Counter sum;
+ /** The sum of squares. */
+ Counter squares;
+ /** The number of samples. */
+ Counter samples;
+ /** Counter for each bucket. */
+ VCounter cvec;
+
+ public:
+ /**
+ * Construct this storage with the supplied params.
+ * @param params The parameters.
+ */
+ DistStor(const Params &params)
+ : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()),
+ overflow(Counter()), sum(Counter()), squares(Counter()),
+ samples(Counter()), cvec(params.size)
+ {
+ reset();
+ }
+
+ /**
+ * Add a value to the distribution for the given number of times.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param params The paramters of the distribution.
+ */
+ void sample(Counter val, int number, const Params &params)
+ {
+ if (val < params.min)
+ underflow += number;
+ else if (val > params.max)
+ overflow += number;
+ else {
+ int index = (int)floor((val - params.min) / params.bucket_size);
+ assert(index < size(params));
+ cvec[index] += number;
+ }
+
+ if (val < min_val)
+ min_val = val;
+
+ if (val > max_val)
+ max_val = val;
+
+ Counter sample = val * number;
+ sum += sample;
+ squares += sample * sample;
+ samples += number;
+ }
+
+ /**
+ * Return the number of buckets in this distribution.
+ * @return the number of buckets.
+ * @todo Is it faster to return the size from the parameters?
+ */
+ size_t size(const Params &) const { return cvec.size(); }
+
+ /**
+ * Returns true if any calls to sample have been made.
+ * @param params The paramters of the distribution.
+ * @return True if any values have been sampled.
+ */
+ bool zero(const Params &params) const
+ {
+ return samples == Counter();
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->min = params.min;
+ data->max = params.max;
+ data->bucket_size = params.bucket_size;
+ data->size = params.size;
+
+ data->min_val = (min_val == INT_MAX) ? 0 : min_val;
+ data->max_val = (max_val == INT_MIN) ? 0 : max_val;
+ data->underflow = underflow;
+ data->overflow = overflow;
+ data->cvec.resize(params.size);
+ for (int i = 0; i < params.size; ++i)
+ data->cvec[i] = cvec[i];
+
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = samples;
+ }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ min_val = INT_MAX;
+ max_val = INT_MIN;
+ underflow = 0;
+ overflow = 0;
+
+ int size = cvec.size();
+ for (int i = 0; i < size; ++i)
+ cvec[i] = Counter();
+
+ sum = Counter();
+ squares = Counter();
+ samples = Counter();
+ }
+};
+
+/**
+ * Templatized storage and interface for a distribution that calculates mean
+ * and variance.
+ */
+struct FancyStor
+{
+ public:
+ /**
+ * No paramters for this storage.
+ */
+ struct Params {};
+ enum { fancy = true };
+
+ private:
+ /** The current sum. */
+ Counter sum;
+ /** The sum of squares. */
+ Counter squares;
+ /** The number of samples. */
+ Counter samples;
+
+ public:
+ /**
+ * Create and initialize this storage.
+ */
+ FancyStor(const Params &)
+ : sum(Counter()), squares(Counter()), samples(Counter())
+ { }
+
+ /**
+ * Add a value the given number of times to this running average.
+ * Update the running sum and sum of squares, increment the number of
+ * values seen by the given number.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param p The parameters of this stat.
+ */
+ void sample(Counter val, int number, const Params &p)
+ {
+ Counter value = val * number;
+ sum += value;
+ squares += value * value;
+ samples += number;
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = samples;
+ }
+
+ /**
+ * Return the number of entries in this stat, 1
+ * @return 1.
+ */
+ size_t size(const Params &) const { return 1; }
+
+ /**
+ * Return true if no samples have been added.
+ * @return True if no samples have been added.
+ */
+ bool zero(const Params &) const { return samples == Counter(); }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ sum = Counter();
+ squares = Counter();
+ samples = Counter();
+ }
+};
+
+/**
+ * Templatized storage for distribution that calculates per cycle mean and
+ * variance.
+ */
+struct AvgFancy
+{
+ public:
+ /** No parameters for this storage. */
+ struct Params {};
+ enum { fancy = true };
+
+ private:
+ /** Current total. */
+ Counter sum;
+ /** Current sum of squares. */
+ Counter squares;
+
+ public:
+ /**
+ * Create and initialize this storage.
+ */
+ AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {}
+
+ /**
+ * Add a value to the distribution for the given number of times.
+ * Update the running sum and sum of squares.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param p The paramters of the distribution.
+ */
+ void sample(Counter val, int number, const Params &p)
+ {
+ Counter value = val * number;
+ sum += value;
+ squares += value * value;
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = curTick;
+ }
+
+ /**
+ * Return the number of entries, in this case 1.
+ * @return 1.
+ */
+ size_t size(const Params &params) const { return 1; }
+ /**
+ * Return true if no samples have been added.
+ * @return True if the sum is zero.
+ */
+ bool zero(const Params &params) const { return sum == Counter(); }
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ sum = Counter();
+ squares = Counter();
+ }
+};
+
+/**
+ * Implementation of a distribution stat. The type of distribution is
+ * determined by the Storage template. @sa ScalarBase
+ */
+template <class Storage, class Bin>
+class DistBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template Bin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage object for this stat.
+ */
+ Storage *data() { return bin.data(params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage object for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(*_params);
+ }
+
+ public:
+ DistBase() { }
+
+ /**
+ * Add a value to the distribtion n times. Calls sample on the storage
+ * class.
+ * @param v The value to add.
+ * @param n The number of times to add it, defaults to 1.
+ */
+ template <typename U>
+ void sample(const U &v, int n = 1) { data()->sample(v, n, params); }
+
+ /**
+ * Return the number of entries in this stat.
+ * @return The number of entries.
+ */
+ size_t size() const { return data()->size(params); }
+ /**
+ * Return true if no samples have been added.
+ * @return True if there haven't been any samples.
+ */
+ bool zero() const { return data()->zero(params); }
+
+ void update(DistData *base)
+ {
+ base->data.fancy = Storage::fancy;
+ data()->update(&(base->data), params);
+ }
+ /**
+ * @return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ bin.reset();
+ }
+
+ bool check() { return bin.initialized(); }
+};
+
+template <class Storage, class Bin>
+class DistProxy;
+
+template <class Storage, class Bin>
+class VectorDistBase : public DataAccess
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ Storage *data(int index) { return bin.data(index, params); }
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ VectorDistBase() {}
+
+ friend class DistProxy<Storage, Bin>;
+ DistProxy<Storage, Bin> operator[](int index);
+ const DistProxy<Storage, Bin> operator[](int index) const;
+
+ size_t size() const { return bin.size(); }
+ bool zero() const { return false; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ bool check() { return bin.initialized(); }
+ void update(VectorDistData *base)
+ {
+ int size = this->size();
+ base->data.resize(size);
+ for (int i = 0; i < size; ++i) {
+ base->data[i].fancy = Storage::fancy;
+ data(i)->update(&(base->data[i]), params);
+ }
+ }
+};
+
+template <class Storage, class Bin>
+class DistProxy
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template Bin<Storage> bin_t;
+ typedef VectorDistBase<Storage, Bin> base_t;
+
+ private:
+ union {
+ base_t *stat;
+ const base_t *cstat;
+ };
+ int index;
+
+ protected:
+ Storage *data() { return stat->data(index); }
+ const Storage *data() const { return cstat->data(index); }
+
+ public:
+ DistProxy(const VectorDistBase<Storage, Bin> &s, int i)
+ : cstat(&s), index(i) {}
+ DistProxy(const DistProxy &sp)
+ : cstat(sp.cstat), index(sp.index) {}
+ const DistProxy &operator=(const DistProxy &sp) {
+ cstat = sp.cstat; index = sp.index; return *this;
+ }
+
+ public:
+ template <typename U>
+ void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); }
+
+ size_t size() const { return 1; }
+ bool zero() const { return data()->zero(cstat->params); }
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies are not binned/printed.
+ */
+ bool binned() const { return false; }
+ /**
+ * Proxy has no state. Nothing to reset.
+ */
+ void reset() { }
+};
+
+template <class Storage, class Bin>
+inline DistProxy<Storage, Bin>
+VectorDistBase<Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return DistProxy<Storage, Bin>(*this, index);
+}
+
+template <class Storage, class Bin>
+inline const DistProxy<Storage, Bin>
+VectorDistBase<Storage, Bin>::operator[](int index) const
+{
+ assert (index >= 0 && index < size());
+ return DistProxy<Storage, Bin>(*this, index);
+}
+
+#if 0
+template <class Storage, class Bin>
+Result
+VectorDistBase<Storage, Bin>::total(int index) const
+{
+ int total = 0;
+ for (int i=0; i < x_size(); ++i) {
+ total += data(i)->result(*params);
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+//
+// Formula Details
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Base class for formula statistic node. These nodes are used to build a tree
+ * that represents the formula.
+ */
+class Node : public RefCounted
+{
+ public:
+ /**
+ * Return the number of nodes in the subtree starting at this node.
+ * @return the number of nodes in this subtree.
+ */
+ virtual size_t size() const = 0;
+ /**
+ * Return the result vector of this subtree.
+ * @return The result vector of this subtree.
+ */
+ virtual const VResult &result() const = 0;
+ /**
+ * Return the total of the result vector.
+ * @return The total of the result vector.
+ */
+ virtual Result total() const = 0;
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const = 0;
+
+ /**
+ *
+ */
+ virtual std::string str() const = 0;
+};
+
+/** Reference counting pointer to a function Node. */
+typedef RefCountingPtr<Node> NodePtr;
+
+class ScalarStatNode : public Node
+{
+ private:
+ const ScalarData *data;
+ mutable VResult vresult;
+
+ public:
+ ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {}
+ virtual const VResult &result() const
+ {
+ vresult[0] = data->result();
+ return vresult;
+ }
+ virtual Result total() const { return data->result(); };
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return data->binned(); }
+
+ /**
+ *
+ */
+ virtual std::string str() const { return data->name; }
+};
+
+template <class Storage, class Bin>
+class ScalarProxyNode : public Node
+{
+ private:
+ const ScalarProxy<Storage, Bin> proxy;
+ mutable VResult vresult;
+
+ public:
+ ScalarProxyNode(const ScalarProxy<Storage, Bin> &p)
+ : proxy(p), vresult(1) { }
+ virtual const VResult &result() const
+ {
+ vresult[0] = proxy.result();
+ return vresult;
+ }
+ virtual Result total() const { return proxy.result(); };
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return proxy.binned(); }
+
+ /**
+ *
+ */
+ virtual std::string str() const { return proxy.str(); }
+};
+
+class VectorStatNode : public Node
+{
+ private:
+ const VectorData *data;
+
+ public:
+ VectorStatNode(const VectorData *d) : data(d) { }
+ virtual const VResult &result() const { return data->result(); }
+ virtual Result total() const { return data->total(); };
+
+ virtual size_t size() const { return data->size(); }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return data->binned(); }
+
+ virtual std::string str() const { return data->name; }
+};
+
+template <class T>
+class ConstNode : public Node
+{
+ private:
+ VResult vresult;
+
+ public:
+ ConstNode(T s) : vresult(1, (Result)s) {}
+ const VResult &result() const { return vresult; }
+ virtual Result total() const { return vresult[0]; };
+ virtual size_t size() const { return 1; }
+
+ /**
+ * Return true if stat is binned.
+ *@return False since constants aren't binned.
+ */
+ virtual bool binned() const { return false; }
+
+ virtual std::string str() const { return to_string(vresult[0]); }
+};
+
+template <class Op>
+struct OpString;
+
+template<>
+struct OpString<std::plus<Result> >
+{
+ static std::string str() { return "+"; }
+};
+
+template<>
+struct OpString<std::minus<Result> >
+{
+ static std::string str() { return "-"; }
+};
+
+template<>
+struct OpString<std::multiplies<Result> >
+{
+ static std::string str() { return "*"; }
+};
+
+template<>
+struct OpString<std::divides<Result> >
+{
+ static std::string str() { return "/"; }
+};
+
+template<>
+struct OpString<std::modulus<Result> >
+{
+ static std::string str() { return "%"; }
+};
+
+template<>
+struct OpString<std::negate<Result> >
+{
+ static std::string str() { return "-"; }
+};
+
+template <class Op>
+class UnaryNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable VResult vresult;
+
+ public:
+ UnaryNode(NodePtr &p) : l(p) {}
+
+ const VResult &result() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+
+ assert(size > 0);
+
+ vresult.resize(size);
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i]);
+
+ return vresult;
+ }
+
+ Result total() const {
+ Op op;
+ return op(l->total());
+ }
+
+ virtual size_t size() const { return l->size(); }
+ /**
+ * Return true if child of node is binned.
+ *@return True if child of node is binned.
+ */
+ virtual bool binned() const { return l->binned(); }
+
+ virtual std::string str() const
+ {
+ return OpString<Op>::str() + l->str();
+ }
+};
+
+template <class Op>
+class BinaryNode : public Node
+{
+ public:
+ NodePtr l;
+ NodePtr r;
+ mutable VResult vresult;
+
+ public:
+ BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
+
+ const VResult &result() const
+ {
+ Op op;
+ const VResult &lvec = l->result();
+ const VResult &rvec = r->result();
+
+ assert(lvec.size() > 0 && rvec.size() > 0);
+
+ if (lvec.size() == 1 && rvec.size() == 1) {
+ vresult.resize(1);
+ vresult[0] = op(lvec[0], rvec[0]);
+ } else if (lvec.size() == 1) {
+ int size = rvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[0], rvec[i]);
+ } else if (rvec.size() == 1) {
+ int size = lvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i], rvec[0]);
+ } else if (rvec.size() == lvec.size()) {
+ int size = rvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i], rvec[i]);
+ }
+
+ return vresult;
+ }
+
+ Result total() const {
+ Op op;
+ return op(l->total(), r->total());
+ }
+
+ virtual size_t size() const {
+ int ls = l->size();
+ int rs = r->size();
+ if (ls == 1)
+ return rs;
+ else if (rs == 1)
+ return ls;
+ else {
+ assert(ls == rs && "Node vector sizes are not equal");
+ return ls;
+ }
+ }
+ /**
+ * Return true if any children of node are binned
+ *@return True if either child of node is binned.
+ */
+ virtual bool binned() const { return (l->binned() || r->binned()); }
+
+ virtual std::string str() const
+ {
+ return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
+ }
+};
+
+template <class Op>
+class SumNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable VResult vresult;
+
+ public:
+ SumNode(NodePtr &p) : l(p), vresult(1) {}
+
+ const VResult &result() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+ assert(size > 0);
+
+ vresult[0] = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult[0] = op(vresult[0], lvec[i]);
+
+ return vresult;
+ }
+
+ Result total() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+ assert(size > 0);
+
+ Result vresult = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult = op(vresult, lvec[i]);
+
+ return vresult;
+ }
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if child of node is binned.
+ *@return True if child of node is binned.
+ */
+ virtual bool binned() const { return l->binned(); }
+
+ virtual std::string str() const
+ {
+ return csprintf("total(%s)", l->str());
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Visible Statistics Types
+//
+//////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup VisibleStats "Statistic Types"
+ * These are the statistics that are used in the simulator. By default these
+ * store counters and don't use binning, but are templatized to accept any type
+ * and any Bin class.
+ * @{
+ */
+
+/**
+ * This is an easy way to assign all your stats to be binned or not
+ * binned. If the typedef is NoBin, nothing is binned. If it is
+ * MainBin, then all stats are binned under that Bin.
+ */
+#if STATS_BINNING
+typedef MainBin DefaultBin;
+#else
+typedef NoBin DefaultBin;
+#endif
+
+/**
+ * This is a simple scalar statistic, like a counter.
+ * @sa Stat, ScalarBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Scalar
+ : public Wrap<Scalar<Bin>,
+ ScalarBase<StatStor, Bin>,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<StatStor, Bin> Base;
+
+ Scalar()
+ {
+ this->setInit();
+ }
+
+ /**
+ * Sets the stat equal to the given value. Calls the base implementation
+ * of operator=
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { Base::operator=(v); }
+};
+
+class Value
+ : public Wrap<Value,
+ ValueBase,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ValueBase Base;
+
+ template <class T>
+ Value &scalar(T &value)
+ {
+ Base::scalar(value);
+ return *this;
+ }
+
+ template <class T>
+ Value &functor(T &func)
+ {
+ Base::functor(func);
+ return *this;
+ }
+};
+
+/**
+ * A stat that calculates the per cycle average of a value.
+ * @sa Stat, ScalarBase, AvgStor
+ */
+template <class Bin = DefaultBin>
+class Average
+ : public Wrap<Average<Bin>,
+ ScalarBase<AvgStor, Bin>,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<AvgStor, Bin> Base;
+
+ Average()
+ {
+ this->setInit();
+ }
+
+ /**
+ * Sets the stat equal to the given value. Calls the base implementation
+ * of operator=
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { Base::operator=(v); }
+};
+
+/**
+ * A vector of scalar stats.
+ * @sa Stat, VectorBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Vector
+ : public WrapVec<Vector<Bin>,
+ VectorBase<StatStor, Bin>,
+ VectorStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<StatStor, Bin> Base;
+
+ /**
+ * Set this vector to have the given size.
+ * @param size The new size.
+ * @return A reference to this stat.
+ */
+ Vector &init(size_t size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A vector of Average stats.
+ * @sa Stat, VectorBase, AvgStor
+ */
+template <class Bin = DefaultBin>
+class AverageVector
+ : public WrapVec<AverageVector<Bin>,
+ VectorBase<AvgStor, Bin>,
+ VectorStatData>
+{
+ public:
+ /**
+ * Set this vector to have the given size.
+ * @param size The new size.
+ * @return A reference to this stat.
+ */
+ AverageVector &init(size_t size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A 2-Dimensional vecto of scalar stats.
+ * @sa Stat, Vector2dBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Vector2d
+ : public WrapVec2d<Vector2d<Bin>,
+ Vector2dBase<StatStor, Bin>,
+ Vector2dStatData>
+{
+ public:
+ Vector2d &init(size_t _x, size_t _y) {
+ this->statData()->x = this->x = _x;
+ this->statData()->y = this->y = _y;
+ this->bin.init(this->x * this->y, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A simple distribution stat.
+ * @sa Stat, DistBase, DistStor
+ */
+template <class Bin = DefaultBin>
+class Distribution
+ : public Wrap<Distribution<Bin>,
+ DistBase<DistStor, Bin>,
+ DistStatData>
+{
+ public:
+ /** Base implementation. */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The Parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Set the parameters of this distribution. @sa DistStor::Params
+ * @param min The minimum value of the distribution.
+ * @param max The maximum value of the distribution.
+ * @param bkt The number of values in each bucket.
+ * @return A reference to this distribution.
+ */
+ Distribution &init(Counter min, Counter max, Counter bkt) {
+ this->params.min = min;
+ this->params.max = max;
+ this->params.bucket_size = bkt;
+ this->params.size = (int)rint((max - min) / bkt + 1.0);
+ this->bin.init(this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * Calculates the mean and variance of all the samples.
+ * @sa Stat, DistBase, FancyStor
+ */
+template <class Bin = DefaultBin>
+class StandardDeviation
+ : public Wrap<StandardDeviation<Bin>,
+ DistBase<FancyStor, Bin>,
+ DistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Construct and initialize this distribution.
+ */
+ StandardDeviation() {
+ this->bin.init(this->params);
+ this->setInit();
+ }
+};
+
+/**
+ * Calculates the per cycle mean and variance of the samples.
+ * @sa Stat, DistBase, AvgFancy
+ */
+template <class Bin = DefaultBin>
+class AverageDeviation
+ : public Wrap<AverageDeviation<Bin>,
+ DistBase<AvgFancy, Bin>,
+ DistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Construct and initialize this distribution.
+ */
+ AverageDeviation()
+ {
+ this->bin.init(this->params);
+ this->setInit();
+ }
+};
+
+/**
+ * A vector of distributions.
+ * @sa Stat, VectorDistBase, DistStor
+ */
+template <class Bin = DefaultBin>
+class VectorDistribution
+ : public WrapVec<VectorDistribution<Bin>,
+ VectorDistBase<DistStor, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage and parameters for this distribution.
+ * @param size The size of the vector (the number of distributions).
+ * @param min The minimum value of the distribution.
+ * @param max The maximum value of the distribution.
+ * @param bkt The number of values in each bucket.
+ * @return A reference to this distribution.
+ */
+ VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) {
+ this->params.min = min;
+ this->params.max = max;
+ this->params.bucket_size = bkt;
+ this->params.size = (int)rint((max - min) / bkt + 1.0);
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * This is a vector of StandardDeviation stats.
+ * @sa Stat, VectorDistBase, FancyStor
+ */
+template <class Bin = DefaultBin>
+class VectorStandardDeviation
+ : public WrapVec<VectorStandardDeviation<Bin>,
+ VectorDistBase<FancyStor, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<FancyStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage for this distribution.
+ * @param size The size of the vector.
+ * @return A reference to this distribution.
+ */
+ VectorStandardDeviation &init(int size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * This is a vector of AverageDeviation stats.
+ * @sa Stat, VectorDistBase, AvgFancy
+ */
+template <class Bin = DefaultBin>
+class VectorAverageDeviation
+ : public WrapVec<VectorAverageDeviation<Bin>,
+ VectorDistBase<AvgFancy, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<AvgFancy, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage for this distribution.
+ * @param size The size of the vector.
+ * @return A reference to this distribution.
+ */
+ VectorAverageDeviation &init(int size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A formula for statistics that is calculated when printed. A formula is
+ * stored as a tree of Nodes that represent the equation to calculate.
+ * @sa Stat, ScalarStat, VectorStat, Node, Temp
+ */
+class FormulaBase : public DataAccess
+{
+ protected:
+ /** The root of the tree which represents the Formula */
+ NodePtr root;
+ friend class Temp;
+
+ public:
+ /**
+ * Return the result of the Fomula in a vector. If there were no Vector
+ * components to the Formula, then the vector is size 1. If there were,
+ * like x/y with x being a vector of size 3, then the result returned will
+ * be x[0]/y, x[1]/y, x[2]/y, respectively.
+ * @return The result vector.
+ */
+ void result(VResult &vec) const;
+
+ /**
+ * Return the total Formula result. If there is a Vector
+ * component to this Formula, then this is the result of the
+ * Formula if the formula is applied after summing all the
+ * components of the Vector. For example, if Formula is x/y where
+ * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If
+ * there is no Vector component, total() returns the same value as
+ * the first entry in the VResult val() returns.
+ * @return The total of the result vector.
+ */
+ Result total() const;
+
+ /**
+ * Return the number of elements in the tree.
+ */
+ size_t size() const;
+
+ /**
+ * Return true if Formula is binned. i.e. any of its children
+ * nodes are binned
+ * @return True if Formula is binned.
+ */
+ bool binned() const;
+
+ bool check() const { return true; }
+
+ /**
+ * Formulas don't need to be reset
+ */
+ void reset();
+
+ /**
+ *
+ */
+ bool zero() const;
+
+ /**
+ *
+ */
+ void update(StatData *);
+
+ std::string str() const;
+};
+
+class FormulaData : public VectorData
+{
+ public:
+ virtual std::string str() const = 0;
+ virtual bool check() const { return true; }
+};
+
+template <class Stat>
+class FormulaStatData : public FormulaData
+{
+ protected:
+ Stat &s;
+ mutable VResult vec;
+ mutable VCounter cvec;
+
+ public:
+ FormulaStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void reset() { s.reset(); }
+
+ virtual size_t size() const { return s.size(); }
+ virtual const VResult &result() const
+ {
+ s.result(vec);
+ return vec;
+ }
+ virtual Result total() const { return s.total(); }
+ virtual VCounter &value() const { return cvec; }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+ virtual std::string str() const { return s.str(); }
+};
+
+class Temp;
+class Formula
+ : public WrapVec<Formula,
+ FormulaBase,
+ FormulaStatData>
+{
+ public:
+ /**
+ * Create and initialize thie formula, and register it with the database.
+ */
+ Formula();
+
+ /**
+ * Create a formula with the given root node, register it with the
+ * database.
+ * @param r The root of the expression tree.
+ */
+ Formula(Temp r);
+
+ /**
+ * Set an unitialized Formula to the given root.
+ * @param r The root of the expression tree.
+ * @return a reference to this formula.
+ */
+ const Formula &operator=(Temp r);
+
+ /**
+ * Add the given tree to the existing one.
+ * @param r The root of the expression tree.
+ * @return a reference to this formula.
+ */
+ const Formula &operator+=(Temp r);
+};
+
+class FormulaNode : public Node
+{
+ private:
+ const Formula &formula;
+ mutable VResult vec;
+
+ public:
+ FormulaNode(const Formula &f) : formula(f) {}
+
+ virtual size_t size() const { return formula.size(); }
+ virtual const VResult &result() const { formula.result(vec); return vec; }
+ virtual Result total() const { return formula.total(); }
+ virtual bool binned() const { return formula.binned(); }
+
+ virtual std::string str() const { return formula.str(); }
+};
+
+/**
+ * Helper class to construct formula node trees.
+ */
+class Temp
+{
+ protected:
+ /**
+ * Pointer to a Node object.
+ */
+ NodePtr node;
+
+ public:
+ /**
+ * Copy the given pointer to this class.
+ * @param n A pointer to a Node object to copy.
+ */
+ Temp(NodePtr n) : node(n) { }
+
+ /**
+ * Return the node pointer.
+ * @return the node pointer.
+ */
+ operator NodePtr&() { return node;}
+
+ public:
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Scalar<Bin> &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ Temp(const Value &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Average<Bin> &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new VectorStatNode.
+ * @param s The VectorStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Vector<Bin> &s)
+ : node(new VectorStatNode(s.statData())) { }
+
+ /**
+ *
+ */
+ Temp(const Formula &f)
+ : node(new FormulaNode(f)) { }
+
+ /**
+ * Create a new ScalarProxyNode.
+ * @param p The ScalarProxy to place in a node.
+ */
+ template <class Storage, class Bin>
+ Temp(const ScalarProxy<Storage, Bin> &p)
+ : node(new ScalarProxyNode<Storage, Bin>(p)) { }
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed char value)
+ : node(new ConstNode<signed char>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned char value)
+ : node(new ConstNode<unsigned char>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed short value)
+ : node(new ConstNode<signed short>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned short value)
+ : node(new ConstNode<unsigned short>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed int value)
+ : node(new ConstNode<signed int>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned int value)
+ : node(new ConstNode<unsigned int>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed long value)
+ : node(new ConstNode<signed long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned long value)
+ : node(new ConstNode<unsigned long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed long long value)
+ : node(new ConstNode<signed long long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned long long value)
+ : node(new ConstNode<unsigned long long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(float value)
+ : node(new ConstNode<float>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(double value)
+ : node(new ConstNode<double>(value)) {}
+};
+
+
+/**
+ * @}
+ */
+
+void check();
+void reset();
+void registerResetCallback(Callback *cb);
+
+inline Temp
+operator+(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::plus<Result> >(l, r));
+}
+
+inline Temp
+operator-(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::minus<Result> >(l, r));
+}
+
+inline Temp
+operator*(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r));
+}
+
+inline Temp
+operator/(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::divides<Result> >(l, r));
+}
+
+inline Temp
+operator-(Temp l)
+{
+ return NodePtr(new UnaryNode<std::negate<Result> >(l));
+}
+
+template <typename T>
+inline Temp
+constant(T val)
+{
+ return NodePtr(new ConstNode<T>(val));
+}
+
+inline Temp
+sum(Temp val)
+{
+ return NodePtr(new SumNode<std::plus<Result> >(val));
+}
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATISTICS_HH__
diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc
new file mode 100644
index 000000000..3191aec13
--- /dev/null
+++ b/src/base/stats/events.cc
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <vector>
+
+#include "base/stats/events.hh"
+
+#if USE_MYSQL
+#include "base/cprintf.hh"
+#include "base/misc.hh"
+#include "base/mysql.hh"
+#include "base/stats/mysql.hh"
+#include "base/stats/mysql_run.hh"
+#include "base/str.hh"
+#endif
+
+#include "base/match.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+namespace Stats {
+
+Tick EventStart = ULL(0x7fffffffffffffff);
+
+ObjectMatch event_ignore;
+
+#if USE_MYSQL
+class InsertEvent
+{
+ private:
+ char *query;
+ int size;
+ bool first;
+ static const int maxsize = 1024*1024;
+
+ typedef map<string, uint32_t> event_map_t;
+ event_map_t events;
+
+ MySQL::Connection &mysql;
+ uint16_t run;
+
+ public:
+ InsertEvent()
+ : mysql(MySqlDB.conn()), run(MySqlDB.run())
+ {
+ query = new char[maxsize + 1];
+ size = 0;
+ first = true;
+ flush();
+ }
+ ~InsertEvent()
+ {
+ flush();
+ }
+
+ void flush();
+ void insert(const string &stat);
+};
+
+void
+InsertEvent::insert(const string &stat)
+{
+ assert(mysql.connected());
+
+ event_map_t::iterator i = events.find(stat);
+ uint32_t event;
+ if (i == events.end()) {
+ mysql.query(
+ csprintf("SELECT en_id "
+ "from event_names "
+ "where en_name=\"%s\"",
+ stat));
+
+ MySQL::Result result = mysql.store_result();
+ if (!result)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ assert(result.num_fields() == 1);
+ MySQL::Row row = result.fetch_row();
+ if (row) {
+ if (!to_number(row[0], event))
+ panic("invalid event id: %s\n", row[0]);
+ } else {
+ mysql.query(
+ csprintf("INSERT INTO "
+ "event_names(en_name)"
+ "values(\"%s\")",
+ stat));
+
+ if (mysql.error)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ event = mysql.insert_id();
+ }
+ } else {
+ event = (*i).second;
+ }
+
+ if (size + 1024 > maxsize)
+ flush();
+
+ if (!first) {
+ query[size++] = ',';
+ query[size] = '\0';
+ }
+
+ first = false;
+
+ size += sprintf(query + size, "(%u,%u,%llu)",
+ event, run, (unsigned long long)curTick);
+}
+
+void
+InsertEvent::flush()
+{
+ static const char query_header[] = "INSERT INTO "
+ "events(ev_event, ev_run, ev_tick)"
+ "values";
+
+ if (size) {
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ mysql.query(query);
+ }
+
+ query[0] = '\0';
+ size = sizeof(query_header);
+ first = true;
+ memcpy(query, query_header, size);
+}
+
+void
+__event(const string &stat)
+{
+ static InsertEvent event;
+ event.insert(stat);
+}
+
+#endif
+
+/* namespace Stats */ }
diff --git a/src/base/stats/events.hh b/src/base/stats/events.hh
new file mode 100644
index 000000000..2a23240b4
--- /dev/null
+++ b/src/base/stats/events.hh
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_EVENTS_HH__
+#define __BASE_STATS_EVENTS_HH__
+
+#include <string>
+
+#include "base/trace.hh"
+#include "config/use_mysql.hh"
+
+namespace Stats {
+
+extern Tick EventStart;
+
+#if USE_MYSQL
+void __event(const std::string &stat);
+bool MySqlConnected();
+#endif
+
+bool ignoreEvent(const std::string &name);
+
+inline void
+recordEvent(const std::string &stat)
+{
+ if (EventStart > curTick)
+ return;
+
+ DPRINTF(StatEvents, "Statistics Event: %s\n", stat);
+
+#if USE_MYSQL
+ if (!MySqlConnected())
+ return;
+
+ __event(stat);
+#endif
+}
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_EVENTS_HH__
diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh
new file mode 100644
index 000000000..00db95bc1
--- /dev/null
+++ b/src/base/stats/flags.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_FLAGS_HH__
+#define __BASE_STATS_FLAGS_HH__
+namespace Stats {
+
+/**
+ * Define the storage for format flags.
+ * @todo Can probably shrink this.
+ */
+typedef u_int32_t StatFlags;
+
+/** Nothing extra to print. */
+const StatFlags none = 0x00000000;
+/** This Stat is Initialized */
+const StatFlags init = 0x00000001;
+/** Print this stat. */
+const StatFlags print = 0x00000002;
+/** Print the total. */
+const StatFlags total = 0x00000010;
+/** Print the percent of the total that this entry represents. */
+const StatFlags pdf = 0x00000020;
+/** Print the cumulative percentage of total upto this entry. */
+const StatFlags cdf = 0x00000040;
+/** Print the distribution. */
+const StatFlags dist = 0x00000080;
+/** Don't print if this is zero. */
+const StatFlags nozero = 0x00000100;
+/** Don't print if this is NAN */
+const StatFlags nonan = 0x00000200;
+/** Used for SS compatability. */
+const StatFlags __substat = 0x80000000;
+
+/** Mask of flags that can't be set directly */
+const StatFlags __reserved = init | print | __substat;
+
+enum DisplayMode
+{
+ mode_m5,
+ mode_simplescalar
+};
+
+extern DisplayMode DefaultMode;
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_FLAGS_HH__
diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc
new file mode 100644
index 000000000..6d12b4fc1
--- /dev/null
+++ b/src/base/stats/mysql.cc
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cassert>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/mysql.hh"
+#include "base/statistics.hh"
+#include "base/stats/flags.hh"
+#include "base/stats/mysql.hh"
+#include "base/stats/mysql_run.hh"
+#include "base/stats/statdb.hh"
+#include "base/stats/types.hh"
+#include "base/str.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+namespace Stats {
+
+MySqlRun MySqlDB;
+
+bool
+MySqlConnected()
+{
+ return MySqlDB.connected();
+}
+
+void
+MySqlRun::connect(const string &host, const string &user, const string &passwd,
+ const string &db, const string &name, const string &sample,
+ const string &project)
+{
+ if (connected())
+ panic("can only get one database connection at this time!");
+
+ mysql.connect(host, user, passwd, db);
+ if (mysql.error)
+ panic("could not connect to database server\n%s\n", mysql.error);
+
+ if (mysql.autocommit(false))
+ panic("could not set autocommit\n%s\n", mysql.error);
+
+ remove(name);
+ //cleanup();
+ setup(name, sample, user, project);
+}
+
+void
+MySqlRun::setup(const string &name, const string &sample, const string &user,
+ const string &project)
+{
+ assert(mysql.connected());
+
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO "
+ "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)"
+ "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW(),"
+ "DATE_ADD(CURDATE(), INTERVAL 31 DAY))",
+ name, sample, user, project);
+
+ mysql.query(insert);
+ if (mysql.error)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ run_id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySqlRun::remove(const string &name)
+{
+ assert(mysql.connected());
+ stringstream sql;
+ ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name);
+ mysql.query(sql);
+ if (mysql.error)
+ panic("could not delete run\n%s\n", mysql.error);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySqlRun::cleanup()
+{
+ assert(mysql.connected());
+
+ mysql.query("DELETE data "
+ "FROM data "
+ "LEFT JOIN runs ON dt_run=rn_id "
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE formula_ref "
+ "FROM formula_ref "
+ "LEFT JOIN runs ON fr_run=rn_id "
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE formulas "
+ "FROM formulas "
+ "LEFT JOIN formula_ref ON fm_stat=fr_stat "
+ "WHERE fr_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE stats "
+ "FROM stats "
+ "LEFT JOIN data ON st_id=dt_stat "
+ "WHERE dt_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE subdata "
+ "FROM subdata "
+ "LEFT JOIN data ON sd_stat=dt_stat "
+ "WHERE dt_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE bins "
+ "FROM bins "
+ "LEFT JOIN data ON bn_id=dt_bin "
+ "WHERE dt_bin IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE events"
+ "FROM events"
+ "LEFT JOIN runs ON ev_run=rn_id"
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE event_names"
+ "FROM event_names"
+ "LEFT JOIN events ON en_id=ev_event"
+ "WHERE ev_event IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+SetupStat::init()
+{
+ name = "";
+ descr = "";
+ type = "";
+ print = false;
+ prereq = 0;
+ prec = -1;
+ nozero = false;
+ nonan = false;
+ total = false;
+ pdf = false;
+ cdf = false;
+ min = 0;
+ max = 0;
+ bktsize = 0;
+ size = 0;
+}
+
+unsigned
+SetupStat::setup()
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO "
+ "stats(st_name, st_descr, st_type, st_print, st_prereq, "
+ "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, "
+ "st_min, st_max, st_bktsize, st_size)"
+ "values(\"%s\",\"%s\",\"%s\","
+ " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ name, descr, type, print, prereq, (int)prec, nozero, nonan,
+ total, pdf, cdf,
+ min, max, bktsize, size);
+
+ mysql.query(insert);
+ if (!mysql.error) {
+ int id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ return id;
+ }
+
+ stringstream select;
+ ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name);
+
+ mysql.query(select);
+ MySQL::Result result = mysql.store_result();
+ if (!result)
+ panic("could not find stat\n%s\n", mysql.error);
+
+ assert(result.num_fields() == 16);
+ MySQL::Row row = result.fetch_row();
+ if (!row)
+ panic("could not get stat row\n%s\n", mysql.error);
+
+ bool tb;
+ int8_t ti8;
+ uint16_t tu16;
+ int64_t ti64;
+ uint64_t tu64;
+
+ if (name != (char *)row[1])
+ panic("failed stat check on %s:name. %s != %s\n",
+ name, name, row[1]);
+
+ if (descr != (char *)row[2])
+ panic("failed stat check on %s:descr. %s != %s\n",
+ name, descr, row[2]);
+
+ if (type != (char *)row[3])
+ panic("failed stat check on %s:type. %s != %s\n",
+ name, type, row[3]);
+
+ if (!to_number(row[4], tb) || print != tb)
+ panic("failed stat check on %s:print. %d != %d\n",
+ name, print, tb);
+
+ if (!to_number(row[6], ti8) || prec != ti8)
+ panic("failed stat check on %s:prec. %d != %d\n",
+ name, prec, ti8);
+
+ if (!to_number(row[7], tb) || nozero != tb)
+ panic("failed stat check on %s:nozero. %d != %d\n",
+ name, nozero, tb);
+
+ if (!to_number(row[8], tb) || nonan != tb)
+ panic("failed stat check on %s:nonan. %d != %d\n",
+ name, nonan, tb);
+
+ if (!to_number(row[9], tb) || total != tb)
+ panic("failed stat check on %s:total. %d != %d\n",
+ name, total, tb);
+
+ if (!to_number(row[10], tb) || pdf != tb)
+ panic("failed stat check on %s:pdf. %d != %d\n",
+ name, pdf, tb);
+
+ if (!to_number(row[11], tb) || cdf != tb)
+ panic("failed stat check on %s:cdf. %d != %d\n",
+ name, cdf, tb);
+
+ if (!to_number(row[12], ti64) || min != ti64)
+ panic("failed stat check on %s:min. %d != %d\n",
+ name, min, ti64);
+
+ if (!to_number(row[13], ti64) || max != ti64)
+ panic("failed stat check on %s:max. %d != %d\n",
+ name, max, ti64);
+
+ if (!to_number(row[14], tu64) || bktsize != tu64)
+ panic("failed stat check on %s:bktsize. %d != %d\n",
+ name, bktsize, tu64);
+
+ if (!to_number(row[15], tu16) || size != tu16)
+ panic("failed stat check on %s:size. %d != %d\n",
+ name, size, tu16);
+
+ to_number(row[5], prereq);
+ uint16_t statid;
+ to_number(row[0], statid);
+ return statid;
+}
+
+unsigned
+SetupBin(const string &bin)
+{
+ static map<string, int> binmap;
+
+ using namespace MySQL;
+ map<string,int>::const_iterator i = binmap.find(bin);
+ if (i != binmap.end())
+ return (*i).second;
+
+ Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+
+ uint16_t bin_id;
+
+ stringstream select;
+ stringstream insert;
+ ccprintf(select, "SELECT bn_id FROM bins WHERE bn_name=\"%s\"", bin);
+
+ mysql.query(select);
+ MySQL::Result result = mysql.store_result();
+ if (result) {
+ assert(result.num_fields() == 1);
+ MySQL::Row row = result.fetch_row();
+ if (row) {
+ to_number(row[0], bin_id);
+ goto exit;
+ }
+ }
+
+ ccprintf(insert, "INSERT INTO bins(bn_name) values(\"%s\")", bin);
+
+ mysql.query(insert);
+ if (mysql.error)
+ panic("could not get a bin\n%s\n", mysql.error);
+
+ bin_id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ binmap.insert(make_pair(bin, bin_id));
+
+ exit:
+ return bin_id;
+}
+
+InsertData::InsertData()
+{
+ query = new char[maxsize + 1];
+ size = 0;
+ flush();
+}
+
+InsertData::~InsertData()
+{
+ delete [] query;
+}
+
+void
+InsertData::flush()
+{
+ if (size) {
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ mysql.query(query);
+ if (mysql.error)
+ panic("could not insert data\n%s\n", mysql.error);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ }
+
+ query[0] = '\0';
+ size = 0;
+ first = true;
+ strcpy(query, "INSERT INTO "
+ "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_bin,dt_data) "
+ "values");
+ size = strlen(query);
+}
+
+void
+InsertData::insert()
+{
+ if (size + 1024 > maxsize)
+ flush();
+
+ if (!first) {
+ query[size++] = ',';
+ query[size] = '\0';
+ }
+
+ first = false;
+
+ size += sprintf(query + size, "(%u,%d,%d,%u,%llu,%u,\"%f\")",
+ stat, x, y, MySqlDB.run(), (unsigned long long)tick,
+ bin, data);
+}
+
+struct InsertSubData
+{
+ uint16_t stat;
+ int16_t x;
+ int16_t y;
+ string name;
+ string descr;
+
+ void setup();
+};
+
+void
+InsertSubData::setup()
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) "
+ "values(%d,%d,%d,\"%s\",\"%s\")",
+ stat, x, y, name, descr);
+
+ mysql.query(insert);
+// if (mysql.error)
+// panic("could not insert subdata\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+InsertFormula(uint16_t stat, const string &formula)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream insert_formula;
+ ccprintf(insert_formula,
+ "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")",
+ stat, formula);
+
+ mysql.query(insert_formula);
+// if (mysql.error)
+// panic("could not insert formula\n%s\n", mysql.error);
+
+ stringstream insert_ref;
+ ccprintf(insert_ref,
+ "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)",
+ stat, MySqlDB.run());
+
+ mysql.query(insert_ref);
+// if (mysql.error)
+// panic("could not insert formula reference\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+UpdatePrereq(uint16_t stat, uint16_t prereq)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream update;
+ ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d",
+ prereq, stat);
+ mysql.query(update);
+ if (mysql.error)
+ panic("could not update prereq\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySql::configure()
+{
+ /*
+ * set up all stats!
+ */
+ using namespace Database;
+
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i) {
+ (*i)->visit(*this);
+ }
+
+ for (i = stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ if (data->prereq) {
+ uint16_t stat_id = find(data->id);
+ uint16_t prereq_id = find(data->prereq->id);
+ assert(stat_id && prereq_id);
+
+ UpdatePrereq(stat_id, prereq_id);
+ }
+ }
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ configured = true;
+}
+
+
+bool
+MySql::configure(const StatData &data, string type)
+{
+ stat.init();
+ stat.name = data.name;
+ stat.descr = data.desc;
+ stat.type = type;
+ stat.print = data.flags & print;
+ stat.prec = data.precision;
+ stat.nozero = data.flags & nozero;
+ stat.nonan = data.flags & nonan;
+ stat.total = data.flags & total;
+ stat.pdf = data.flags & pdf;
+ stat.cdf = data.flags & cdf;
+
+ return stat.print;
+}
+
+void
+MySql::configure(const ScalarData &data)
+{
+ if (!configure(data, "SCALAR"))
+ return;
+
+ insert(data.id, stat.setup());
+}
+
+void
+MySql::configure(const VectorData &data)
+{
+ if (!configure(data, "VECTOR"))
+ return;
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = 0;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const DistData &data)
+{
+ if (!configure(data, "DIST"))
+ return;
+
+ if (!data.data.fancy) {
+ stat.size = data.data.size;
+ stat.min = data.data.min;
+ stat.max = data.data.max;
+ stat.bktsize = data.data.bucket_size;
+ }
+ insert(data.id, stat.setup());
+}
+
+void
+MySql::configure(const VectorDistData &data)
+{
+ if (!configure(data, "VECTORDIST"))
+ return;
+
+ if (!data.data[0].fancy) {
+ stat.size = data.data[0].size;
+ stat.min = data.data[0].min;
+ stat.max = data.data[0].max;
+ stat.bktsize = data.data[0].bucket_size;
+ }
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = 0;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const Vector2dData &data)
+{
+ if (!configure(data, "VECTOR2D"))
+ return;
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = -1;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ if (!data.y_subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.x = -1;
+ subdata.descr = "";
+ for (int i = 0; i < data.y_subnames.size(); ++i) {
+ subdata.y = i;
+ subdata.name = data.y_subnames[i];
+ if (!subdata.name.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const FormulaData &data)
+{
+ configure(data, "FORMULA");
+ insert(data.id, stat.setup());
+ InsertFormula(find(data.id), data.str());
+}
+
+void
+MySql::output(MainBin *bin)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ if (bin) {
+ bin->activate();
+ newdata.bin = SetupBin(bin->name());
+ } else {
+ newdata.bin = 0;
+ }
+
+ Database::stat_list_t::const_iterator i, end = Database::stats().end();
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *stat = *i;
+ if (bin && stat->binned() || !bin && !stat->binned()) {
+ stat->visit(*this);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ }
+ }
+}
+
+bool
+MySql::valid() const
+{
+ return MySqlDB.connected();
+}
+
+void
+MySql::output()
+{
+ using namespace Database;
+ assert(valid());
+
+ if (!configured)
+ configure();
+
+ // store sample #
+ newdata.tick = curTick;
+
+ output(NULL);
+ if (!bins().empty()) {
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i)
+ output(*i);
+ }
+
+ newdata.flush();
+}
+
+void
+MySql::output(const ScalarData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.x = 0;
+ newdata.y = 0;
+ newdata.data = data.value();
+
+ newdata.insert();
+}
+
+void
+MySql::output(const VectorData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.y = 0;
+
+ const VCounter &cvec = data.value();
+ int size = data.size();
+ for (int x = 0; x < size; x++) {
+ newdata.x = x;
+ newdata.data = cvec[x];
+ newdata.insert();
+ }
+}
+
+void
+MySql::output(const DistDataData &data)
+{
+ const int db_sum = -1;
+ const int db_squares = -2;
+ const int db_samples = -3;
+ const int db_min_val = -4;
+ const int db_max_val = -5;
+ const int db_underflow = -6;
+ const int db_overflow = -7;
+
+ newdata.x = db_sum;
+ newdata.data = data.sum;
+ newdata.insert();
+
+ newdata.x = db_squares;
+ newdata.data = data.squares;
+ newdata.insert();
+
+ newdata.x = db_samples;
+ newdata.data = data.samples;
+ newdata.insert();
+
+ if (data.samples && !data.fancy) {
+ newdata.x = db_min_val;
+ newdata.data = data.min_val;
+ newdata.insert();
+
+ newdata.x = db_max_val;
+ newdata.data = data.max_val;
+ newdata.insert();
+
+ newdata.x = db_underflow;
+ newdata.data = data.underflow;
+ newdata.insert();
+
+ newdata.x = db_overflow;
+ newdata.data = data.overflow;
+ newdata.insert();
+
+ int size = data.cvec.size();
+ for (int x = 0; x < size; x++) {
+ newdata.x = x;
+ newdata.data = data.cvec[x];
+ newdata.insert();
+ }
+ }
+}
+
+
+void
+MySql::output(const DistData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.y = 0;
+ output(data.data);
+}
+
+void
+MySql::output(const VectorDistData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+
+ int size = data.data.size();
+ for (int y = 0; y < size; ++y) {
+ newdata.y = y;
+ output(data.data[y]);
+ }
+}
+
+void
+MySql::output(const Vector2dData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+
+ int index = 0;
+ for (int x = 0; x < data.x; x++) {
+ newdata.x = x;
+ for (int y = 0; y < data.y; y++) {
+ newdata.y = y;
+ newdata.data = data.cvec[index++];
+ newdata.insert();
+ }
+ }
+}
+
+void
+MySql::output(const FormulaData &data)
+{
+}
+
+/*
+ * Implement the visitor
+ */
+void
+MySql::visit(const ScalarData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const VectorData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const DistData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const VectorDistData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const Vector2dData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const FormulaData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh
new file mode 100644
index 000000000..25ea22b97
--- /dev/null
+++ b/src/base/stats/mysql.hh
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_MYSQL_HH__
+#define __BASE_STATS_MYSQL_HH__
+
+#include <map>
+#include <string>
+
+#include "base/stats/output.hh"
+
+namespace MySQL { class Connection; }
+namespace Stats {
+
+class MainBin;
+class DistDataData;
+class MySqlRun;
+bool MySqlConnected();
+extern MySqlRun MySqlDB;
+
+struct SetupStat
+{
+ std::string name;
+ std::string descr;
+ std::string type;
+ bool print;
+ uint16_t prereq;
+ int8_t prec;
+ bool nozero;
+ bool nonan;
+ bool total;
+ bool pdf;
+ bool cdf;
+ double min;
+ double max;
+ double bktsize;
+ uint16_t size;
+
+ void init();
+ unsigned setup();
+};
+
+class InsertData
+{
+ private:
+ char *query;
+ int size;
+ bool first;
+ static const int maxsize = 1024*1024;
+
+ public:
+ MySqlRun *run;
+
+ public:
+ uint64_t tick;
+ double data;
+ uint16_t stat;
+ uint16_t bin;
+ int16_t x;
+ int16_t y;
+
+ public:
+ InsertData();
+ ~InsertData();
+
+ void flush();
+ void insert();
+};
+
+class MySql : public Output
+{
+ protected:
+ SetupStat stat;
+ InsertData newdata;
+ std::list<FormulaData *> formulas;
+ bool configured;
+
+ protected:
+ std::map<int, int> idmap;
+
+ void insert(int sim_id, int db_id)
+ {
+ using namespace std;
+ idmap.insert(make_pair(sim_id, db_id));
+ }
+
+ int find(int sim_id)
+ {
+ using namespace std;
+ map<int,int>::const_iterator i = idmap.find(sim_id);
+ assert(i != idmap.end());
+ return (*i).second;
+ }
+ public:
+ // Implement Visit
+ virtual void visit(const ScalarData &data);
+ virtual void visit(const VectorData &data);
+ virtual void visit(const DistData &data);
+ virtual void visit(const VectorDistData &data);
+ virtual void visit(const Vector2dData &data);
+ virtual void visit(const FormulaData &data);
+
+ // Implement Output
+ virtual bool valid() const;
+ virtual void output();
+
+ protected:
+ // Output helper
+ void output(MainBin *bin);
+ void output(const DistDataData &data);
+ void output(const ScalarData &data);
+ void output(const VectorData &data);
+ void output(const DistData &data);
+ void output(const VectorDistData &data);
+ void output(const Vector2dData &data);
+ void output(const FormulaData &data);
+
+ void configure();
+ bool configure(const StatData &data, std::string type);
+ void configure(const ScalarData &data);
+ void configure(const VectorData &data);
+ void configure(const DistData &data);
+ void configure(const VectorDistData &data);
+ void configure(const Vector2dData &data);
+ void configure(const FormulaData &data);
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_MYSQL_HH__
diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh
new file mode 100644
index 000000000..d8dcb7594
--- /dev/null
+++ b/src/base/stats/mysql_run.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_MYSQL_RUN_HH__
+#define __BASE_STATS_MYSQL_RUN_HH__
+
+#include <string>
+
+#include "base/mysql.hh"
+#include "sim/host.hh"
+
+namespace Stats {
+
+struct MySqlRun
+{
+ private:
+ MySQL::Connection mysql;
+ uint16_t run_id;
+
+ protected:
+ void setup(const std::string &name, const std::string &sample,
+ const std::string &user, const std::string &project);
+
+ void remove(const std::string &name);
+ void cleanup();
+
+ public:
+ bool connected() const { return mysql.connected(); }
+ void connect(const std::string &host, const std::string &user,
+ const std::string &passwd, const std::string &db,
+ const std::string &name, const std::string &sample,
+ const std::string &project);
+
+ MySQL::Connection &conn() { return mysql; }
+ uint16_t run() const { return run_id; }
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_MYSQL_RUN_HH__
diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh
new file mode 100644
index 000000000..ee6b38d63
--- /dev/null
+++ b/src/base/stats/output.hh
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_OUTPUT_HH__
+#define __BASE_STATS_OUTPUT_HH__
+
+#include <string>
+
+#include "base/stats/visit.hh"
+
+namespace Stats {
+
+struct Output : public Visit
+{
+ inline void operator()() { output(); }
+ virtual void output() = 0;
+ virtual bool valid() const = 0;
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_OUTPUT_HH__
diff --git a/src/base/stats/statdb.cc b/src/base/stats/statdb.cc
new file mode 100644
index 000000000..a6b00ab8a
--- /dev/null
+++ b/src/base/stats/statdb.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/statistics.hh"
+#include "base/stats/bin.hh"
+#include "base/stats/statdb.hh"
+
+using namespace std;
+
+namespace Stats {
+namespace Database {
+
+StatData *
+find(void *stat)
+{
+ stat_map_t::const_iterator i = map().find(stat);
+
+ if (i == map().end())
+ return NULL;
+
+ return (*i).second;
+}
+
+void
+regBin(MainBin *bin, const std::string &_name)
+{
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i)
+ if ((*i)->name() == _name)
+ panic("re-registering bin %s", _name);
+ bins().push_back(bin);
+ DPRINTF(Stats, "registering %s\n", _name);
+}
+
+void
+regStat(void *stat, StatData *data)
+{
+ if (map().find(stat) != map().end())
+ panic("shouldn't register stat twice!");
+
+ stats().push_back(data);
+
+#ifndef NDEBUG
+ pair<stat_map_t::iterator, bool> result =
+#endif
+ map().insert(make_pair(stat, data));
+ assert(result.second && "this should never fail");
+ assert(map().find(stat) != map().end());
+}
+
+void
+regPrint(void *stat)
+{
+ StatData *data = find(stat);
+ assert(data);
+ data->flags |= print;
+}
+
+TheDatabase &db()
+{
+ static TheDatabase db;
+ return db;
+}
+
+/* namespace Database */ }
+/* namespace Stats */ }
diff --git a/src/base/stats/statdb.hh b/src/base/stats/statdb.hh
new file mode 100644
index 000000000..eb56d8fac
--- /dev/null
+++ b/src/base/stats/statdb.hh
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_STATDB_HH__
+#define __BASE_STATS_STATDB_HH__
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <string>
+
+class Python;
+
+namespace Stats {
+
+class MainBin;
+class StatData;
+
+namespace Database {
+
+typedef std::map<void *, StatData *> stat_map_t;
+typedef std::list<StatData *> stat_list_t;
+typedef std::list<MainBin *> bin_list_t;
+
+// We wrap the database in a struct to make sure it is built in time.
+struct TheDatabase
+{
+ stat_map_t map;
+ stat_list_t stats;
+ bin_list_t bins;
+
+};
+
+TheDatabase &db();
+inline stat_map_t &map() { return db().map; }
+inline stat_list_t &stats() { return db().stats; }
+inline bin_list_t &bins() { return db().bins; }
+
+StatData *find(void *stat);
+void regBin(MainBin *bin, const std::string &name);
+void regStat(void *stat, StatData *data);
+void regPrint(void *stat);
+
+inline std::string name() { return "Statistics Database"; }
+
+/* namespace Database */ }
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_STATDB_HH__
diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc
new file mode 100644
index 000000000..300737c60
--- /dev/null
+++ b/src/base/stats/text.cc
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__APPLE__)
+#define _GLIBCPP_USE_C99 1
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/stats/statdb.hh"
+#include "base/stats/text.hh"
+#include "base/stats/visit.hh"
+
+using namespace std;
+
+#ifndef NAN
+float __nan();
+/** Define Not a number. */
+#define NAN (__nan())
+/** Need to define __nan() */
+#define __M5_NAN
+#endif
+
+#ifdef __M5_NAN
+float
+__nan()
+{
+ union {
+ uint32_t ui;
+ float f;
+ } nan;
+
+ nan.ui = 0x7fc00000;
+ return nan.f;
+}
+#endif
+
+namespace Stats {
+
+Text::Text()
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+}
+
+Text::Text(std::ostream &stream)
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+ open(stream);
+}
+
+Text::Text(const std::string &file)
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+ open(file);
+}
+
+
+Text::~Text()
+{
+ if (mystream) {
+ assert(stream);
+ delete stream;
+ }
+}
+
+void
+Text::open(std::ostream &_stream)
+{
+ if (stream)
+ panic("stream already set!");
+
+ mystream = false;
+ stream = &_stream;
+ assert(valid());
+}
+
+void
+Text::open(const std::string &file)
+{
+ if (stream)
+ panic("stream already set!");
+
+ mystream = true;
+ stream = new ofstream(file.c_str(), ios::trunc);
+ assert(valid());
+}
+
+bool
+Text::valid() const
+{
+ return stream != NULL;
+}
+
+void
+Text::output()
+{
+ using namespace Database;
+
+ ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
+ if (bins().empty() || bins().size() == 1) {
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i)
+ (*i)->visit(*this);
+ } else {
+ ccprintf(*stream, "PRINTING BINNED STATS\n");
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i) {
+ MainBin *bin = *i;
+ bin->activate();
+ ccprintf(*stream,"---%s Bin------------\n", bin->name());
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i)
+ (*i)->visit(*this);
+ ccprintf(*stream, "---------------------------------\n");
+ }
+ }
+ ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n");
+ stream->flush();
+}
+
+bool
+Text::noOutput(const StatData &data)
+{
+ if (!(data.flags & print))
+ return true;
+
+ if (data.prereq && data.prereq->zero())
+ return true;
+
+ return false;
+}
+
+string
+ValueToString(Result value, int precision, bool compat)
+{
+ stringstream val;
+
+ if (!isnan(value)) {
+ if (precision != -1)
+ val.precision(precision);
+ else if (value == rint(value))
+ val.precision(0);
+
+ val.unsetf(ios::showpoint);
+ val.setf(ios::fixed);
+ val << value;
+ } else {
+ val << (compat ? "<err: div-0>" : "no value");
+ }
+
+ return val.str();
+}
+
+struct ScalarPrint
+{
+ Result value;
+ string name;
+ string desc;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+ Result pdf;
+ Result cdf;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+ScalarPrint::operator()(ostream &stream) const
+{
+ if (flags & nozero && value == 0.0 ||
+ flags & nonan && isnan(value))
+ return;
+
+ stringstream pdfstr, cdfstr;
+
+ if (!isnan(pdf))
+ ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
+
+ if (!isnan(cdf))
+ ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
+
+ if (compat && flags & __substat) {
+ ccprintf(stream, "%32s %12s %10s %10s", name,
+ ValueToString(value, precision, compat), pdfstr, cdfstr);
+ } else {
+ ccprintf(stream, "%-40s %12s %10s %10s", name,
+ ValueToString(value, precision, compat), pdfstr, cdfstr);
+ }
+
+ if (descriptions) {
+ if (!desc.empty())
+ ccprintf(stream, " # %s", desc);
+ }
+ stream << endl;
+}
+
+struct VectorPrint
+{
+ string name;
+ string desc;
+ vector<string> subnames;
+ vector<string> subdescs;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+ VResult vec;
+ Result total;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+VectorPrint::operator()(std::ostream &stream) const
+{
+ int _size = vec.size();
+ Result _total = 0.0;
+
+ if (flags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ string base = name + (compat ? "_" : "::");
+
+ ScalarPrint print;
+ print.name = name;
+ print.desc = desc;
+ print.precision = precision;
+ print.descriptions = descriptions;
+ print.flags = flags;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ bool havesub = !subnames.empty();
+
+ if (_size == 1) {
+ print.value = vec[0];
+ print(stream);
+ } else if (!compat) {
+ for (int i = 0; i < _size; ++i) {
+ if (havesub && (i >= subnames.size() || subnames[i].empty()))
+ continue;
+
+ print.name = base + (havesub ? subnames[i] : to_string(i));
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.value = vec[i];
+
+ if (_total && (flags & pdf)) {
+ print.pdf = vec[i] / _total;
+ print.cdf += print.pdf;
+ }
+
+ print(stream);
+ }
+
+ if (flags & ::Stats::total) {
+ print.name = base + "total";
+ print.desc = desc;
+ print.value = total;
+ print(stream);
+ }
+ } else {
+ if (flags & ::Stats::total) {
+ print.value = total;
+ print(stream);
+ }
+
+ Result _pdf = 0.0;
+ Result _cdf = 0.0;
+ if (flags & dist) {
+ ccprintf(stream, "%s.start_dist\n", name);
+ for (int i = 0; i < _size; ++i) {
+ print.name = havesub ? subnames[i] : to_string(i);
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.flags |= __substat;
+ print.value = vec[i];
+
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ }
+
+ if (flags & pdf)
+ print.pdf = _pdf;
+ if (flags & cdf)
+ print.cdf = _cdf;
+
+ print(stream);
+ }
+ ccprintf(stream, "%s.end_dist\n", name);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ if (havesub && subnames[i].empty())
+ continue;
+
+ print.name = base;
+ print.name += havesub ? subnames[i] : to_string(i);
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.value = vec[i];
+
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = NAN;
+ }
+
+ if (flags & pdf) {
+ print.pdf = _pdf;
+ print.cdf = _cdf;
+ }
+
+ print(stream);
+ }
+ }
+ }
+}
+
+struct DistPrint
+{
+ string name;
+ string desc;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+
+ Result min_val;
+ Result max_val;
+ Result underflow;
+ Result overflow;
+ VResult vec;
+ Result sum;
+ Result squares;
+ Result samples;
+
+ Counter min;
+ Counter max;
+ Counter bucket_size;
+ int size;
+ bool fancy;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+DistPrint::operator()(ostream &stream) const
+{
+ if (fancy) {
+ ScalarPrint print;
+ string base = name + (compat ? "_" : "::");
+
+ print.precision = precision;
+ print.flags = flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.desc = desc;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ print.name = base + "mean";
+ print.value = samples ? sum / samples : NAN;
+ print(stream);
+
+ print.name = base + "stdev";
+ print.value = samples ? sqrt((samples * squares - sum * sum) /
+ (samples * (samples - 1.0))) : NAN;
+ print(stream);
+
+ print.name = "**Ignore: " + base + "TOT";
+ print.value = samples;
+ print(stream);
+ return;
+ }
+
+ assert(size == vec.size());
+
+ Result total = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ string base = name + (compat ? "." : "::");
+
+ ScalarPrint print;
+ print.desc = compat ? "" : desc;
+ print.flags = flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = precision;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ if (compat) {
+ ccprintf(stream, "%-42s", base + "start_dist");
+ if (descriptions && !desc.empty())
+ ccprintf(stream, " # %s", desc);
+ stream << endl;
+ }
+
+ print.name = base + "samples";
+ print.value = samples;
+ print(stream);
+
+ print.name = base + "min_value";
+ print.value = min_val;
+ print(stream);
+
+ if (!compat || underflow > 0.0) {
+ print.name = base + "underflows";
+ print.value = underflow;
+ if (!compat && total) {
+ print.pdf = underflow / total;
+ print.cdf += print.pdf;
+ }
+ print(stream);
+ }
+
+
+ if (!compat) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ namestr << name;
+
+ Counter low = i * bucket_size + min;
+ Counter high = ::min(low + bucket_size, max);
+ namestr << low;
+ if (low < high)
+ namestr << "-" << high;
+
+ print.name = namestr.str();
+ print.value = vec[i];
+ if (total) {
+ print.pdf = vec[i] / total;
+ print.cdf += print.pdf;
+ }
+ print(stream);
+ }
+
+ } else {
+ Counter _min;
+ Result _pdf;
+ Result _cdf = 0.0;
+
+ print.flags = flags | __substat;
+
+ for (int i = 0; i < size; ++i) {
+ if (flags & nozero && vec[i] == 0.0 ||
+ flags & nonan && isnan(vec[i]))
+ continue;
+
+ _min = i * bucket_size + min;
+ _pdf = vec[i] / total * 100.0;
+ _cdf += _pdf;
+
+
+ print.name = ValueToString(_min, 0, compat);
+ print.value = vec[i];
+ print.pdf = (flags & pdf) ? _pdf : NAN;
+ print.cdf = (flags & cdf) ? _cdf : NAN;
+ print(stream);
+ }
+
+ print.flags = flags;
+ }
+
+ if (!compat || overflow > 0.0) {
+ print.name = base + "overflows";
+ print.value = overflow;
+ if (!compat && total) {
+ print.pdf = overflow / total;
+ print.cdf += print.pdf;
+ } else {
+ print.pdf = NAN;
+ print.cdf = NAN;
+ }
+ print(stream);
+ }
+
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ if (!compat) {
+ print.name = base + "total";
+ print.value = total;
+ print(stream);
+ }
+
+ print.name = base + "max_value";
+ print.value = max_val;
+ print(stream);
+
+ if (!compat && samples != 0) {
+ print.name = base + "mean";
+ print.value = sum / samples;
+ print(stream);
+
+ print.name = base + "stdev";
+ print.value = sqrt((samples * squares - sum * sum) /
+ (samples * (samples - 1.0)));
+ print(stream);
+ }
+
+ if (compat)
+ ccprintf(stream, "%send_dist\n\n", base);
+}
+
+void
+Text::visit(const ScalarData &data)
+{
+ if (noOutput(data))
+ return;
+
+ ScalarPrint print;
+ print.value = data.result();
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ print(*stream);
+}
+
+void
+Text::visit(const VectorData &data)
+{
+ if (noOutput(data))
+ return;
+
+ int size = data.size();
+ VectorPrint print;
+
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+ print.vec = data.result();
+ print.total = data.total();
+
+ if (!data.subnames.empty()) {
+ for (int i = 0; i < size; ++i) {
+ if (!data.subnames[i].empty()) {
+ print.subnames = data.subnames;
+ print.subnames.resize(size);
+ for (int i = 0; i < size; ++i) {
+ if (!data.subnames[i].empty() &&
+ !data.subdescs[i].empty()) {
+ print.subdescs = data.subdescs;
+ print.subdescs.resize(size);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ print(*stream);
+}
+
+void
+Text::visit(const Vector2dData &data)
+{
+ if (noOutput(data))
+ return;
+
+ bool havesub = false;
+ VectorPrint print;
+
+ print.subnames = data.y_subnames;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ if (!data.subnames.empty()) {
+ for (int i = 0; i < data.x; ++i)
+ if (!data.subnames[i].empty())
+ havesub = true;
+ }
+
+ VResult tot_vec(data.y);
+ Result super_total = 0.0;
+ for (int i = 0; i < data.x; ++i) {
+ if (havesub && (i >= data.subnames.size() || data.subnames[i].empty()))
+ continue;
+
+ int iy = i * data.y;
+ VResult yvec(data.y);
+
+ Result total = 0.0;
+ for (int j = 0; j < data.y; ++j) {
+ yvec[j] = data.cvec[iy + j];
+ tot_vec[j] += yvec[j];
+ total += yvec[j];
+ super_total += yvec[j];
+ }
+
+ print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i));
+ print.desc = data.desc;
+ print.vec = yvec;
+ print.total = total;
+ print(*stream);
+ }
+
+ if ((data.flags & ::Stats::total) && (data.x > 1)) {
+ print.name = data.name;
+ print.desc = data.desc;
+ print.vec = tot_vec;
+ print.total = super_total;
+ print(*stream);
+ }
+}
+
+void
+Text::visit(const DistData &data)
+{
+ if (noOutput(data))
+ return;
+
+ DistPrint print;
+
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ print.min_val = data.data.min_val;
+ print.max_val = data.data.max_val;
+ print.underflow = data.data.underflow;
+ print.overflow = data.data.overflow;
+ print.vec.resize(data.data.cvec.size());
+ for (int i = 0; i < print.vec.size(); ++i)
+ print.vec[i] = (Result)data.data.cvec[i];
+ print.sum = data.data.sum;
+ print.squares = data.data.squares;
+ print.samples = data.data.samples;
+
+ print.min = data.data.min;
+ print.max = data.data.max;
+ print.bucket_size = data.data.bucket_size;
+ print.size = data.data.size;
+ print.fancy = data.data.fancy;
+
+ print(*stream);
+}
+
+void
+Text::visit(const VectorDistData &data)
+{
+ if (noOutput(data))
+ return;
+
+ for (int i = 0; i < data.size(); ++i) {
+ DistPrint print;
+
+ print.name = data.name +
+ (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]);
+ print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i];
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ print.min_val = data.data[i].min_val;
+ print.max_val = data.data[i].max_val;
+ print.underflow = data.data[i].underflow;
+ print.overflow = data.data[i].overflow;
+ print.vec.resize(data.data[i].cvec.size());
+ for (int j = 0; j < print.vec.size(); ++j)
+ print.vec[j] = (Result)data.data[i].cvec[j];
+ print.sum = data.data[i].sum;
+ print.squares = data.data[i].squares;
+ print.samples = data.data[i].samples;
+
+ print.min = data.data[i].min;
+ print.max = data.data[i].max;
+ print.bucket_size = data.data[i].bucket_size;
+ print.size = data.data[i].size;
+ print.fancy = data.data[i].fancy;
+
+ print(*stream);
+ }
+}
+
+void
+Text::visit(const FormulaData &data)
+{
+ visit((const VectorData &)data);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh
new file mode 100644
index 000000000..125cb79fa
--- /dev/null
+++ b/src/base/stats/text.hh
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_TEXT_HH__
+#define __BASE_STATS_TEXT_HH__
+
+#include <iosfwd>
+#include <string>
+
+#include "base/stats/output.hh"
+
+namespace Stats {
+
+class Text : public Output
+{
+ protected:
+ bool mystream;
+ std::ostream *stream;
+
+ protected:
+ bool noOutput(const StatData &data);
+ void binout();
+
+ public:
+ bool compat;
+ bool descriptions;
+
+ public:
+ Text();
+ Text(std::ostream &stream);
+ Text(const std::string &file);
+ ~Text();
+
+ void open(std::ostream &stream);
+ void open(const std::string &file);
+
+ // Implement Visit
+ virtual void visit(const ScalarData &data);
+ virtual void visit(const VectorData &data);
+ virtual void visit(const DistData &data);
+ virtual void visit(const VectorDistData &data);
+ virtual void visit(const Vector2dData &data);
+ virtual void visit(const FormulaData &data);
+
+ // Implement Output
+ virtual bool valid() const;
+ virtual void output();
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_TEXT_HH__
diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh
new file mode 100644
index 000000000..57f1564a5
--- /dev/null
+++ b/src/base/stats/types.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_TYPES_HH__
+#define __BASE_STATS_TYPES_HH__
+
+#include <vector>
+#include "sim/host.hh"
+
+namespace Stats {
+
+/** All counters are of 64-bit values. */
+typedef double Counter;
+/** vector of counters. */
+typedef std::vector<Counter> VCounter;
+
+/** All results are doubles. */
+typedef double Result;
+/** vector of results. */
+typedef std::vector<Result> VResult;
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_TYPES_HH__
diff --git a/src/base/stats/visit.cc b/src/base/stats/visit.cc
new file mode 100644
index 000000000..dd4d49502
--- /dev/null
+++ b/src/base/stats/visit.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/stats/visit.hh"
+
+namespace Stats {
+namespace Detail {
+
+Visit::Visit()
+{}
+
+Visit::~Visit()
+{}
+
+/* namespace Detail */ }
+/* namespace Stats */ }
diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh
new file mode 100644
index 000000000..c0593c670
--- /dev/null
+++ b/src/base/stats/visit.hh
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_VISIT_HH__
+#define __BASE_STATS_VISIT_HH__
+
+#include <string>
+
+#include "base/time.hh"
+#include "sim/host.hh"
+
+namespace Stats {
+
+class StatData;
+class ScalarData;
+class VectorData;
+class DistDataData;
+class DistData;
+class VectorDistData;
+class Vector2dData;
+class FormulaData;
+
+struct Visit
+{
+ Visit();
+ virtual ~Visit();
+
+ virtual void visit(const ScalarData &data) = 0;
+ virtual void visit(const VectorData &data) = 0;
+ virtual void visit(const DistData &data) = 0;
+ virtual void visit(const VectorDistData &data) = 0;
+ virtual void visit(const Vector2dData &data) = 0;
+ virtual void visit(const FormulaData &data) = 0;
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_VISIT_HH__
diff --git a/src/base/str.cc b/src/base/str.cc
new file mode 100644
index 000000000..5f7f50286
--- /dev/null
+++ b/src/base/str.cc
@@ -0,0 +1,373 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "base/intmath.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+bool
+split_first(const string &s, string &lhs, string &rhs, char c)
+{
+ string::size_type offset = s.find(c);
+ if (offset == string::npos) {
+ lhs = s;
+ rhs = "";
+ return false;
+ }
+
+ lhs = s.substr(0, offset);
+ rhs = s.substr(offset + 1);
+ return true;
+}
+
+bool
+split_last(const string &s, string &lhs, string &rhs, char c)
+{
+ string::size_type offset = s.rfind(c);
+ if (offset == string::npos) {
+ lhs = s;
+ rhs = "";
+ return false;
+ }
+
+ lhs = s.substr(0, offset);
+ rhs = s.substr(offset + 1);
+ return true;
+}
+
+void
+tokenize(vector<string>& v, const string &s, char token, bool ignore)
+{
+ string::size_type first = 0;
+ string::size_type last = s.find_first_of(token);
+
+ if (s.empty())
+ return;
+
+ if (ignore && last == first) {
+ while (last == first)
+ last = s.find_first_of(token, ++first);
+
+ if (last == string::npos) {
+ if (first != s.size())
+ v.push_back(s.substr(first));
+ return;
+ }
+ }
+
+ while (last != string::npos) {
+ v.push_back(s.substr(first, last - first));
+
+ if (ignore) {
+ first = s.find_first_not_of(token, last + 1);
+
+ if (first == string::npos)
+ return;
+ } else
+ first = last + 1;
+
+ last = s.find_first_of(token, first);
+ }
+
+ v.push_back(s.substr(first));
+}
+
+/**
+ * @todo This function will not handle the smallest negative decimal
+ * value for a signed type
+ */
+
+template <class T>
+inline bool
+__to_number(string value, T &retval)
+{
+ static const T maxnum = ((T)-1);
+ static const bool sign = maxnum < 0;
+ static const int bits = sizeof(T) * 8;
+ static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1);
+ static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1);
+ static const T signmax =
+ (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum;
+ static const T decmax = signmax / 10;
+
+#if 0
+ cout << "maxnum = 0x" << hex << (unsigned long long)maxnum << "\n"
+ << "sign = 0x" << hex << (unsigned long long)sign << "\n"
+ << "hexmax = 0x" << hex << (unsigned long long)hexmax << "\n"
+ << "octmax = 0x" << hex << (unsigned long long)octmax << "\n"
+ << "signmax = 0x" << hex << (unsigned long long)signmax << "\n"
+ << "decmax = 0x" << hex << (unsigned long long)decmax << "\n";
+#endif
+
+ eat_white(value);
+
+ bool negative = false;
+ bool hex = false;
+ bool oct = false;
+ int last = value.size() - 1;
+ retval = 0;
+ int i = 0;
+
+ char c = value[i];
+ if (!isDec(c)) {
+ if (c == '-' && sign)
+ negative = true;
+ else
+ return false;
+ }
+ else {
+ retval += c - '0';
+ if (last == 0) return true;
+ }
+
+ if (c == '0')
+ oct = true;
+
+ c = value[++i];
+ if (oct) {
+ if (sign && negative)
+ return false;
+
+ if (!isOct(c)) {
+ if (c == 'X' || c == 'x') {
+ hex = true;
+ oct = false;
+ } else
+ return false;
+ }
+ else
+ retval += c - '0';
+ } else if (!isDec(c))
+ goto multiply;
+ else {
+ if (sign && negative && c == '0')
+ return false;
+
+ retval *= 10;
+ retval += c - '0';
+ if (last == 1) {
+ if (sign && negative) retval = -retval;
+ return true;
+ }
+ }
+
+ if (hex) {
+ if (last == 1)
+ return false;
+
+ for (i = 2; i <= last ; i++) {
+ c = value[i];
+ if (!isHex(c))
+ return false;
+
+ if (retval > hexmax) return false;
+ retval *= 16;
+ retval += hex2Int(c);
+ }
+ return true;
+ } else if (oct) {
+ for (i = 2; i <= last ; i++) {
+ c = value[i];
+ if (!isOct(c))
+ return false;
+
+ if (retval > octmax) return false;
+ retval *= 8;
+ retval += (c - '0');
+ }
+ return true;
+ }
+
+ for (i = 2; i < last ; i++) {
+ c = value[i];
+ if (!isDec(c))
+ goto multiply;
+
+ if (retval > decmax) return false;
+ bool atmax = retval == decmax;
+ retval *= 10;
+ retval += c - '0';
+ if (atmax && retval < decmax) return false;
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+
+ c = value[last];
+ if (isDec(c)) {
+
+ if (retval > decmax) return false;
+ bool atmax = retval == decmax;
+ retval *= 10;
+ retval += c - '0';
+ if (atmax && retval < decmax) return false;
+ if (sign && negative) {
+ if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
+ retval >= (T)-signmax)
+ return false;
+ retval = -retval;
+ }
+ else
+ if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
+ return false;
+ return true;
+ }
+
+ multiply:
+ signed long long mult = 1;
+ T val;
+ switch (c) {
+ case 'k':
+ case 'K':
+ if (i != last) return false;
+ mult = 1024;
+ val = signmax / mult;
+ break;
+ case 'm':
+ case 'M':
+ if (i != last) return false;
+ mult = 1024 * 1024;
+ val = signmax / mult;
+ break;
+ case 'g':
+ case 'G':
+ if (i != last) return false;
+ mult = 1024 * 1024 * 1024;
+ val = signmax / mult;
+ break;
+ case 'e':
+ case 'E':
+ if (i >= last) return false;
+
+ mult = 0;
+ for (i++; i <= last; i++) {
+ c = value[i];
+ if (!isDec(c))
+ return false;
+
+ mult *= 10;
+ mult += c - '0';
+ }
+
+ for (i = 0; i < mult; i++) {
+ if (retval > signmax / 10)
+ return false;
+ retval *= 10;
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+ if (sign && negative) {
+ if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
+ retval >= (T)-signmax)
+ return false;
+ retval = -retval;
+ }
+ else
+ if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
+ return false;
+
+ return true;
+
+ default:
+ return false;
+ }
+
+ if (sign && negative)
+ return false;
+
+ if (mult > (unsigned long long)signmax)
+ return false;
+
+ if (retval > val)
+ return false;
+
+ retval *= mult;
+
+ return true;
+}
+
+#define STN(type) \
+template<> \
+bool to_number<type>(const string &value, type &retval) \
+{ return __to_number(value, retval); }
+
+STN(unsigned long long);
+STN(signed long long);
+STN(unsigned long);
+STN(signed long);
+STN(unsigned int);
+STN(signed int);
+STN(unsigned short);
+STN(signed short);
+STN(unsigned char);
+STN(signed char);
+
+template<>
+bool to_number<bool>(const string &value, bool &retval)
+{
+ string lowered = to_lower(value);
+
+ if (value == "0") {
+ retval = false;
+ return true;
+ }
+
+ if (value == "1"){
+ retval = true;
+ return true;
+ }
+
+ if (lowered == "false") {
+ retval = false;
+ return true;
+ }
+
+ if (lowered == "true"){
+ retval = true;
+ return true;
+ }
+
+ if (lowered == "no") {
+ retval = false;
+ return true;
+ }
+
+ if (lowered == "yes"){
+ retval = true;
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/base/str.hh b/src/base/str.hh
new file mode 100644
index 000000000..79e33a1be
--- /dev/null
+++ b/src/base/str.hh
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifndef __STR_HH__
+#define __STR_HH__
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+
+template<class> class Hash;
+template<>
+class Hash<std::string> {
+public:
+ unsigned operator()(const std::string &s) {
+ std::string::const_iterator i = s.begin();
+ std::string::const_iterator end = s.end();
+ unsigned hash = 5381;
+
+ while (i < end)
+ hash = ((hash << 5) + hash) + *i++;
+
+ return hash;
+ }
+};
+
+inline void
+eat_lead_white(std::string &s)
+{
+ std::string::size_type off = s.find_first_not_of(' ');
+ if (off != std::string::npos) {
+ std::string::iterator begin = s.begin();
+ s.erase(begin, begin + off);
+ }
+}
+
+inline void
+eat_end_white(std::string &s)
+{
+ std::string::size_type off = s.find_last_not_of(' ');
+ if (off != std::string::npos)
+ s.erase(s.begin() + off + 1, s.end());
+}
+
+inline void
+eat_white(std::string &s)
+{
+ eat_lead_white(s);
+ eat_end_white(s);
+}
+
+inline std::string
+to_lower(const std::string &s)
+{
+ std::string lower;
+ int len = s.size();
+
+ lower.reserve(len);
+
+ for (int i = 0; i < len; ++i)
+ lower.push_back(tolower(s[i]));
+
+ return lower;
+}
+
+// Split the string s into lhs and rhs on the first occurence of the
+// character c.
+bool
+split_first(const std::string &s, std::string &lhs, std::string &rhs, char c);
+
+// Split the string s into lhs and rhs on the last occurence of the
+// character c.
+bool
+split_last(const std::string &s, std::string &lhs, std::string &rhs, char c);
+
+// Tokenize the string <s> splitting on the character <token>, and
+// place the result in the string vector <vector>. If <ign> is true,
+// then empty result strings (due to trailing tokens, or consecutive
+// tokens) are skipped.
+void
+tokenize(std::vector<std::string> &vector, const std::string &s,
+ char token, bool ign = true);
+
+template <class T> bool
+to_number(const std::string &value, T &retval);
+
+template <class T>
+inline std::string
+to_string(const T &value)
+{
+ std::stringstream str;
+ str << value;
+ return str.str();
+}
+
+// Put quotes around string arg if it contains spaces.
+inline std::string
+quote(const std::string &s)
+{
+ std::string ret;
+ bool quote = s.find(' ') != std::string::npos;
+
+ if (quote)
+ ret = '"';
+
+ ret += s;
+
+ if (quote)
+ ret += '"';
+
+ return ret;
+}
+
+#endif //__STR_HH__
diff --git a/src/base/time.cc b/src/base/time.cc
new file mode 100644
index 000000000..5827c9a85
--- /dev/null
+++ b/src/base/time.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <string>
+
+#include "base/time.hh"
+
+using namespace std;
+
+struct _timeval
+{
+ timeval tv;
+};
+
+double
+convert(const timeval &tv)
+{
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+}
+
+Time::Time(bool set_now)
+{
+ time = new _timeval;
+ if (set_now)
+ set();
+}
+
+Time::Time(const timeval &val)
+{
+ time = new _timeval;
+ set(val);
+}
+
+Time::Time(const Time &val)
+{
+ time = new _timeval;
+ set(val.get());
+}
+
+Time::~Time()
+{
+ delete time;
+}
+
+const timeval &
+Time::get() const
+{
+ return time->tv;
+}
+
+void
+Time::set()
+{
+ ::gettimeofday(&time->tv, NULL);
+}
+
+void
+Time::set(const timeval &tv)
+{
+ memcpy(&time->tv, &tv, sizeof(timeval));
+}
+
+double
+Time::operator()() const
+{
+ return convert(get());
+}
+
+string
+Time::date(string format) const
+{
+ const timeval &tv = get();
+ time_t sec = tv.tv_sec;
+ char buf[256];
+
+ if (format.empty()) {
+ ctime_r(&sec, buf);
+ buf[24] = '\0';
+ return buf;
+ }
+
+ struct tm *tm = localtime(&sec);
+ strftime(buf, sizeof(buf), format.c_str(), tm);
+ return buf;
+}
+
+ostream &
+operator<<(ostream &out, const Time &start)
+{
+ out << start.date();
+ return out;
+}
+
+Time
+operator-(const Time &l, const Time &r)
+{
+ timeval tv;
+ timersub(&l.get(), &r.get(), &tv);
+ return tv;
+}
+
+const Time Time::start(true);
diff --git a/src/base/time.hh b/src/base/time.hh
new file mode 100644
index 000000000..5731e3029
--- /dev/null
+++ b/src/base/time.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_TIME_HH__
+#define __SIM_TIME_HH__
+
+#include <sys/time.h>
+
+#include <iosfwd>
+#include <string>
+
+struct _timeval;
+
+class Time
+{
+ protected:
+ mutable _timeval *time;
+
+ public:
+ explicit Time(bool set_now = false);
+ Time(const timeval &val);
+ Time(const Time &val);
+ ~Time();
+
+ void set();
+ const timeval &get() const;
+ void set(const timeval &val);
+
+ double operator()() const;
+ std::string date(std::string format = "") const;
+
+ public:
+ static const Time start;
+};
+
+Time operator-(const Time &l, const Time &r);
+
+std::ostream &operator<<(std::ostream &out, const Time &time);
+
+#endif // __SIM_TIME_HH__
diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh
new file mode 100644
index 000000000..f6b5b2781
--- /dev/null
+++ b/src/base/timebuf.hh
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_TIMEBUF_HH__
+#define __BASE_TIMEBUF_HH__
+
+#include <vector>
+
+template <class T>
+class TimeBuffer
+{
+ protected:
+ int past;
+ int future;
+ int size;
+
+ char *data;
+ std::vector<char *> index;
+ int base;
+
+ void valid(int idx)
+ {
+ assert (idx >= -past && idx <= future);
+ }
+
+ public:
+ friend class wire;
+ class wire
+ {
+ friend class TimeBuffer;
+ protected:
+ TimeBuffer<T> *buffer;
+ int index;
+
+ void set(int idx)
+ {
+ buffer->valid(idx);
+ index = idx;
+ }
+
+ wire(TimeBuffer<T> *buf, int i)
+ : buffer(buf), index(i)
+ { }
+
+ public:
+ wire()
+ { }
+
+ wire(const wire &i)
+ : buffer(i.buffer), index(i.index)
+ { }
+
+ const wire &operator=(const wire &i)
+ {
+ buffer = i.buffer;
+ set(i.index);
+ return *this;
+ }
+
+ const wire &operator=(int idx)
+ {
+ set(idx);
+ return *this;
+ }
+
+ const wire &operator+=(int offset)
+ {
+ set(index + offset);
+ return *this;
+ }
+
+ const wire &operator-=(int offset)
+ {
+ set(index - offset);
+ return *this;
+ }
+
+ wire &operator++()
+ {
+ set(index + 1);
+ return *this;
+ }
+
+ wire &operator++(int)
+ {
+ int i = index;
+ set(index + 1);
+ return wire(this, i);
+ }
+
+ wire &operator--()
+ {
+ set(index - 1);
+ return *this;
+ }
+
+ wire &operator--(int)
+ {
+ int i = index;
+ set(index - 1);
+ return wire(this, i);
+ }
+ T &operator*() const { return *buffer->access(index); }
+ T *operator->() const { return buffer->access(index); }
+ };
+
+
+ public:
+ TimeBuffer(int p, int f)
+ : past(p), future(f), size(past + future + 1),
+ data(new char[size * sizeof(T)]), index(size), base(0)
+ {
+ assert(past >= 0 && future >= 0);
+ char *ptr = data;
+ for (int i = 0; i < size; i++) {
+ index[i] = ptr;
+ memset(ptr, 0, sizeof(T));
+ new (ptr) T;
+ ptr += sizeof(T);
+ }
+ }
+
+ TimeBuffer()
+ : data(NULL)
+ {
+ }
+
+ ~TimeBuffer()
+ {
+ for (int i = 0; i < size; ++i)
+ (reinterpret_cast<T *>(index[i]))->~T();
+ delete [] data;
+ }
+
+ void
+ advance()
+ {
+ if (++base >= size)
+ base = 0;
+
+ int ptr = base + future;
+ if (ptr >= size)
+ ptr -= size;
+ (reinterpret_cast<T *>(index[ptr]))->~T();
+ memset(index[ptr], 0, sizeof(T));
+ new (index[ptr]) T;
+ }
+
+ T *access(int idx)
+ {
+ //Need more complex math here to calculate index.
+ valid(idx);
+
+ int vector_index = idx + base;
+ if (vector_index >= size) {
+ vector_index -= size;
+ } else if (vector_index < 0) {
+ vector_index += size;
+ }
+
+ return reinterpret_cast<T *>(index[vector_index]);
+ }
+
+ T &operator[](int idx)
+ {
+ //Need more complex math here to calculate index.
+ valid(idx);
+
+ int vector_index = idx + base;
+ if (vector_index >= size) {
+ vector_index -= size;
+ } else if (vector_index < 0) {
+ vector_index += size;
+ }
+
+ return reinterpret_cast<T &>(*index[vector_index]);
+ }
+
+ wire getWire(int idx)
+ {
+ valid(idx);
+
+ return wire(this, idx);
+ }
+
+ wire zero()
+ {
+ return wire(this, 0);
+ }
+};
+
+#endif // __BASE_TIMEBUF_HH__
+
diff --git a/src/base/trace.cc b/src/base/trace.cc
new file mode 100644
index 000000000..90db7f045
--- /dev/null
+++ b/src/base/trace.cc
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+namespace Trace {
+const string DefaultName("global");
+FlagVec flags(NumFlags, false);
+
+//
+// This variable holds the output stream for debug information. Other
+// than setting up/redirecting this stream, do *NOT* reference this
+// directly; use DebugOut() (see below) to access this stream for
+// output.
+//
+ostream *dprintf_stream = &cerr;
+
+ObjectMatch ignore;
+
+Log theLog;
+
+Log::Log()
+{
+ size = 0;
+ buffer = NULL;
+}
+
+
+void
+Log::init(int _size)
+{
+ if (buffer != NULL) {
+ fatal("Trace::Log::init called twice!");
+ }
+
+ size = _size;
+
+ buffer = new Record *[size];
+
+ for (int i = 0; i < size; ++i) {
+ buffer[i] = NULL;
+ }
+
+ nextRecPtr = &buffer[0];
+ wrapRecPtr = &buffer[size];
+}
+
+
+Log::~Log()
+{
+ for (int i = 0; i < size; ++i) {
+ delete buffer[i];
+ }
+
+ delete [] buffer;
+}
+
+
+void
+Log::append(Record *rec)
+{
+ // dump record to output stream if there's one open
+ if (dprintf_stream != NULL) {
+ rec->dump(*dprintf_stream);
+ } else {
+ rec->dump(cout);
+ }
+
+ // no buffering: justget rid of it now
+ if (buffer == NULL) {
+ delete rec;
+ return;
+ }
+
+ Record *oldRec = *nextRecPtr;
+
+ if (oldRec != NULL) {
+ // log has wrapped: overwrite
+ delete oldRec;
+ }
+
+ *nextRecPtr = rec;
+
+ if (++nextRecPtr == wrapRecPtr) {
+ nextRecPtr = &buffer[0];
+ }
+}
+
+
+void
+Log::dump(ostream &os)
+{
+ if (buffer == NULL) {
+ return;
+ }
+
+ Record **bufPtr = nextRecPtr;
+
+ if (*bufPtr == NULL) {
+ // next record slot is empty: log must not be full yet.
+ // start dumping from beginning of buffer
+ bufPtr = buffer;
+ }
+
+ do {
+ Record *rec = *bufPtr;
+
+ rec->dump(os);
+
+ if (++bufPtr == wrapRecPtr) {
+ bufPtr = &buffer[0];
+ }
+ } while (bufPtr != nextRecPtr);
+}
+
+PrintfRecord::~PrintfRecord()
+{
+ delete &args;
+}
+
+void
+PrintfRecord::dump(ostream &os)
+{
+ string fmt = "";
+
+ if (!name.empty()) {
+ fmt = "%s: " + fmt;
+ args.prepend(name);
+ }
+
+ if (cycle != (Tick)-1) {
+ fmt = "%7d: " + fmt;
+ args.prepend(cycle);
+ }
+
+ fmt += format;
+
+ args.dump(os, fmt);
+ os.flush();
+}
+
+DataRecord::DataRecord(Tick _cycle, const string &_name,
+ const void *_data, int _len)
+ : Record(_cycle), name(_name), len(_len)
+{
+ data = new uint8_t[len];
+ memcpy(data, _data, len);
+}
+
+DataRecord::~DataRecord()
+{
+ delete [] data;
+}
+
+void
+DataRecord::dump(ostream &os)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ ccprintf(os, "%d: %s: %08x ", cycle, name, i);
+ c = len - i;
+ if (c > 16) c = 16;
+
+ for (j = 0; j < c; j++) {
+ ccprintf(os, "%02x ", data[i + j] & 0xff);
+ if ((j & 0xf) == 7 && j > 0)
+ ccprintf(os, " ");
+ }
+
+ for (; j < 16; j++)
+ ccprintf(os, " ");
+ ccprintf(os, " ");
+
+ for (j = 0; j < c; j++) {
+ int ch = data[i + j] & 0x7f;
+ ccprintf(os,
+ "%c", (char)(isprint(ch) ? ch : ' '));
+ }
+
+ ccprintf(os, "\n");
+
+ if (c < 16)
+ break;
+ }
+}
+} // namespace Trace
+
+//
+// Returns the current output stream for debug information. As a
+// wrapper around Trace::dprintf_stream, this handles cases where debug
+// information is generated in the process of parsing .ini options,
+// before we process the option that sets up the debug output stream
+// itself.
+//
+std::ostream &
+DebugOut()
+{
+ return *Trace::dprintf_stream;
+}
+
+/////////////////////////////////////////////
+//
+// C-linkage functions for invoking from gdb
+//
+/////////////////////////////////////////////
+
+//
+// Dump trace buffer to specified file (cout if NULL)
+//
+extern "C"
+void
+dumpTrace(const char *filename)
+{
+ if (filename != NULL) {
+ ofstream out(filename);
+ Trace::theLog.dump(out);
+ out.close();
+ }
+ else {
+ Trace::theLog.dump(cout);
+ }
+}
+
+
+//
+// Turn on/off trace output to cerr. Typically used when trace output
+// is only going to circular buffer, but you want to see what's being
+// sent there as you step through some code in gdb. This uses the
+// same facility as the "trace to file" feature, and will print error
+// messages rather than clobbering an existing ostream pointer.
+//
+extern "C"
+void
+echoTrace(bool on)
+{
+ if (on) {
+ if (Trace::dprintf_stream != NULL) {
+ cerr << "Already echoing trace to a file... go do a 'tail -f'"
+ << " on that file instead." << endl;
+ } else {
+ Trace::dprintf_stream = &cerr;
+ }
+ } else {
+ if (Trace::dprintf_stream != &cerr) {
+ cerr << "Not echoing trace to cerr." << endl;
+ } else {
+ Trace::dprintf_stream = NULL;
+ }
+ }
+}
+
+extern "C"
+void
+printTraceFlags()
+{
+ using namespace Trace;
+ for (int i = 0; i < numFlagStrings; ++i)
+ if (flags[i])
+ cprintf("%s\n", flagStrings[i]);
+}
+
+void
+tweakTraceFlag(const char *string, bool value)
+{
+ using namespace Trace;
+ std::string str(string);
+
+ for (int i = 0; i < numFlagStrings; ++i) {
+ if (str != flagStrings[i])
+ continue;
+
+ int idx = i;
+
+ if (idx < NumFlags) {
+ flags[idx] = value;
+ } else {
+ idx -= NumFlags;
+ if (idx >= NumCompoundFlags) {
+ ccprintf(cerr, "Invalid compound flag");
+ return;
+ }
+
+ const Flags *flagVec = compoundFlags[idx];
+
+ for (int j = 0; flagVec[j] != -1; ++j) {
+ if (flagVec[j] >= NumFlags) {
+ ccprintf(cerr, "Invalid compound flag");
+ return;
+ }
+ flags[flagVec[j]] = value;
+ }
+ }
+
+ cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
+ return;
+ }
+
+ cprintf("could not find flag %s\n", string);
+}
+
+extern "C"
+void
+setTraceFlag(const char *string)
+{
+ tweakTraceFlag(string, true);
+}
+
+extern "C"
+void
+clearTraceFlag(const char *string)
+{
+ tweakTraceFlag(string, false);
+}
diff --git a/src/base/trace.hh b/src/base/trace.hh
new file mode 100644
index 000000000..5e14f1bff
--- /dev/null
+++ b/src/base/trace.hh
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#ifndef __BASE_TRACE_HH__
+#define __BASE_TRACE_HH__
+
+#include <vector>
+
+#include "base/cprintf.hh"
+#include "base/match.hh"
+#include "sim/host.hh"
+#include "sim/root.hh"
+
+#ifndef TRACING_ON
+#ifndef NDEBUG
+#define TRACING_ON 1
+#else
+#define TRACING_ON 0
+#endif
+#endif
+
+#include "base/traceflags.hh"
+
+namespace Trace {
+
+ typedef std::vector<bool> FlagVec;
+
+ extern FlagVec flags;
+
+#if TRACING_ON
+ const bool On = true;
+#else
+ const bool On = false;
+#endif
+
+ inline bool
+ IsOn(int t)
+ {
+ return flags[t];
+
+ }
+
+ void dump(const uint8_t *data, int count);
+
+ class Record
+ {
+ protected:
+ Tick cycle;
+
+ Record(Tick _cycle)
+ : cycle(_cycle)
+ {
+ }
+
+ public:
+ virtual ~Record() {}
+
+ virtual void dump(std::ostream &) = 0;
+ };
+
+ class PrintfRecord : public Record
+ {
+ private:
+ const char *format;
+ const std::string &name;
+ cp::ArgList &args;
+
+ public:
+ PrintfRecord(const char *_format, cp::ArgList &_args,
+ Tick cycle, const std::string &_name)
+ : Record(cycle), format(_format), name(_name), args(_args)
+ {
+ }
+
+ virtual ~PrintfRecord();
+
+ virtual void dump(std::ostream &);
+ };
+
+ class DataRecord : public Record
+ {
+ private:
+ const std::string &name;
+ uint8_t *data;
+ int len;
+
+ public:
+ DataRecord(Tick cycle, const std::string &name,
+ const void *_data, int _len);
+ virtual ~DataRecord();
+
+ virtual void dump(std::ostream &);
+ };
+
+ class Log
+ {
+ private:
+ int size; // number of records in log
+ Record **buffer; // array of 'size' Record ptrs (circular buf)
+ Record **nextRecPtr; // next slot to use in buffer
+ Record **wrapRecPtr; // &buffer[size], for quick wrap check
+
+ public:
+
+ Log();
+ ~Log();
+
+ void init(int _size);
+
+ void append(Record *); // append trace record to log
+ void dump(std::ostream &); // dump contents to stream
+ };
+
+ extern Log theLog;
+
+ extern ObjectMatch ignore;
+
+ inline void
+ dprintf(const char *format, cp::ArgList &args, Tick cycle,
+ const std::string &name)
+ {
+ if (name.empty() || !ignore.match(name))
+ theLog.append(new Trace::PrintfRecord(format, args, cycle, name));
+ }
+
+ inline void
+ dataDump(Tick cycle, const std::string &name, const void *data, int len)
+ {
+ theLog.append(new Trace::DataRecord(cycle, name, data, len));
+ }
+
+ extern const std::string DefaultName;
+};
+
+// This silly little class allows us to wrap a string in a functor
+// object so that we can give a name() that DPRINTF will like
+struct StringWrap
+{
+ std::string str;
+ StringWrap(const std::string &s) : str(s) {}
+ const std::string &operator()() const { return str; }
+};
+
+inline const std::string &name() { return Trace::DefaultName; }
+std::ostream &DebugOut();
+
+//
+// DPRINTF is a debugging trace facility that allows one to
+// selectively enable tracing statements. To use DPRINTF, there must
+// be a function or functor called name() that returns a const
+// std::string & in the current scope.
+//
+// If you desire that the automatic printing not occur, use DPRINTFR
+// (R for raw)
+//
+
+#if TRACING_ON
+
+#define DTRACE(x) (Trace::IsOn(Trace::x))
+
+#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut()
+
+#define DDUMP(x, data, count) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ Trace::dataDump(curTick, name(), data, count); \
+} while (0)
+
+#define __dprintf(cycle, name, format, args...) \
+ Trace::dprintf(format, (*(new cp::ArgList), args), cycle, name)
+
+#define DPRINTF(x, args...) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ __dprintf(curTick, name(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFR(x, args...) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ __dprintf((Tick)-1, std::string(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFN(args...) \
+do { \
+ __dprintf(curTick, name(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFNR(args...) \
+do { \
+ __dprintf((Tick)-1, string(), args, cp::ArgListNull()); \
+} while (0)
+
+#else // !TRACING_ON
+
+#define DTRACE(x) (false)
+#define DCOUT(x) if (0) DebugOut()
+#define DPRINTF(x, args...) do {} while (0)
+#define DPRINTFR(args...) do {} while (0)
+#define DPRINTFN(args...) do {} while (0)
+#define DPRINTFNR(args...) do {} while (0)
+#define DDUMP(x, data, count) do {} while (0)
+
+#endif // TRACING_ON
+
+#endif // __BASE_TRACE_HH__
diff --git a/src/base/traceflags.py b/src/base/traceflags.py
new file mode 100644
index 000000000..7dbaac60e
--- /dev/null
+++ b/src/base/traceflags.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# This file generates the header and source files for the flags
+# that control the tracing facility.
+#
+
+import sys
+
+if len(sys.argv) != 2:
+ print "%s: Need argument (basename of cc/hh files)" % sys.argv[0]
+ sys.exit(1)
+
+hhfilename = sys.argv[1] + '.hh'
+ccfilename = sys.argv[1] + '.cc'
+
+#
+# The list of trace flags that can be used to condition DPRINTFs etc.
+# To define a new flag, simply add it to this list.
+#
+baseFlags = [
+ 'TCPIP',
+ 'Bus',
+ 'ScsiDisk',
+ 'ScsiCtrl',
+ 'ScsiNone',
+ 'DMA',
+ 'DMAReadVerbose',
+ 'DMAWriteVerbose',
+ 'TLB',
+ 'SimpleDisk',
+ 'SimpleDiskData',
+ 'Clock',
+ 'Regs',
+ 'MC146818',
+ 'IPI',
+ 'Timer',
+ 'Mbox',
+ 'PCIA',
+ 'PCIDEV',
+ 'PciConfigAll',
+ 'ISP',
+ 'BADADDR',
+ 'Console',
+ 'ConsolePoll',
+ 'ConsoleVerbose',
+ 'AlphaConsole',
+ 'Flow',
+ 'Interrupt',
+ 'Fault',
+ 'Cycle',
+ 'Loader',
+ 'MMU',
+ 'Ethernet',
+ 'EthernetPIO',
+ 'EthernetDMA',
+ 'EthernetData',
+ 'EthernetDesc',
+ 'EthernetIntr',
+ 'EthernetSM',
+ 'EthernetCksum',
+ 'GDBMisc',
+ 'GDBAcc',
+ 'GDBRead',
+ 'GDBWrite',
+ 'GDBSend',
+ 'GDBRecv',
+ 'GDBExtra',
+ 'VtoPhys',
+ 'Printf',
+ 'DebugPrintf',
+ 'Serialize',
+ 'Event',
+ 'PCEvent',
+ 'Syscall',
+ 'SyscallVerbose',
+ 'DiskImage',
+ 'DiskImageRead',
+ 'DiskImageWrite',
+ 'InstExec',
+ 'BPredRAS',
+ 'Cache',
+ 'IIC',
+ 'IICMore',
+ 'MSHR',
+ 'Chains',
+ 'Pipeline',
+ 'Stats',
+ 'StatEvents',
+ 'Context',
+ 'Config',
+ 'Sampler',
+ 'WriteBarrier',
+ 'IdeCtrl',
+ 'IdeDisk',
+ 'Tsunami',
+ 'Uart',
+ 'Split',
+ 'SQL',
+ 'Thread',
+ 'Fetch',
+ 'Decode',
+ 'Rename',
+ 'IEW',
+ 'Commit',
+ 'IQ',
+ 'ROB',
+ 'FreeList',
+ 'RenameMap',
+ 'LDSTQ',
+ 'StoreSet',
+ 'MemDepUnit',
+ 'DynInst',
+ 'FullCPU',
+ 'CommitRate',
+ 'OoOCPU',
+ 'HWPrefetch',
+ 'Stack',
+ 'SimpleCPU',
+ 'Sparc',
+ ]
+
+#
+# "Compound" flags correspond to a set of base flags. These exist
+# solely for convenience in setting them via the command line: if a
+# compound flag is specified, all of the corresponding base flags are
+# set. Compound flags cannot be used directly in DPRINTFs etc.
+# To define a new compound flag, add a new entry to this hash
+# following the existing examples.
+#
+compoundFlagMap = {
+ 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ],
+ 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ],
+ 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ],
+ 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
+ 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
+ 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ],
+ 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LDSTQ', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU']
+}
+
+#############################################################
+#
+# Everything below this point generates the appropriate C++
+# declarations and definitions for the trace flags. If you are simply
+# adding or modifying flag definitions, you should not have to change
+# anything below.
+#
+
+import sys
+
+# extract just the compound flag names into a list
+compoundFlags = []
+compoundFlags.extend(compoundFlagMap.keys())
+compoundFlags.sort()
+
+#
+# First generate the header file. This defines the Flag enum
+# and some extern declarations for the .cc file.
+#
+try:
+ hhfile = file(hhfilename, 'w')
+except IOError, e:
+ sys.exit("can't open %s: %s" % (hhfilename, e))
+
+# file header boilerplate
+print >>hhfile, '''
+/*
+ * DO NOT EDIT THIS FILE!
+ *
+ * Automatically generated from traceflags.py
+ */
+
+#ifndef __BASE_TRACE_FLAGS_HH__
+#define __BASE_TRACE_FLAGS_HH__
+
+namespace Trace {
+
+enum Flags {
+''',
+
+# Generate the enum. Base flags come first, then compound flags.
+idx = 0
+for flag in baseFlags:
+ print >>hhfile, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+numBaseFlags = idx
+print >>hhfile, ' NumFlags = %d,' % idx
+
+# put a comment in here to separate base from compound flags
+print >>hhfile, '''
+ // The remaining enum values are *not* valid indices for Trace::flags.
+ // They are "compound" flags, which correspond to sets of base
+ // flags, and are used only by TraceParamContext::setFlags().
+''',
+
+for flag in compoundFlags:
+ print >>hhfile, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+numCompoundFlags = idx - numBaseFlags
+print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags
+
+# trailer boilerplate
+print >>hhfile, '''\
+}; // enum Flags
+
+// Array of strings for SimpleEnumParam
+extern const char *flagStrings[];
+extern const int numFlagStrings;
+
+// Array of arraay pointers: for each compound flag, gives the list of
+// base flags to set. Inidividual flag arrays are terminated by -1.
+extern const Flags *compoundFlags[];
+
+/* namespace Trace */ }
+
+#endif // __BASE_TRACE_FLAGS_HH__
+''',
+
+hhfile.close()
+
+#
+#
+# Print out .cc file with array definitions.
+#
+#
+try:
+ ccfile = file(ccfilename, 'w')
+except OSError, e:
+ sys.exit("can't open %s: %s" % (ccfilename, e))
+
+# file header
+print >>ccfile, '''
+/*
+ * DO NOT EDIT THIS FILE!
+ *
+ * Automatically generated from traceflags.pl.
+ */
+
+#include "base/traceflags.hh"
+
+using namespace Trace;
+
+const char *Trace::flagStrings[] =
+{
+''',
+
+# The string array is used by SimpleEnumParam to map the strings
+# provided by the user to enum values.
+for flag in baseFlags:
+ print >>ccfile, ' "%s",' % flag
+
+for flag in compoundFlags:
+ print >>ccfile, ' "%s",' % flag
+
+print >>ccfile, '};\n'
+
+numFlagStrings = len(baseFlags) + len(compoundFlags);
+
+print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings
+print >>ccfile
+
+#
+# Now define the individual compound flag arrays. There is an array
+# for each compound flag listing the component base flags.
+#
+
+for flag in compoundFlags:
+ flags = compoundFlagMap[flag]
+ flags.append('(Flags)-1')
+ print >>ccfile, 'static const Flags %sMap[] =' % flag
+ print >>ccfile, '{ %s };' % (', '.join(flags))
+ print >>ccfile
+
+#
+# Finally the compoundFlags[] array maps the compound flags
+# to their individual arrays/
+#
+print >>ccfile, 'const Flags *Trace::compoundFlags[] ='
+print >>ccfile, '{'
+
+for flag in compoundFlags:
+ print >>ccfile, ' %sMap,' % flag
+
+# file trailer
+print >>ccfile, '};'
+
+ccfile.close()
+
diff --git a/src/base/userinfo.cc b/src/base/userinfo.cc
new file mode 100644
index 000000000..15bd72224
--- /dev/null
+++ b/src/base/userinfo.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <string>
+
+std::string
+username()
+{
+ struct passwd *pwd = getpwuid(getuid());
+
+ return pwd->pw_name;
+}
diff --git a/src/base/userinfo.hh b/src/base/userinfo.hh
new file mode 100644
index 000000000..d8ebd443c
--- /dev/null
+++ b/src/base/userinfo.hh
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_USERINFO_HH__
+#define __BASE_USERINFO_HH__
+
+#include <string>
+
+std::string username();
+
+#endif // __BASE_USERINFO_HH__