summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/bitfield.hh69
-rw-r--r--base/callback.hh56
-rw-r--r--base/circlebuf.cc187
-rw-r--r--base/circlebuf.hh59
-rw-r--r--base/cprintf.cc277
-rw-r--r--base/cprintf.hh197
-rw-r--r--base/cprintf_formats.hh354
-rw-r--r--base/date.cc29
-rw-r--r--base/dbl_list.hh165
-rw-r--r--base/endian.hh41
-rw-r--r--base/fast_alloc.cc191
-rw-r--r--base/fast_alloc.hh203
-rw-r--r--base/fifo_buffer.cc40
-rw-r--r--base/fifo_buffer.hh93
-rw-r--r--base/hashmap.hh83
-rw-r--r--base/inet.cc161
-rw-r--r--base/inet.hh37
-rw-r--r--base/inifile.cc437
-rw-r--r--base/inifile.hh111
-rw-r--r--base/intmath.cc58
-rw-r--r--base/intmath.h123
-rw-r--r--base/kgdb.h203
-rw-r--r--base/misc.cc97
-rw-r--r--base/misc.hh76
-rw-r--r--base/mod_num.hh201
-rw-r--r--base/object_file.cc173
-rw-r--r--base/object_file.hh92
-rw-r--r--base/pollevent.cc254
-rw-r--r--base/pollevent.hh89
-rw-r--r--base/random.cc79
-rw-r--r--base/random.hh100
-rw-r--r--base/range.hh260
-rw-r--r--base/refcnt.hh122
-rw-r--r--base/remote_gdb.cc1150
-rw-r--r--base/remote_gdb.hh189
-rw-r--r--base/res_list.hh756
-rw-r--r--base/sched_list.hh176
-rw-r--r--base/socket.cc114
-rw-r--r--base/socket.hh49
-rw-r--r--base/statistics.cc823
-rw-r--r--base/statistics.hh1682
-rw-r--r--base/str.cc332
-rw-r--r--base/str.hh127
-rw-r--r--base/symtab.cc133
-rw-r--r--base/symtab.hh59
-rw-r--r--base/trace.cc325
-rw-r--r--base/trace.hh218
47 files changed, 10850 insertions, 0 deletions
diff --git a/base/bitfield.hh b/base/bitfield.hh
new file mode 100644
index 000000000..ee5ea72cf
--- /dev/null
+++ b/base/bitfield.hh
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003 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 __BITFIELD_HH
+#define __BITFIELD_HH
+
+#include <inttypes.h>
+
+/**
+ * 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
diff --git a/base/callback.hh b/base/callback.hh
new file mode 100644
index 000000000..a1d23b5ed
--- /dev/null
+++ b/base/callback.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003 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>
+
+class Callback {
+ public:
+ virtual ~Callback() {}
+ virtual void process() = 0;
+};
+
+class CallbackQueue
+{
+ protected:
+ std::list<Callback *> callbacks;
+
+ public:
+ void add(Callback *callback) { callbacks.push_back(callback); }
+ bool empty() const { return callbacks.empty(); }
+ void processOne() {
+ Callback *c = callbacks.front();
+ callbacks.pop_front();
+ c->process();
+ }
+ void processAll() { while (!empty()) processOne(); }
+};
+
+#endif // __CALLBACK_HH__
diff --git a/base/circlebuf.cc b/base/circlebuf.cc
new file mode 100644
index 000000000..482c97f84
--- /dev/null
+++ b/base/circlebuf.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+#include "circlebuf.hh"
+#include "intmath.h"
+
+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::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/base/circlebuf.hh b/base/circlebuf.hh
new file mode 100644
index 000000000..e0abed31c
--- /dev/null
+++ b/base/circlebuf.hh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 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__
+
+
+class CircleBuf
+{
+protected:
+ char *buf;
+ bool rollover;
+ int buflen;
+ int size;
+ int start;
+ int stop;
+
+public:
+ explicit CircleBuf(int l);
+ ~CircleBuf();
+
+ bool empty() { return size == 0; }
+ void dump();
+ void flush();
+ void read(char *b, int len);
+ void read(int fd, int len);
+ void read(int fd);
+ 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/base/cprintf.cc b/base/cprintf.cc
new file mode 100644
index 000000000..be6e64f59
--- /dev/null
+++ b/base/cprintf.cc
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+
+using namespace std;
+
+namespace cp {
+
+void
+ArgList::dump(const string &format)
+{
+ const char *p = format.c_str();
+
+ stream->fill(' ');
+ stream->flags((ios::fmtflags)0);
+
+ Format fmt;
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ if (p[1] == '%') {
+ *stream << '%';
+ p += 2;
+ continue;
+ }
+
+ if (objects.empty())
+ format_invalid(*stream);
+
+ Base *data = objects.front();
+
+ fmt.clear();
+ 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;
+ }
+ }
+
+ ios::fmtflags saved_flags = stream->flags();
+ char old_fill = stream->fill();
+ int old_precision = stream->precision();
+
+ data->process(*stream, fmt);
+
+ stream->flags(saved_flags);
+ stream->fill(old_fill);
+ stream->precision(old_precision);
+
+ delete data;
+ objects.pop_front();
+ ++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;
+ }
+
+ ios::iostate state = stream->rdstate();
+ if (state) {
+#if 0
+ cout << "stream->rdstate() == " << state << endl;
+ if (state & ios::badbit)
+ cout << "stream is bad!\n";
+ if (state & ios::eofbit)
+ cout << "stream at eof!\n";
+ if (state & ios::failbit)
+ cout << "stream failed!\n";
+ if (state & ios::goodbit)
+ cout << "stream is good!!\n";
+#endif
+ stream->clear();
+ }
+ }
+
+ while (!objects.empty()) {
+ Base *data = objects.front();
+ data->process(*stream, fmt);
+ delete data;
+ objects.pop_front();
+ }
+}
+
+string
+ArgList::dumpToString(const string &format)
+{
+ stringstream ss;
+
+ dump(ss, format);
+
+ return ss.str();
+}
+
+}
diff --git a/base/cprintf.hh b/base/cprintf.hh
new file mode 100644
index 000000000..2dc84502a
--- /dev/null
+++ b/base/cprintf.hh
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003 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 <sstream>
+#include <string>
+
+namespace cp {
+
+#include "cprintf_formats.hh"
+
+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:
+ format_invalid(out);
+ break;
+ }
+ }
+ };
+
+ typedef std::list<Base *> list_t;
+
+ protected:
+ list_t objects;
+ std::ostream *stream;
+
+ public:
+ ArgList() : stream(&std::cout) {}
+
+ 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/base/cprintf_formats.hh b/base/cprintf_formats.hh
new file mode 100644
index 000000000..1e5de4fdf
--- /dev/null
+++ b/base/cprintf_formats.hh
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2003 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__
+
+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() { }
+ 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;
+ }
+};
+
+inline void
+format_invalid(std::ostream &out)
+{
+ using namespace std;
+
+ out << "format invalid!!!" << endl;
+}
+
+
+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)
+{ format_invalid(out); }
+
+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); }
+
+#if 0
+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); }
+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)
+{ format_invalid(out); }
+
+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); }
+
+#endif // __CPRINTF_FORMATS_HH__
diff --git a/base/date.cc b/base/date.cc
new file mode 100644
index 000000000..f961b9c21
--- /dev/null
+++ b/base/date.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2003 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/base/dbl_list.hh b/base/dbl_list.hh
new file mode 100644
index 000000000..4f6d61a45
--- /dev/null
+++ b/base/dbl_list.hh
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2003 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/base/endian.hh b/base/endian.hh
new file mode 100644
index 000000000..2877744ae
--- /dev/null
+++ b/base/endian.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 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/base/fast_alloc.cc b/base/fast_alloc.cc
new file mode 100644
index 000000000..290e59113
--- /dev/null
+++ b/base/fast_alloc.cc
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "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
diff --git a/base/fast_alloc.hh b/base/fast_alloc.hh
new file mode 100644
index 000000000..7d699abd1
--- /dev/null
+++ b/base/fast_alloc.hh
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2003 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
+
+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 // __FAST_ALLOC_H__
diff --git a/base/fifo_buffer.cc b/base/fifo_buffer.cc
new file mode 100644
index 000000000..d0b59e832
--- /dev/null
+++ b/base/fifo_buffer.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003 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 "fifo_buffer.hh"
+
+template<class T>
+void
+FifoBuffer<T>::dump(void)
+{
+ if (buffer->count() > 0)
+ for (iterator i=buffer->tail(); i.notnull(); i=i.prev())
+ i->dump();
+}
+
+
diff --git a/base/fifo_buffer.hh b/base/fifo_buffer.hh
new file mode 100644
index 000000000..27b4973ac
--- /dev/null
+++ b/base/fifo_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003 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 "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(void) { return buffer->head(); }
+ iterator tail(void) { return buffer->tail(); }
+
+ unsigned count(void) {return buffer->count();}
+ unsigned free_slots(void) {return buffer->num_free();}
+
+ T * peek(void)
+ {
+ if (count() > 0) {
+ return tail().data_ptr();
+ }
+ else {
+ return 0;
+ }
+ }
+
+ T remove(void)
+ {
+ assert(buffer->count() > 0);
+ T rval = *buffer->tail();
+ buffer->remove_tail();
+ return rval;
+ }
+
+ void dump(void);
+
+ ~FifoBuffer() { delete buffer; }
+};
+
+
+#endif
+
diff --git a/base/hashmap.hh b/base/hashmap.hh
new file mode 100644
index 000000000..21d4a818e
--- /dev/null
+++ b/base/hashmap.hh
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003 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 "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 {
+ template<>
+ struct hash<uint64_t> {
+ size_t operator()(uint64_t r) const {
+ return r;
+ }
+ };
+
+ template<>
+ struct hash<Counter> {
+ size_t operator()(Counter r) const {
+ return r;
+ };
+ };
+
+ 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/base/inet.cc b/base/inet.cc
new file mode 100644
index 000000000..33483bb32
--- /dev/null
+++ b/base/inet.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+#include "host.hh"
+#include "inet.hh"
+
+using namespace::std;
+string
+eaddr_string(const uint8_t a[6])
+{
+ stringstream stream;
+ ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
+
+ return stream.str();
+}
+
+/*
+ * 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.
+ */
+/***********************************************************************
+ This section of code taken from NetBSD
+***********************************************************************/
+
+#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);
+}
+
+/***********************************************************************
+ This is the end of the NetBSD code
+***********************************************************************/
diff --git a/base/inet.hh b/base/inet.hh
new file mode 100644
index 000000000..1c48d0730
--- /dev/null
+++ b/base/inet.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 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 __INET_HH__
+#define __INET_HH__
+
+#include "host.hh"
+
+uint32_t crc32be(const uint8_t *buf, size_t len);
+uint32_t crc32le(const uint8_t *buf, size_t len);
+std::string eaddr_string(const uint8_t a[6]);
+#endif // __INET_HH__
diff --git a/base/inifile.cc b/base/inifile.cc
new file mode 100644
index 000000000..3f80ec259
--- /dev/null
+++ b/base/inifile.cc
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2003 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
+// #define CPP_PIPE
+
+
+#ifdef USE_CPP
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <fstream>
+#include <iostream>
+#if __GNUC__ >= 3
+#include <ext/stdio_filebuf.h>
+#endif
+
+#include <vector>
+#include <string>
+
+#include "inifile.hh"
+#include "str.hh"
+
+using namespace std;
+
+IniFile::IniFile()
+{}
+
+IniFile::~IniFile()
+{
+ ConfigTable::iterator i = table.begin();
+ ConfigTable::iterator end = table.end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+
+#ifdef USE_CPP
+bool
+IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
+{
+ int fd[2];
+
+#ifdef CPP_PIPE
+ if (pipe(fd) == -1)
+ return false;
+#else
+ char tempfile[] = "/tmp/configXXXXXX";
+ fd[0] = fd[1] = mkstemp(tempfile);
+#endif
+
+ int pid = fork();
+
+ if (pid == -1)
+ return 1;
+
+ 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];
+
+ args[nextArg++] = filename;
+ args[nextArg++] = NULL;
+
+ close(STDOUT_FILENO);
+ if (dup2(fd[1], STDOUT_FILENO) == -1)
+ return 1;
+
+ execvp("g++", args);
+
+ exit(1);
+ }
+
+ int retval;
+ waitpid(pid, &retval, 0);
+
+ // check for normal completion of CPP
+ if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
+ return false;
+
+#ifdef CPP_PIPE
+ close(fd[1]);
+#else
+ lseek(fd[0], 0, SEEK_SET);
+#endif
+
+ bool status = false;
+
+#if __GNUC__ >= 3
+ using namespace __gnu_cxx;
+ stdio_filebuf<char> fbuf(fd[0], ios_base::in, true,
+ static_cast<stdio_filebuf<char>::int_type>(BUFSIZ));
+
+ if (fbuf.is_open()) {
+ istream f(&fbuf);
+ status = load(f);
+ }
+
+#else
+ ifstream f(fd[0]);
+ if (f.is_open())
+ status = load(f);
+#endif
+
+#ifndef CPP_PIPE
+ unlink(tempfile);
+#endif
+
+ 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)
+{
+ EntryTable::iterator ei = table.find(entryName);
+
+ if (ei == table.end()) {
+ // new entry
+ table[entryName] = new Entry(value);
+ }
+ else {
+ // override old entry
+ ei->second->setValue(value);
+ }
+}
+
+
+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)
+{
+ ConfigTable::iterator ci = table.find(sectionName);
+
+ if (ci != table.end()) {
+ return ci->second;
+ }
+ else {
+ // new entry
+ Section *sec = new Section();
+ table[sectionName] = sec;
+ return sec;
+ }
+}
+
+
+IniFile::Section *
+IniFile::findSection(const string &sectionName) const
+{
+ ConfigTable::const_iterator ci = table.find(sectionName);
+
+ return (ci == table.end()) ? NULL : ci->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);
+
+ offset = rest.find('=');
+ if (offset == string::npos) // no '='found
+ return false;
+
+ string entryName = rest.substr(0, offset);
+ string value = rest.substr(offset + 1);
+
+ eat_white(sectionName);
+ eat_white(entryName);
+ eat_white(value);
+
+ Section *s = addSection(sectionName);
+ s->addEntry(entryName, value);
+
+ return true;
+}
+
+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;
+
+ string::size_type offset = line.find('=');
+ string entryName = line.substr(0, offset);
+ string value = line.substr(offset + 1);
+
+ eat_white(entryName);
+ eat_white(value);
+
+ section->addEntry(entryName, value);
+ }
+
+ 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::findDefault(const string &_section, const string &entry,
+ string &value) const
+{
+ string section = _section;
+ while (!find(section, entry, value)) {
+ if (!find(section, "default", section))
+ return false;
+ }
+
+ return true;
+}
+
+
+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 (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ const string &sectionName = ci->first;
+ Section *section = ci->second;
+
+ if (!section->isReferenced()) {
+ if (section->findEntry("unref_section_ok") == NULL) {
+ cerr << "Section " << sectionName << " not referenced."
+ << endl;
+ unref = true;
+ }
+ }
+ else {
+#if 0
+ if (section->findEntry("unref_entries_ok") == NULL) {
+ bool unrefEntries = section->printUnreferenced(sectionName);
+ unref = unref || unrefEntries;
+ }
+#else
+ if (section->printUnreferenced(sectionName)) {
+ unref = true;
+ }
+#endif
+ }
+ }
+
+ 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 << "\n";
+ }
+}
+
+void
+IniFile::dump()
+{
+ for (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ ci->second->dump(ci->first);
+ }
+}
diff --git a/base/inifile.hh b/base/inifile.hh
new file mode 100644
index 000000000..b384fe21a
--- /dev/null
+++ b/base/inifile.hh
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003 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 "hashmap.hh"
+
+class IniFile
+{
+ protected:
+ class Entry
+ {
+ std::string value;
+ mutable bool referenced;
+
+ public:
+ Entry(const std::string &v)
+ : value(v), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ const std::string &getValue() const;
+
+ void setValue(const std::string &v) { value = v; }
+ };
+
+ class Section
+ {
+ typedef m5::hash_map<std::string, Entry *> EntryTable;
+
+ EntryTable table;
+ mutable bool referenced;
+
+ public:
+ Section()
+ : table(), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ void addEntry(const std::string &entryName, const std::string &value);
+ Entry *findEntry(const std::string &entryName) const;
+
+ bool printUnreferenced(const std::string &sectionName);
+ void dump(const std::string &sectionName);
+ };
+
+ typedef m5::hash_map<std::string, Section *> ConfigTable;
+
+ protected:
+ ConfigTable table;
+
+ Section *addSection(const std::string &sectionName);
+ Section *findSection(const std::string &sectionName) const;
+
+ bool load(std::istream &f);
+
+ public:
+ IniFile();
+ ~IniFile();
+
+ bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
+ bool load(const std::string &file);
+
+ bool add(const std::string &s);
+
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value) const;
+ bool findDefault(const std::string &section, const std::string &entry,
+ std::string &value) const;
+
+ bool printUnreferenced();
+
+ void dump();
+};
+
+#endif // __INIFILE_HH__
diff --git a/base/intmath.cc b/base/intmath.cc
new file mode 100644
index 000000000..8d08e59a8
--- /dev/null
+++ b/base/intmath.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 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 "intmath.h"
+
+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/base/intmath.h b/base/intmath.h
new file mode 100644
index 000000000..814dacd5f
--- /dev/null
+++ b/base/intmath.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003 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_H__
+#define __INTMATH_H__
+
+// Returns the prime number one less than n.
+int PrevPrime(int n);
+
+// Determine if a number is prime
+inline bool
+IsPrime(int n)
+{
+ int 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;
+}
+
+inline unsigned
+LeastSigBit(unsigned n)
+{ return n & ~(n - 1); }
+
+inline bool
+IsPowerOf2(unsigned n)
+{ return n != 0 && LeastSigBit(n) == n; }
+
+inline int
+FloorLog2(unsigned x)
+{
+ if (x == 0)
+ return -1;
+
+ 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
+CeilLog2(unsigned n)
+{ return FloorLog2(n-1)+1; }
+
+inline unsigned
+FloorPow2(unsigned n)
+{ return 1 << FloorLog2(n); }
+
+inline unsigned
+CeilPow2(unsigned n)
+{ return 1 << CeilLog2(n); }
+
+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_H__
diff --git a/base/kgdb.h b/base/kgdb.h
new file mode 100644
index 000000000..35f74f4ba
--- /dev/null
+++ b/base/kgdb.h
@@ -0,0 +1,203 @@
+/* $Id$ */
+/*
+ * 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
+
+/*
+ * MMCSR Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_MMCSR_INVALTRANS 0
+#define ALPHA_MMCSR_ACCESS 1
+#define ALPHA_MMCSR_FOR 2
+#define ALPHA_MMCSR_FOE 3
+#define ALPHA_MMCSR_FOW 4
+
+/*
+ * Instruction Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_IF_CODE_BPT 0
+#define ALPHA_IF_CODE_BUGCHK 1
+#define ALPHA_IF_CODE_GENTRAP 2
+#define ALPHA_IF_CODE_FEN 3
+#define ALPHA_IF_CODE_OPDEC 4
+
+#define BKPT_INST 0x00000080 // breakpoint instruction
+#define BKPT_SIZE (4) // size of breakpoint inst
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \
+ (code) == ALPHA_IF_CODE_BPT)
+#define IS_WATCHPOINT_TRAP(type, code) 0
+
+
+#endif /* __KGDB_H__ */
diff --git a/base/misc.cc b/base/misc.cc
new file mode 100644
index 000000000..0ce9f7be9
--- /dev/null
+++ b/base/misc.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003 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 "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "universe.hh"
+#include "trace.hh"
+
+using namespace std;
+
+void
+__panic(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "panic: " + format + " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+#if TRACING_ON
+ // dump trace buffer, if there is one
+ Trace::theLog.dump(cerr);
+#endif
+
+ abort();
+}
+
+void
+__fatal(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ long mem_usage();
+
+ string fmt = "fatal: " + format + " [%s:%s, line %d]\n"
+ "\n%d\nMemory Usage: %ld KBytes\n";
+
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.append(curTick);
+ args.append(mem_usage());
+ 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;
+#ifdef VERBOSE_WARN
+ fmt += " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+#else
+ fmt += "\n";
+#endif
+ args.dump(cerr, fmt);
+
+ delete &args;
+}
diff --git a/base/misc.hh b/base/misc.hh
new file mode 100644
index 000000000..3ac4d1491
--- /dev/null
+++ b/base/misc.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+
+//
+// This implements a cprintf based panic
+//
+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
+//
+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/base/mod_num.hh b/base/mod_num.hh
new file mode 100644
index 000000000..3b4ef9bb8
--- /dev/null
+++ b/base/mod_num.hh
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2003 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/base/object_file.cc b/base/object_file.cc
new file mode 100644
index 000000000..b9542f280
--- /dev/null
+++ b/base/object_file.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+#include "ecoff.hh"
+#include "object_file.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+ObjectFile::ObjectFile()
+ : descriptor(-1), data(NULL)
+{}
+
+ObjectFile::ObjectFile(string file)
+ : descriptor(-1), data(NULL)
+{ open(file); }
+
+ObjectFile::~ObjectFile()
+{ close(); }
+
+bool
+ObjectFile::open(string file_name)
+{
+ close();
+
+ name = file_name;
+
+ descriptor = ::open(name.c_str(), O_RDONLY);
+ if (descriptor < 0)
+ return false;
+
+ len = (size_t)::lseek(descriptor, 0, SEEK_END);
+
+ data = (uint8_t *)::mmap(NULL, len, PROT_READ, MAP_SHARED, descriptor, 0);
+ if (data == MAP_FAILED)
+ return false;
+
+ postOpen();
+
+ return true;
+}
+
+void
+ObjectFile::close()
+{
+ if (descriptor >= 0)
+ ::close(descriptor);
+
+ if (data)
+ ::munmap(data, len);
+}
+
+void
+EcoffObject::postOpen()
+{
+ exec = &(((EcoffExecHeader *)data)->f);
+ aout = &(((EcoffExecHeader *)data)->a);
+
+ text_off = aout->text_start;
+ data_off = aout->data_start;
+ bss_off = aout->bss_start;
+
+ text_size = aout->tsize;
+ data_size = aout->dsize;
+ bss_size = aout->bsize;
+}
+
+bool
+EcoffObject::loadGlobals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffExtSymEntry *ext_syms =
+ (EcoffExtSymEntry *)(data + syms->cbExtOffset);
+
+ char *ext_strings = (char *)(data + syms->cbSsExtOffset);
+ for (int i = 0; i < syms->iextMax; i++) {
+ EcoffSymEntry *entry = &(ext_syms[i].asym);
+ if (entry->iss != -1)
+ symtab->insert(entry->value, ext_strings + entry->iss);
+ }
+
+ return true;
+}
+
+bool
+EcoffObject::loadLocals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffSymEntry *local_syms = (EcoffSymEntry *)(data + syms->cbSymOffset);
+ char *local_strings = (char *)(data + syms->cbSsOffset);
+ EcoffFileDesc *fdesc = (EcoffFileDesc *)(data + syms->cbFdOffset);
+
+ for (int i = 0; i < syms->ifdMax; i++) {
+ EcoffSymEntry *entry =
+ (EcoffSymEntry *)(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 == 1 || entry[j].st == 6)
+ if (entry[j].iss != -1)
+ symtab->insert(entry[j].value, strings + entry[j].iss);
+ }
+ }
+
+ for (int i = 0; i < syms->isymMax; i++) {
+ EcoffSymEntry *entry = &(local_syms[i]);
+ if (entry->st == 6)
+ if (entry->st == 1 || entry->st == 6)
+ symtab->insert(entry->value, local_strings + entry->iss);
+ }
+
+ return true;
+}
diff --git a/base/object_file.hh b/base/object_file.hh
new file mode 100644
index 000000000..c100efc94
--- /dev/null
+++ b/base/object_file.hh
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2003 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 "ecoff.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable;
+
+class ObjectFile
+{
+ protected:
+ std::string name;
+ int descriptor;
+ uint8_t *data;
+ size_t len;
+
+ public:
+ ObjectFile();
+ explicit ObjectFile(std::string file);
+ virtual ~ObjectFile();
+
+ bool open(std::string file);
+ void close();
+
+ virtual bool loadGlobals(SymbolTable *symtab) = 0;
+ virtual bool loadLocals(SymbolTable *symtab) = 0;
+ virtual void postOpen() = 0;
+
+ protected:
+ Addr text_off;
+ Addr data_off;
+ Addr bss_off;
+
+ size_t text_size;
+ size_t data_size;
+ size_t bss_size;
+
+ public:
+ Addr textOffset() const { return text_off; }
+ Addr dataOffset() const { return data_off; }
+ Addr bssOffset() const { return bss_off; }
+
+ size_t textSize() const { return text_size; }
+ size_t dataSize() const { return data_size; }
+ size_t bssSize() const { return bss_size; }
+};
+
+class EcoffObject : public ObjectFile
+{
+ protected:
+ EcoffFileHeader *exec;
+ EcoffAOutHeader *aout;
+
+ public:
+ EcoffObject() {}
+ explicit EcoffObject(std::string file) { open(file); }
+ virtual ~EcoffObject() {}
+
+ virtual bool loadGlobals(SymbolTable *symtab);
+ virtual bool loadLocals(SymbolTable *symtab);
+ virtual void postOpen();
+};
+
+#endif // __OBJECT_FILE_HH__
diff --git a/base/pollevent.cc b/base/pollevent.cc
new file mode 100644
index 000000000..fd08d4c4c
--- /dev/null
+++ b/base/pollevent.cc
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2003 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 "async.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "pollevent.hh"
+#include "universe.hh"
+
+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();
+}
+
+/////////////////////////////////////////////////////
+//
+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 = 0;
+
+ if (sigaction(SIGIO, &act, &oldio) == -1)
+ panic("could not do sigaction");
+
+ act.sa_handler = handleALRM;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ 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/base/pollevent.hh b/base/pollevent.hh
new file mode 100644
index 000000000..57e12f549
--- /dev/null
+++ b/base/pollevent.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003 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 "universe.hh"
+
+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;
+};
+
+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/base/random.cc b/base/random.cc
new file mode 100644
index 000000000..42a169c06
--- /dev/null
+++ b/base/random.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2003 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 "param.hh"
+#include "random.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()
+{
+ ::srandom(seed);
+}
+
+long
+getLong()
+{
+ return random();
+}
+
+// idea for generating a double from erand48
+double
+getDouble()
+{
+ union {
+ uint32_t _long[2];
+ uint16_t _short[4];
+ };
+
+ _long[0] = random();
+ _long[1] = random();
+
+ return ldexp((double) _short[0], -48) +
+ ldexp((double) _short[1], -32) +
+ ldexp((double) _short[2], -16);
+}
diff --git a/base/random.hh b/base/random.hh
new file mode 100644
index 000000000..f1b383eda
--- /dev/null
+++ b/base/random.hh
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2003 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 __RANDOM_HH__
+#define __RANDOM_HH__
+
+#include "host.hh"
+
+long getLong();
+double getDouble();
+
+template <typename T>
+struct Random;
+
+struct Random<int8_t>
+{
+ static int8_t get()
+ { return getLong() & (int8_t)-1; }
+};
+
+struct Random<uint8_t>
+{
+ uint8_t get()
+ { return getLong() & (uint8_t)-1; }
+};
+
+struct Random<int16_t>
+{
+ int16_t get()
+ { return getLong() & (int16_t)-1; }
+};
+
+struct Random<uint16_t>
+{
+ uint16_t get()
+ { return getLong() & (uint16_t)-1; }
+};
+
+struct Random<int32_t>
+{
+ int32_t get()
+ { return (int32_t)getLong(); }
+};
+
+struct Random<uint32_t>
+{
+ uint32_t get()
+ { return (uint32_t)getLong(); }
+};
+
+struct Random<int64_t>
+{
+ int64_t get()
+ { return (int64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<uint64_t>
+{
+ uint64_t get()
+ { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<float>
+{
+ float get()
+ { return getDouble(); }
+};
+
+struct Random<double>
+{
+ double get()
+ { return getDouble(); }
+};
+
+#endif // __RANDOM_HH__
diff --git a/base/range.hh b/base/range.hh
new file mode 100644
index 000000000..254e71460
--- /dev/null
+++ b/base/range.hh
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2003 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 __RANGE_HH__
+#define __RANGE_HH__
+
+#include <assert.h>
+
+#include "str.hh"
+#include "intmath.h"
+
+template<class T>
+class Range
+{
+ private:
+ bool valid;
+
+ public:
+ T start;
+ T end;
+
+ public:
+ Range() {}
+
+ Range(const Range &r) { operator=(r); }
+
+ Range(const T& s, const T& e)
+ : start(s), end(e)
+ {
+ valid = (start <= end);
+ }
+
+ Range(const std::string &s) { valid = parse(s); }
+
+ ~Range() {}
+
+ int compare(const T &p);
+ bool parse(const std::string &s);
+ const Range &operator=(const Range &r);
+
+ bool isValid() const { return valid; }
+};
+
+
+template<class T>
+inline int
+Range<T>::compare(const T &p)
+{
+ assert(isValid());
+
+ if (p < start)
+ return -1;
+ else if (p > end)
+ return 1;
+ else
+ return 0;
+}
+
+// Parse a range string
+//
+// Ranges are in the following format:
+// <range> := {<start_val>}:{<end>}
+// <end> := <end_val> | +<delta>
+template<class T>
+inline bool
+Range<T>::parse(const std::string &str)
+{
+ std::vector<std::string> values;
+ tokenize(values, str, ':');
+
+ T thestart, theend;
+
+ if (values.size() != 2)
+ return false;
+
+ std::string s = values[0];
+ std::string e = values[1];
+
+ if (!to_number(s, thestart))
+ return false;
+
+ bool increment = (e[0] == '+');
+ if (increment)
+ e = e.substr(1);
+
+ if (!to_number(e, theend))
+ return false;
+
+ if (increment)
+ theend += thestart;
+
+ start = thestart;
+ end = theend;
+
+ if (start > end)
+ return false;
+
+ return true;
+}
+
+
+template<class T>
+inline const Range<T> &
+Range<T>::operator=(const Range<T> &r)
+{
+ if (this != &r) {
+ start = r.start;
+ end = r.end;
+
+ valid = r.valid;
+ }
+ else {
+ valid = false;
+ }
+
+ return *this;
+}
+
+template<class T>
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
+{
+ // don't currently support output of invalid ranges
+ assert(r.isValid());
+ o << r.start << ":" << r.end;
+ return o;
+}
+
+//////////////////////////////////////////
+//
+// Compare two ranges
+//
+template<class T>
+inline bool
+operator==(const Range<T> &l, const Range<T> &r)
+{
+ // ranges must both be valid to be equal
+ return (l.isValid() && r.isValid() &&
+ (l.start == r.start) && (l.end == r.end));
+}
+
+template<class T>
+inline bool
+operator!=(const Range<T> &l, const Range<T> &r)
+{
+ // for symmetry with ==, an invalid range is not equal to any other
+ return (!l.isValid() || !r.isValid() ||
+ (l.start != r.start) || (l.end != r.end));
+}
+
+//////////////////////////////////////////
+//
+// Compare position to a range
+//
+// - 'pos == range' indicates that position pos is within the given range.
+// This test always returns false if the range is invalid.
+//
+// - 'pos < range' and 'pos > range' indicate that the position is
+// before the start of or after the end of the range, respectively.
+// The range must be valid for these comparisons to be made.
+//
+// All other comparisons do the obvious thing based on these definitions.
+//
+//
+
+//
+// Basic comparisons
+//
+template<class T>
+inline bool
+operator==(const T &pos, const Range<T> &range)
+{ return range.isValid() && pos >= range.start && pos <= range.end; }
+
+template<class T>
+inline bool
+operator<(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos < range.start; }
+
+template<class T>
+inline bool
+operator>(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos > range.end; }
+
+//
+// Derived comparisons
+//
+template<class T>
+inline bool
+operator<=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos <= range.end; }
+
+template<class T>
+inline bool
+operator>=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos >= range.start; }
+
+template<class T>
+inline bool
+operator!=(const T &pos, const Range<T> &range)
+{ return !(pos == range); }
+
+//
+// Define symmetric comparisons based on above
+//
+template<class T>
+inline bool
+operator>(const Range<T> &range, const T &pos)
+{ return pos < range; }
+
+template<class T>
+inline bool
+operator<(const Range<T> &range, const T &pos)
+{ return pos > range; }
+
+template<class T>
+inline bool
+operator<=(const Range<T> &range, const T &pos)
+{ return pos >= range; }
+
+template<class T>
+inline bool
+operator>=(const Range<T> &range, const T &pos)
+{ return pos <= range; }
+
+template<class T>
+inline bool
+operator==(const Range<T> &range, const T &pos)
+{ return (pos == range); }
+
+template<class T>
+inline bool
+operator!=(const Range<T> &range, const T &pos)
+{ return (pos != range); }
+
+#endif // __RANGE_HH__
diff --git a/base/refcnt.hh b/base/refcnt.hh
new file mode 100644
index 000000000..5bc62ae23
--- /dev/null
+++ b/base/refcnt.hh
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003 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__
+
+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
+{
+ private:
+ T *data;
+
+ void copy(T *d) {
+ data = d;
+ if (data)
+ data->incref();
+ }
+ void del() {
+ if (data)
+ data->decref();
+ }
+
+ 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) {
+ if (data != p) {
+ del();
+ copy(p);
+ }
+ return *this;
+ }
+
+ RefCountingPtr &operator=(const RefCountingPtr& r) {
+ if (data != r.data) {
+ del();
+ copy(r.data);
+ }
+ return *this;
+ }
+
+ 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/base/remote_gdb.cc b/base/remote_gdb.cc
new file mode 100644
index 000000000..5a6987877
--- /dev/null
+++ b/base/remote_gdb.cc
@@ -0,0 +1,1150 @@
+/* $Id$ */
+/*
+ * 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 <unistd.h>
+
+#include <string>
+
+#include "exec_context.hh"
+#include "intmath.h"
+#include "kgdb.h"
+
+#include "physical_memory.hh"
+#include "remote_gdb.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+#ifdef DEBUG
+RemoteGDB *theDebugger = NULL;
+
+void
+debugger()
+{
+ if (theDebugger)
+ theDebugger->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)
+{}
+
+GDBListener::~GDBListener()
+{
+ if (event)
+ delete event;
+}
+
+void
+GDBListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(RGDB, "GDBListener(listen): Can't bind port %d\n", port);
+ port++;
+ }
+
+ cerr << "Listening for remote gdb connection on port " << port << endl;
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+}
+
+void
+GDBListener::accept()
+{
+ if (!listener.islistening())
+ panic("GDBListener(accept): cannot accept a connection 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)
+{ gdb->trap(ALPHA_KENTRY_IF); }
+
+RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+ : event(NULL), fd(-1), active(false), attached(false),
+ system(_system), pmem(_system->physmem), context(c)
+{
+#ifdef DEBUG
+ theDebugger = this;
+#endif
+ memset(gdbregs, 0, sizeof(gdbregs));
+}
+
+RemoteGDB::~RemoteGDB()
+{
+ if (event)
+ delete event;
+}
+
+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;
+ Addr pte;
+
+ va = alpha_trunc_page(va);
+ last_va = alpha_round_page(va + len);
+
+ do {
+ if (va < ALPHA_K0SEG_BASE) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n", va);
+ return false;
+ }
+
+ if (va < ALPHA_K1SEG_BASE) {
+ if (va < (ALPHA_K0SEG_BASE + pmem->getSize())) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is valid K0SEG <= "
+ "%#x < K0SEG + size\n", va);
+ return true;
+ } else {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n",
+ va);
+ return false;
+ }
+ }
+
+ Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20];
+ pte = kernel_pte_lookup(pmem, ptbr, va);
+ if (!pte || !entry_valid(pmem->phys_read_qword(pte))) {
+ DPRINTF(RGDB, "RGDB(acc): %#x pte is invalid\n", va);
+ return false;
+ }
+ va += ALPHA_PGBYTES;
+ } while (va < last_va);
+
+ DPRINTF(RGDB, "RGDB(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_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));
+ memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q,
+ 32 * sizeof(uint64_t));
+#endif
+ gdbregs[KGDB_REG_PC] = context->regs.pc;
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::setregs
+//
+// Translate the GDB register format into the kernel
+// debugger register format.
+//
+void
+RemoteGDB::setregs()
+{
+ memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0],
+ 32 * sizeof(uint64_t));
+#endif
+ context->regs.pc = gdbregs[KGDB_REG_PC];
+}
+
+void
+RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", addr);
+
+ bkpt.address = addr;
+ insertHardBreak(addr, 4);
+}
+
+void
+RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n",
+ bkpt.address);
+
+
+ removeHardBreak(bkpt.address, 4);
+ bkpt.address = 0;
+}
+
+void
+RemoteGDB::clearSingleStep()
+{
+ DPRINTF(RGDB, "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->regs.pc;
+ 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<TheISA> 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(RGDB, "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(RGDB, "RGDB(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(RGDB, "RGDB(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;
+
+ uint8_t *maddr;
+
+ if (vaddr < 10) {
+ DPRINTF(RGDB, "\nRGDB(read): reading memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ DPRINTF(RGDB, "RGDB(read): addr=%#x, size=%d", vaddr, size);
+#if TRACING_ON
+ char *d = data;
+ size_t s = size;
+#endif
+
+ lastaddr = vaddr;
+ lastsize = size;
+
+ size_t count = min((Addr)size,
+ VMPageSize - (vaddr & (VMPageSize - 1)));
+
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, count);
+
+ vaddr += count;
+ data += count;
+ size -= count;
+
+ while (size >= VMPageSize) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, VMPageSize);
+
+ vaddr += VMPageSize;
+ data += VMPageSize;
+ size -= VMPageSize;
+ }
+
+ if (size > 0) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, size);
+ }
+
+#if TRACING_ON
+ if (DTRACE(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, d, s);
+ cprintf(": %s\n", buf);
+ }
+#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;
+
+ uint8_t *maddr;
+
+ if (vaddr < 10) {
+ DPRINTF(RGDB, "RGDB(write): writing memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ if (DTRACE(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ cprintf("RGDB(write): addr=%#x, size=%d: %s\n", vaddr, size, buf);
+ }
+
+ lastaddr = vaddr;
+ lastsize = size;
+
+ size_t count = min((Addr)size,
+ VMPageSize - (vaddr & (VMPageSize - 1)));
+
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, data, count);
+
+ vaddr += count;
+ data += count;
+ size -= count;
+
+ while (size >= VMPageSize) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, data, VMPageSize);
+
+ vaddr += VMPageSize;
+ data += VMPageSize;
+ size -= VMPageSize;
+ }
+
+ if (size > 0) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, 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(RGDB, "creating hardware breakpoint at %#x\n", evpc);
+ schedule();
+}
+
+void
+RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+{
+ DPRINTF(RGDB, "handling hardware breakpoint at %#x\n", pc());
+
+ if (xc == gdb->context)
+ gdb->trap(ALPHA_KENTRY_IF);
+}
+
+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(RGDB, "inserting hardware breakpoint at %#x\n", addr);
+
+ HardBreakpoint *&bkpt = hardBreakMap[addr];
+ if (bkpt == 0)
+ bkpt = new HardBreakpoint(this, addr);
+
+ bkpt->refcount++;
+
+ return true;
+
+#if 0
+ break_iter_t i = hardBreakMap.find(addr);
+ if (i == hardBreakMap.end()) {
+ HardBreakpoint *bkpt = new HardBreakpoint(this, addr);
+ hardBreakMap[addr] = bkpt;
+ i = hardBreakMap.insert(make_pair(addr, bkpt));
+ if (i == hardBreakMap.end())
+ return false;
+ }
+
+ (*i).second->refcount++;
+#endif
+}
+
+bool
+RemoteGDB::removeHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(RGDB, "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(RGDB, "RGDB(trap): PC=%#x NPC=%#x\n",
+ context->regs.pc, context->regs.npc);
+
+ 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) {
+ if (!IS_BREAKPOINT_TRAP(type, 0)) {
+ // No debugger active -- let trap handle this.
+ return false;
+ }
+ active = true;
+ } else {
+ // Tell remote host that an exception has occurred.
+ sprintf((char *)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".
+ sprintf((char *)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->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_CONT:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_ASYNC_STEP:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_STEP:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = 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(RGDB, "kgdb: 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(RGDB, "kgdb: 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(RGDB, "kgdb: Unsupported command: %s\n",
+ gdb_command(command));
+ DDUMP(RGDB, (uint8_t *)data, datalen);
+ send("");
+ continue;
+
+ default:
+ // Unknown command.
+ DPRINTF(RGDB, "kgdb: 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/base/remote_gdb.hh b/base/remote_gdb.hh
new file mode 100644
index 000000000..315860ead
--- /dev/null
+++ b/base/remote_gdb.hh
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2003 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 "kgdb.h"
+#include "pc_event.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+
+class System;
+class ExecContext;
+class PhysicalMemory;
+
+class RemoteGDB
+{
+ 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;
+
+ 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 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:
+ HardBreakpoint(RemoteGDB *_gdb, Addr addr);
+
+ int refcount;
+ 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);
+};
+
+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();
+};
+
+#endif /* __REMOTE_GDB_H__ */
diff --git a/base/res_list.hh b/base/res_list.hh
new file mode 100644
index 000000000..b5eb209c9
--- /dev/null
+++ b/base/res_list.hh
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2003 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 "cprintf.hh"
+#include "std_types.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)
+ 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/base/sched_list.hh b/base/sched_list.hh
new file mode 100644
index 000000000..f5b90f571
--- /dev/null
+++ b/base/sched_list.hh
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2003 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 "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 (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>
+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/base/socket.cc b/base/socket.cc
new file mode 100644
index 000000000..00fdf1ba3
--- /dev/null
+++ b/base/socket.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2003 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 "host.hh"
+#include "misc.hh"
+#include "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!");
+
+ 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;
+}
+
+#if !defined(__OpenBSD__) && !defined(linux)
+typedef int socklen_t;
+#endif
+
+// 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/base/socket.hh b/base/socket.hh
new file mode 100644
index 000000000..39bacba94
--- /dev/null
+++ b/base/socket.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003 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/base/statistics.cc b/base/statistics.cc
new file mode 100644
index 000000000..1e8cd2565
--- /dev/null
+++ b/base/statistics.cc
@@ -0,0 +1,823 @@
+/*
+ * Copyright (c) 2003 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 <iostream>
+#include <list>
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <math.h>
+
+#include "cprintf.hh"
+#include "intmath.h"
+#include "misc.hh"
+#include "statistics.hh"
+#include "str.hh"
+#include "universe.hh"
+
+#ifdef __M5_NAN
+float
+__nan()
+{
+ union {
+ uint32_t ui;
+ float f;
+ } nan;
+
+ nan.ui = 0x7fc00000;
+ return nan.f;
+}
+#endif
+
+#ifdef STAT_DEBUG
+static int total_stats = 0;
+#endif
+
+using namespace std;
+
+// This is a hack to get this parameter from the old stats package.
+namespace Statistics {
+bool PrintDescriptions = true;
+
+namespace Detail {
+struct SubData
+{
+ string name;
+ string desc;
+};
+
+struct StatData
+{
+ StatData();
+ ~StatData();
+
+ bool init;
+ bool print;
+ string name;
+ vector<SubData> *subdata;
+ string desc;
+ int precision;
+ FormatFlags flags;
+ const Stat *prereq;
+};
+
+StatData::StatData()
+ : init(false), print(false), subdata(NULL), precision(-1), flags(none),
+ prereq(NULL)
+{
+}
+
+StatData::~StatData()
+{
+ if (subdata)
+ delete subdata;
+}
+
+class Database
+{
+ private:
+ Database(const Database &) {}
+
+ private:
+ typedef list<Stat *> list_t;
+ typedef map<const Stat *, StatData *> map_t;
+
+ list_t allStats;
+ list_t printStats;
+ map_t map;
+
+ public:
+ Database();
+ ~Database();
+
+ void dump(ostream &stream);
+
+ StatData *find(const Stat *stat);
+ void check();
+ void regStat(Stat *stat);
+ StatData *print(Stat *stat);
+};
+
+Database::Database()
+{}
+
+Database::~Database()
+{}
+
+void
+Database::dump(ostream &stream)
+{
+ list_t::iterator i = printStats.begin();
+ list_t::iterator end = printStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ if (stat->dodisplay())
+ stat->display(stream);
+ ++i;
+ }
+}
+
+StatData *
+Database::find(const Stat *stat)
+{
+ map_t::const_iterator i = map.find(stat);
+
+ if (i == map.end())
+ return NULL;
+
+ return (*i).second;
+}
+
+void
+Database::check()
+{
+ list_t::iterator i = allStats.begin();
+ list_t::iterator end = allStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ StatData *data = find(stat);
+ if (!data || !data->init) {
+#ifdef STAT_DEBUG
+ cprintf("this is stat number %d\n",(*i)->number);
+#endif
+ panic("Not all stats have been initialized");
+ }
+
+ if (data->print) {
+ if (data->name.empty())
+ panic("all printable stats must be named");
+
+ list_t::iterator j = printStats.insert(printStats.end(), *i);
+ inplace_merge(printStats.begin(), j,
+ printStats.end(), Stat::less);
+ }
+
+ ++i;
+ }
+}
+
+void
+Database::regStat(Stat *stat)
+{
+ if (map.find(stat) != map.end())
+ panic("shouldn't register stat twice!");
+
+ allStats.push_back(stat);
+
+ StatData *data = new StatData;
+ bool success = (map.insert(make_pair(stat, data))).second;
+ assert(map.find(stat) != map.end());
+ assert(success && "this should never fail");
+}
+
+bool
+Stat::less(Stat *stat1, Stat *stat2)
+{
+ const string &name1 = stat1->myname();
+ const string &name2 = stat2->myname();
+
+ 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;
+}
+
+StatData *
+Database::print(Stat *stat)
+{
+ StatData *data = find(stat);
+ assert(data);
+
+ data->print = true;
+
+ return data;
+}
+
+Database &
+StatDB()
+{
+ static Database db;
+ return db;
+}
+
+Stat::Stat(bool reg)
+{
+#if 0
+ // This assert can help you find that pesky stat.
+ assert(this != (void *)0xbffff5c0);
+#endif
+
+ if (reg)
+ StatDB().regStat(this);
+#ifdef STAT_DEBUG
+ number = ++total_stats;
+ cprintf("I'm stat number %d\n",number);
+#endif
+}
+
+void
+Stat::setInit()
+{ mydata()->init = true; }
+
+StatData *
+Stat::mydata()
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const StatData *
+Stat::mydata() const
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const SubData *
+Stat::mysubdata(int index) const
+{
+ assert(index >= 0);
+ if (index >= size())
+ return NULL;
+
+ const StatData *data = this->mydata();
+ if (!data->subdata || data->subdata->size() <= index)
+ return NULL;
+
+ return &(*data->subdata)[index];
+}
+
+SubData *
+Stat::mysubdata_create(int index)
+{
+ int size = this->size();
+ assert(index >= 0 && (size == 0 || size > 0 && index < size));
+
+ StatData *data = this->mydata();
+ if (!data->subdata) {
+ if (!data->subdata) {
+ if (size == 0)
+ size = index + 1;
+
+ data->subdata = new vector<SubData>(size);
+ }
+ } else if (data->subdata->size() <= index)
+ data->subdata->resize(index + 1);
+
+ SubData *sd = &(*data->subdata)[index];
+ assert(sd);
+
+ return sd;
+}
+
+string
+Stat::myname() const
+{ return mydata()->name; }
+
+string
+Stat::mysubname(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->name : "";
+}
+
+string
+Stat::mydesc() const
+{ return mydata()->desc; }
+
+string
+Stat::mysubdesc(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->desc : "";
+}
+
+int
+Stat::myprecision() const
+{ return mydata()->precision; }
+
+FormatFlags
+Stat::myflags() const
+{ return mydata()->flags; }
+
+bool
+Stat::dodisplay() const
+{ return !mydata()->prereq || !mydata()->prereq->zero(); }
+
+StatData *
+Stat::print()
+{
+ StatData *data = StatDB().print(this);
+ assert(data && data->init);
+
+ return data;
+}
+
+Stat &
+Stat::name(const string &name)
+{
+ print()->name = name;
+ return *this;
+}
+
+Stat &
+Stat::desc(const string &desc)
+{
+ print()->desc = desc;
+ return *this;
+}
+
+Stat &
+Stat::precision(int precision)
+{
+ print()->precision = precision;
+ return *this;
+}
+
+Stat &
+Stat::flags(FormatFlags flags)
+{
+ if (flags & __reserved)
+ panic("Cannot set reserved flags!\n");
+
+ print()->flags |= flags;
+ return *this;
+}
+
+Stat &
+Stat::prereq(const Stat &prereq)
+{
+ print()->prereq = &prereq;
+ return *this;
+}
+
+Stat &
+Stat::subname(int index, const string &name)
+{
+ print();
+ mysubdata_create(index)->name = name;
+ return *this;
+}
+Stat &
+Stat::subdesc(int index, const string &desc)
+{
+ print();
+ mysubdata_create(index)->desc = desc;
+ return *this;
+}
+
+bool
+ScalarStat::zero() const
+{
+ return val() == 0.0;
+}
+
+bool
+VectorStat::zero() const
+{
+ return val()[0] == 0.0;
+}
+
+string
+ValueToString(result_t value, int precision)
+{
+ 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 {
+#ifndef STAT_DISPLAY_COMPAT
+ val << "no value";
+#else
+ val << "<err: div-0>";
+#endif
+ }
+
+ return val.str();
+}
+
+void
+PrintOne(ostream &stream, result_t value,
+ const string &name, const string &desc, int precision,
+ FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
+{
+ 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);
+
+#ifdef STAT_DISPLAY_COMPAT
+ if (flags & __substat) {
+ ccprintf(stream, "%32s%12s%10s%10s", name,
+ ValueToString(value, precision),
+ pdfstr, cdfstr);
+ } else
+#endif
+ {
+ ccprintf(stream, "%-40s%12s%10s%10s", name,
+ ValueToString(value, precision), pdfstr, cdfstr);
+ }
+
+ if (PrintDescriptions) {
+ if (!desc.empty())
+ ccprintf(stream, " # %s", desc);
+ }
+ stream << endl;
+}
+
+void
+ScalarStat::display(ostream &stream) const
+{
+ PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
+}
+
+void
+VectorStat::display(ostream &stream) const
+{
+ bool have_subname = false;
+ bool have_subdesc = false;
+ int size = this->size();
+ for (int i = 0; i < size; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ if (!mysubdesc(i).empty())
+ have_subdesc = true;
+ }
+
+ vector<string> *subnames = 0;
+ vector<string> *subdescs = 0;
+ if (have_subname) {
+ subnames = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subnames)[i] = mysubname(i);
+ }
+ if (have_subdesc) {
+ subdescs = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subdescs)[i] = mysubdesc(i);
+ }
+
+ VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
+ myprecision(), myflags(), val(), total());
+}
+
+#ifndef STAT_DISPLAY_COMPAT
+#define NAMESEP "::"
+#else
+#define NAMESEP "_"
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf))
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
+ else {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
+ _pdf, _cdf);
+ }
+ }
+
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname + NAMESEP + "total",
+ mydesc, myprecision, myflags);
+ }
+}
+#else
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
+
+ if (myflags & dist) {
+ ccprintf(stream, "%s.start_dist\n", myname);
+ for (int i = 0; i < _size; ++i) {
+ string subname, subdesc;
+ subname = to_string(i);
+ if (mysubnames) {
+ if (!subname.empty()) {
+ subname = (*mysubnames)[i];
+ }
+ }
+ if (mysubdescs) {
+ subdesc = (*mysubdescs)[i];
+ }
+ if (!(myflags & (pdf | cdf))) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ if (!(myflags & cdf)) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf);
+ } else {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf, _cdf);
+ }
+ }
+ }
+ ccprintf(stream, "%s.end_dist\n", myname);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf)) {
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags, _pdf, _cdf);
+ }
+ }
+ }
+ }
+}
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size);
+{
+ assert(size == vec.size());
+
+ result_t total = 0.0;
+ result_t pdf, cdf = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ pdf = underflow / total;
+ cdf += pdf;
+
+ PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
+ precision, myflags, pdf, cdf);
+
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ namestr << name;
+
+ int low = i * bucket_size + min;
+ int high = ::std::min((i + 1) * bucket_size + min - 1, max);
+ namestr << low;
+ if (low < high)
+ namestr << "-" << high;
+
+ pdf = vec[i] / total;
+ cdf += pdf;
+ PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
+ pdf, cdf);
+ }
+
+ pdf = overflow / total;
+ cdf += pdf;
+ PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
+ precision, myflags, pdf, cdf);
+ PrintOne(stream, total, name + NAMESEP + "total", desc,
+ precision, myflags);
+}
+#else
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size)
+{
+ assert(size == vec.size());
+ string blank;
+
+ result_t total = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ ccprintf(stream, "%-42s", name + ".start_dist");
+ if (PrintDescriptions && !desc.empty())
+ ccprintf(stream, " # %s", desc);
+ stream << endl;
+
+ PrintOne(stream, total, name + ".samples", blank, precision, flags);
+ PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
+
+ if (underflow > 0)
+ PrintOne(stream, min_val, name + ".underflows", blank, precision,
+ flags);
+
+ int _min;
+ result_t _pdf, _cdf, mypdf, mycdf;
+
+ _cdf = 0.0;
+ for (int i = 0; i < size; ++i) {
+ if (flags & nozero && vec[i] == 0.0 ||
+ flags & nonan && isnan(vec[i]))
+ return;
+
+ _min = i * bucket_size + min;
+ _pdf = vec[i] / total * 100.0;
+ _cdf += _pdf;
+
+ mypdf = (flags & pdf) ? _pdf : NAN;
+ mycdf = (flags & cdf) ? _cdf : NAN;
+
+ PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
+ flags | __substat, mypdf, mycdf);
+ }
+
+ if (overflow > 0)
+ PrintOne(stream, overflow, name + ".overflows", blank, precision,
+ flags);
+ PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
+ ccprintf(stream, "%s.end_dist\n\n", name);
+}
+#endif
+
+void
+FancyDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags, result_t mean,
+ result_t variance)
+{
+ result_t stdev = isnan(variance) ? NAN : sqrt(variance);
+ PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
+ PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
+}
+
+BinBase::BinBase(size_t size)
+ : memsize(CeilPow2(size)), mem(NULL)
+{
+}
+
+BinBase::~BinBase()
+{
+ if (mem)
+ delete [] mem;
+}
+
+char *
+BinBase::memory()
+{
+ if (!mem) {
+ mem = new char[memsize];
+ memset(mem, 0, memsize);
+ }
+
+ return mem;
+}
+
+} // namespace Detail
+
+void
+check()
+{
+ Detail::StatDB().check();
+}
+
+void
+dump(ostream &stream)
+{
+ Detail::StatDB().dump(stream);
+}
+
+} // namespace Statistics
diff --git a/base/statistics.hh b/base/statistics.hh
new file mode 100644
index 000000000..3d9d654ed
--- /dev/null
+++ b/base/statistics.hh
@@ -0,0 +1,1682 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/*
+ * @todo
+ *
+ * Generalized N-dimensinal vector
+ * documentation
+ * fix AvgStor
+ * key stats
+ * interval stats
+ * -- these both can use the same function that prints out a
+ * specific set of stats
+ * VectorStandardDeviation totals
+ *
+ */
+#ifndef __STATISTICS_HH__
+#define __STATISTICS_HH__
+
+#include <algorithm>
+#include <functional>
+#include <iosfwd>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <assert.h>
+
+#include "host.hh"
+#include "refcnt.hh"
+#include "str.hh"
+
+#ifndef NAN
+float __nan();
+#define NAN (__nan())
+#define __M5_NAN
+#endif
+
+#define STAT_DISPLAY_COMPAT
+
+extern Tick curTick;
+
+namespace Statistics {
+typedef double result_t;
+typedef std::vector<result_t> rvec_t;
+
+typedef u_int32_t FormatFlags;
+const FormatFlags none = 0x0000;
+const FormatFlags total = 0x0001;
+const FormatFlags pdf = 0x0002;
+const FormatFlags nozero = 0x0004;
+const FormatFlags nonan = 0x0008;
+const FormatFlags cdf = 0x0010;
+const FormatFlags dist = 0x0020;
+const FormatFlags __substat = 0x8000;
+const FormatFlags __reserved = __substat;
+
+namespace Detail {
+//////////////////////////////////////////////////////////////////////
+//
+// Statistics Framework Base classes
+//
+//////////////////////////////////////////////////////////////////////
+struct StatData;
+struct SubData;
+
+class Stat
+{
+ protected:
+ void setInit();
+ StatData *mydata();
+ const StatData *mydata() const;
+ StatData *print();
+ const SubData *mysubdata(int index) const;
+ SubData *mysubdata_create(int index);
+
+ public:
+ virtual std::string myname() const;
+ virtual std::string mysubname(int index) const;
+ virtual std::string mydesc() const;
+ virtual std::string mysubdesc(int index) const;
+ virtual FormatFlags myflags() const;
+ virtual bool dodisplay() const;
+ virtual int myprecision() const;
+
+ public:
+ Stat(bool reg);
+ virtual ~Stat() {}
+
+ virtual void display(std::ostream &stream) const = 0;
+ virtual size_t size() const = 0;
+ virtual bool zero() const = 0;
+
+ Stat &name(const std::string &name);
+ Stat &desc(const std::string &desc);
+ Stat &precision(int p);
+ Stat &flags(FormatFlags f);
+ Stat &prereq(const Stat &prereq);
+ Stat &subname(int index, const std::string &name);
+ Stat &subdesc(int index, const std::string &name);
+
+ public:
+ static bool less(Stat *stat1, Stat *stat2);
+
+#ifdef STAT_DEBUG
+ int number;
+#endif
+};
+
+// Scalar stats involved in formulas
+class ScalarStat : public Stat
+{
+ public:
+ ScalarStat(bool reg) : Stat(reg) {}
+ virtual result_t val() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+void
+VectorDisplay(std::ostream &stream, const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags, const rvec_t &vec,
+ result_t mytotal);
+
+// Vector stats involved in formulas
+class VectorStat : public Stat
+{
+ public:
+ VectorStat(bool reg) : Stat(reg) {}
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Simple Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T>
+struct StatStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T data;
+
+ public:
+ StatStor(const Params &) : data(T()) {}
+
+ void set(T val, const Params &p) { data = val; }
+ void inc(T val, const Params &p) { data += val; }
+ void dec(T val, const Params &p) { data -= val; }
+ result_t val(const Params &p) const { return (result_t)data; }
+ T value(const Params &p) const { return data; }
+};
+
+template <typename T>
+struct AvgStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T current;
+ mutable result_t total;
+ mutable Tick last;
+
+ public:
+ AvgStor(const Params &) : current(T()), total(0), last(0) { }
+
+ void set(T val, const Params &p) {
+ total += current * (curTick - last);
+ last = curTick;
+ current = val;
+ }
+ void inc(T val, const Params &p) { set(current + val, p); }
+ void dec(T val, const Params &p) { set(current - val, p); }
+ result_t val(const Params &p) const {
+ total += current * (curTick - last);
+ last = curTick;
+ return (result_t)(total + current) / (result_t)(curTick + 1);
+ }
+ T value(const Params &p) const { return current; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarBase : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ ScalarBase(const ScalarBase &stat);
+ const ScalarBase &operator=(const ScalarBase &);
+
+ public:
+ result_t val() const { return data()->val(params); }
+ T value() const { return data()->value(params); }
+
+ public:
+ ScalarBase() : ScalarStat(true) {
+ bin.init(params);
+ setInit();
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, params); }
+ void operator--() { data()->dec(1, params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Vector Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorBase : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ mutable rvec_t *vec;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorBase(const VectorBase &stat);
+ const VectorBase &operator=(const VectorBase &);
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(params);
+ return total;
+ }
+
+ public:
+ VectorBase() : VectorStat(true), vec(NULL) {}
+ ~VectorBase() { if (vec) delete vec; }
+
+ VectorBase &init(size_t size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+
+ friend class ScalarProxy<T, Storage, Bin>;
+ ScalarProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int index;
+
+ protected:
+ storage_t *data() { return bin->data(index, *params); }
+ const storage_t *data() const { return bin->data(index, *params); }
+
+ public:
+ result_t val() const { return data()->val(*params); }
+ T value() const { return data()->value(*params); }
+
+ public:
+ ScalarProxy(bin_t &b, params_t &p, int i)
+ : ScalarStat(false), bin(&b), params(&p), index(i) {}
+ ScalarProxy(const ScalarProxy &sp)
+ : ScalarStat(false), bin(sp.bin), params(sp.params), index(sp.index) {}
+ const ScalarProxy &operator=(const ScalarProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ index = sp.index;
+ return *this;
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, *params); }
+ void operator--() { data()->dec(1, *params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, *params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, *params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, *params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline ScalarProxy<T, Storage, Bin>
+VectorBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(bin, params, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class Vector2dBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ size_t x;
+ size_t y;
+ bin_t bin;
+ params_t params;
+ std::vector<std::string> *y_subnames;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ Vector2dBase(const Vector2dBase &stat);
+ const Vector2dBase &operator=(const Vector2dBase &);
+
+ public:
+ Vector2dBase() : Stat(true) {}
+ ~Vector2dBase() { }
+
+ Vector2dBase &init(size_t _x, size_t _y) {
+ x = _x;
+ y = _y;
+ bin.init(x * y, params);
+ setInit();
+ y_subnames = new std::vector<std::string>(y);
+
+ return *this;
+ }
+
+ /**
+ * This makes the assumption that if you're gonna subnames a 2d vector,
+ * you're subnaming across all y
+ */
+ Vector2dBase &ysubnames(const char **names)
+ {
+ for (int i=0; i < y; ++i) {
+ (*y_subnames)[i] = names[i];
+ }
+ return *this;
+ }
+ Vector2dBase &ysubname(int index, const std::string subname)
+ {
+ (*y_subnames)[i] = subname.c_str();
+ return *this;
+ }
+ std::string ysubname(int i) const { return (*y_subnames)[i]; }
+
+ friend class VectorProxy<T, Storage, Bin>;
+ VectorProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return data(0)->value(params) == 0.0; }
+
+ virtual void
+ display(std::ostream &out) const
+ {
+ bool have_subname = false;
+ for (int i = 0; i < x; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ }
+
+ rvec_t tot_vec(y);
+ result_t super_total = 0.0;
+ for (int i = 0; i < x; ++i) {
+ std::string subname;
+ if (have_subname) {
+ subname = mysubname(i);
+ if (subname.empty())
+ continue;
+ } else
+ subname = to_string(i);
+
+ int iy = i * y;
+ rvec_t vec(y);
+
+ result_t total = 0.0;
+ for (int j = 0; j < y; ++j) {
+ vec[j] = data(iy + j)->val(params);
+ tot_vec[j] += vec[j];
+ total += vec[j];
+ super_total += vec[j];
+ }
+
+ std::string desc;
+ if (mysubdesc(i).empty()) {
+ desc = mydesc();
+ } else {
+ desc = mysubdesc(i);
+ }
+
+ VectorDisplay(out, myname() + "_" + subname, y_subnames, desc, 0,
+ myprecision(), myflags(), vec, total);
+
+ }
+ if ((myflags() & ::Statistics::total) && (x > 1)) {
+ VectorDisplay(out, myname(), y_subnames, mydesc(), 0,
+ myprecision(), myflags(), tot_vec, super_total);
+
+ }
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int offset;
+ int len;
+
+ private:
+ mutable rvec_t *vec;
+
+ storage_t *data(int index) {
+ assert(index < len);
+ return bin->data(offset + index, *params);
+ }
+
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(bin))->data(offset + index, *params);
+ }
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(*params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(*params);
+ return total;
+ }
+
+ public:
+ VectorProxy(bin_t &b, params_t &p, int o, int l)
+ : VectorStat(false), bin(&b), params(&p), offset(o), len(l), vec(NULL)
+ { }
+ VectorProxy(const VectorProxy &sp)
+ : VectorStat(false), bin(sp.bin), params(sp.params), offset(sp.offset),
+ len(sp.len), 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;
+ if (vec)
+ delete vec;
+ vec = NULL;
+ return *this;
+ }
+
+ virtual size_t size() const { return len; }
+
+ ScalarProxy<T, Storage, Bin> operator[](int index) {
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(*bin, *params, offset + index);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorProxy<T, Storage, Bin>
+Vector2dBase<T, Storage, Bin>::operator[](int index)
+{
+ int offset = index * y;
+ assert (index >= 0 && offset < size());
+ return VectorProxy<T, Storage, Bin>(bin, params, offset, y);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Non formula statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+void DistDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size,
+ int size);
+
+template <typename T>
+struct DistStor
+{
+ public:
+ struct Params
+ {
+ int min;
+ int max;
+ int bucket_size;
+ int size;
+ };
+
+ private:
+ T min_val;
+ T max_val;
+ T underflow;
+ T overflow;
+ std::vector<T> vec;
+
+ public:
+ DistStor(const Params &params)
+ : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0),
+ vec(params.size) {
+ }
+ void sample(T val, int number, const Params &params) {
+ if (val < params.min)
+ underflow += number;
+ else if (val > params.max)
+ overflow += number;
+ else {
+ int index = (val - params.min) / params.bucket_size;
+ assert(index < size(params));
+ vec[index] += number;
+ }
+
+ if (val < min_val)
+ min_val = val;
+
+ if (val > max_val)
+ max_val = val;
+ }
+
+ size_t size(const Params &) const { return vec.size(); }
+
+ bool zero(const Params &params) const {
+ if (underflow != 0 || overflow != 0)
+ return true;
+
+ int s = size(params);
+ for (int i = 0; i < s; i++)
+ if (vec[i] != 0)
+ return true;
+
+ return false;
+ }
+
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+
+#ifdef STAT_DISPLAY_COMPAT
+ result_t min = params.min;
+#else
+ result_t min = (min_val == INT_MAX) ? params.min : min_val;
+#endif
+ result_t max = (max_val == INT_MIN) ? 0 : max_val;
+
+ rvec_t rvec(params.size);
+ for (int i = 0; i < params.size; ++i)
+ rvec[i] = vec[i];
+
+ DistDisplay(stream, name, desc, precision, flags,
+ (result_t)min, (result_t)max,
+ (result_t)underflow, (result_t)overflow,
+ rvec, params.min, params.max, params.bucket_size,
+ params.size);
+ }
+};
+
+void FancyDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t mean, result_t variance);
+template <typename T>
+struct FancyStor
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+ int total;
+
+ public:
+ FancyStor(const Params &) : sum(0), squares(0), total(0) {}
+
+ void sample(T val, int number, const Params &) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ total += number;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &) const {
+
+ result_t mean = NAN;
+ result_t variance = NAN;
+
+ if (total != 0) {
+ result_t fsum = sum;
+ result_t fsq = squares;
+ result_t ftot = total;
+
+ mean = fsum / ftot;
+ variance = (ftot * fsq - (fsum * fsum)) / (ftot * (ftot - 1.0));
+ }
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &) const { return 1; }
+ bool zero(const Params &) const { return total == 0; }
+};
+
+template <typename T>
+struct AvgFancy
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+
+ public:
+ AvgFancy(const Params &) : sum(0), squares(0) {}
+
+ void sample(T val, int number, const Params& p) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+ result_t mean = sum / curTick;
+ result_t variance = (squares - sum * sum) / curTick;
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &params) const { return 1; }
+ bool zero(const Params &params) const { return sum == 0; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class DistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ DistBase(const DistBase &stat);
+ const DistBase &operator=(const DistBase &);
+
+ public:
+ DistBase() : Stat(true) { }
+ ~DistBase() { }
+
+ template <typename U>
+ void sample(const U& v, int n = 1) { data()->sample(v, n, params); }
+
+ virtual size_t size() const { return data()->size(params); }
+ virtual bool zero() const { return data()->zero(params); }
+ virtual void display(std::ostream &stream) const {
+ data()->display(stream, myname(), mydesc(), myprecision(), myflags(),
+ params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorDistBase(const VectorDistBase &stat);
+ const VectorDistBase &operator=(const VectorDistBase &);
+
+ public:
+ VectorDistBase() : Stat(true) { }
+ ~VectorDistBase() { }
+
+ friend class VectorDistProxy<T, Storage, Bin>;
+ VectorDistProxy<T, Storage, Bin> operator[](int index);
+ const VectorDistProxy<T, Storage, Bin> operator[](int index) const;
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return false; }
+ virtual void display(std::ostream &stream) const;
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+ typedef VectorDistBase<T, Storage, Bin> base_t;
+
+ private:
+ union {
+ base_t *stat;
+ const base_t *cstat;
+ };
+ int index;
+
+ protected:
+ storage_t *data() { return stat->data(index); }
+ const storage_t *data() const { return cstat->data(index); }
+
+ public:
+ VectorDistProxy(const VectorDistBase<T, Storage, Bin> &s, int i)
+ : Stat(false), cstat(&s), index(i) {}
+ VectorDistProxy(const VectorDistProxy &sp)
+ : Stat(false), cstat(sp.cstat), index(sp.index) {}
+ const VectorDistProxy &operator=(const VectorDistProxy &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); }
+
+ virtual size_t size() const { return 1; }
+ virtual bool zero() const {
+ return data()->zero(cstat->params);
+ }
+ virtual void display(std::ostream &stream) const {
+ std::stringstream name, desc;
+
+ if (!(cstat->mysubname(index).empty())) {
+ name << cstat->myname() << cstat->mysubname(index);
+ } else {
+ name << cstat->myname() << "_" << index;
+ }
+ if (!(cstat->mysubdesc(index).empty())) {
+ desc << cstat->mysubdesc(index);
+ } else {
+ desc << cstat->mydesc();
+ }
+
+ data()->display(stream, name.str(), desc.str(),
+ cstat->myprecision(), cstat->myflags(), cstat->params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline const VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index) const
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+/**
+ * @todo Need a way to print Distribution totals across the Vector
+ */
+template <typename T, template <typename T> class Storage, class Bin>
+void
+VectorDistBase<T, Storage, Bin>::display(std::ostream &stream) const
+{
+ for (int i = 0; i < size(); ++i) {
+ VectorDistProxy<T, Storage, Bin> proxy(*this, i);
+ proxy.display(stream);
+ }
+}
+
+#if 0
+result_t
+VectorDistBase<T, Storage, Bin>::total(int index) const
+{
+ int total = 0;
+ for (int i=0; i < x_size(); ++i) {
+ total += data(i)->val(*params);
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+//
+// Formula Details
+//
+//////////////////////////////////////////////////////////////////////
+class Node : public RefCounted
+{
+ public:
+ virtual size_t size() const = 0;
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+};
+
+typedef RefCountingPtr<Node> NodePtr;
+
+class ScalarStatNode : public Node
+{
+ private:
+ const ScalarStat &stat;
+ mutable rvec_t result;
+
+ public:
+ ScalarStatNode(const ScalarStat &s) : stat(s), result(1) {}
+ const rvec_t &val() const { result[0] = stat.val(); return result; }
+ virtual result_t total() const { return stat.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxyNode : public Node
+{
+ private:
+ const ScalarProxy<T, Storage, Bin> proxy;
+ mutable rvec_t result;
+
+ public:
+ ScalarProxyNode(const ScalarProxy<T, Storage, Bin> &p)
+ : proxy(p), result(1) { }
+ const rvec_t &val() const { result[0] = proxy.val(); return result; }
+ virtual result_t total() const { return proxy.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+class VectorStatNode : public Node
+{
+ private:
+ const VectorStat &stat;
+
+ public:
+ VectorStatNode(const VectorStat &s) : stat(s) {}
+ const rvec_t &val() const { return stat.val(); }
+ virtual result_t total() const { return stat.total(); };
+
+ virtual size_t size() const { return stat.size(); }
+};
+
+template <typename T>
+class ConstNode : public Node
+{
+ private:
+ rvec_t data;
+
+ public:
+ ConstNode(T s) : data(1, (result_t)s) {}
+ const rvec_t &val() const { return data; }
+ virtual result_t total() const { return data[0]; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class FunctorNode : public Node
+{
+ private:
+ T &functor;
+ mutable rvec_t result;
+
+ public:
+ FunctorNode(T &f) : functor(f) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)functor();
+ return result;
+ }
+ virtual result_t total() const { return (result_t)functor(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class ScalarNode : public Node
+{
+ private:
+ T &scalar;
+ mutable rvec_t result;
+
+ public:
+ ScalarNode(T &s) : scalar(s) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)scalar;
+ return result;
+ }
+ virtual result_t total() const { return (result_t)scalar; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <class Op>
+class UnaryNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ UnaryNode(NodePtr p) : l(p) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+
+ assert(size > 0);
+
+ result.resize(size);
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ Op op;
+ return op(l->total());
+ }
+
+ virtual size_t size() const { return l->size(); }
+};
+
+template <class Op>
+class BinaryNode : public Node
+{
+ public:
+ NodePtr l;
+ NodePtr r;
+ mutable rvec_t result;
+
+ public:
+ BinaryNode(NodePtr a, NodePtr b) : l(a), r(b) {}
+
+ const rvec_t &val() const {
+ Op op;
+ const rvec_t &lvec = l->val();
+ const rvec_t &rvec = r->val();
+
+ assert(lvec.size() > 0 && rvec.size() > 0);
+
+ if (lvec.size() == 1 && rvec.size() == 1) {
+ result.resize(1);
+ result[0] = op(lvec[0], rvec[0]);
+ } else if (lvec.size() == 1) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[0], rvec[i]);
+ } else if (rvec.size() == 1) {
+ int size = lvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[0]);
+ } else if (rvec.size() == lvec.size()) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[i]);
+ }
+
+ return result;
+ }
+
+ result_t 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;
+ }
+ }
+};
+
+template <class Op>
+class SumNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ SumNode(NodePtr p) : l(p), result(1) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result[0] = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[0] = op(result[0], lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result_t result = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result = op(result, lvec[i]);
+
+ return result;
+ }
+
+ virtual size_t size() const { return 1; }
+};
+
+class Temp
+{
+ private:
+ NodePtr node;
+
+ public:
+ Temp(NodePtr n) : node(n) {}
+ Temp(const ScalarStat &s) : node(new ScalarStatNode(s)) {}
+ template <typename T, template <typename T> class Storage, class Bin>
+ Temp(const ScalarProxy<T, Storage, Bin> &p)
+ : node(new ScalarProxyNode<T, Storage, Bin>(p)) {}
+ Temp(const VectorStat &s) : node(new VectorStatNode(s)) {}
+
+#define TempSCALAR(T) \
+ Temp(T value) : node(new ConstNode<T>(value)) {}
+
+ TempSCALAR( signed char);
+ TempSCALAR(unsigned char);
+ TempSCALAR( signed short);
+ TempSCALAR(unsigned short);
+ TempSCALAR( signed int);
+ TempSCALAR(unsigned int);
+ TempSCALAR( signed long);
+ TempSCALAR(unsigned long);
+ TempSCALAR( signed long long);
+ TempSCALAR(unsigned long long);
+ TempSCALAR(float);
+ TempSCALAR(double);
+#undef TempSCALAR
+
+ operator NodePtr() { return node;}
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Binning Interface
+//
+//////////////////////////////////////////////////////////////////////
+
+class BinBase
+{
+ private:
+ off_t memsize;
+ char *mem;
+
+ protected:
+ off_t size() const { return memsize; }
+ char *memory();
+
+ public:
+ BinBase(size_t size);
+ ~BinBase();
+};
+
+} // namespace Detail
+
+template <class BinType>
+struct StatBin : public Detail::BinBase
+{
+ static StatBin *&curBin() {
+ static StatBin *current = NULL;
+ return current;
+ }
+
+ static void setCurBin(StatBin *bin) { curBin() = bin; }
+ static StatBin *current() { assert(curBin()); return curBin(); }
+
+ static off_t &offset() {
+ static off_t offset = 0;
+ return offset;
+ }
+
+ static off_t new_offset(size_t size) {
+ size_t mask = sizeof(u_int64_t) - 1;
+ off_t off = offset();
+
+ // That one is for the last trailing flags byte.
+ offset() += (size + 1 + mask) & ~mask;
+
+ return off;
+ }
+
+ explicit StatBin(size_t size = 1024) : Detail::BinBase(size) {}
+
+ char *memory(off_t off) {
+ assert(offset() <= size());
+ return Detail::BinBase::memory() + off;
+ }
+
+ static void activate(StatBin &bin) { setCurBin(&bin); }
+
+ class BinBase
+ {
+ private:
+ int offset;
+
+ public:
+ BinBase() : offset(-1) {}
+ void allocate(size_t size) {
+ offset = new_offset(size);
+ }
+ char *access() {
+ assert(offset != -1);
+ return current()->memory(offset);
+ }
+ };
+
+ template <class Storage>
+ class Bin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ public:
+ Bin() { allocate(sizeof(Storage)); }
+ bool initialized() const { return true; }
+ void init(const Params &params) { }
+
+ int size() const { return 1; }
+
+ Storage *data(const Params &params) {
+ assert(initialized());
+ char *ptr = access();
+ char *flags = ptr + sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ new (ptr) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ class VectorBin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ int _size;
+
+ public:
+ VectorBin() : _size(0) {}
+
+ bool initialized() const { return _size > 0; }
+ void init(int s, const Params &params) {
+ assert(!initialized());
+ assert(s > 0);
+ _size = s;
+ allocate(_size * sizeof(Storage));
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ char *ptr = access();
+ char *flags = ptr + size() * sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ for (int i = 0; i < size(); ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+class MainBinType {};
+typedef StatBin<MainBinType> MainBin;
+
+struct NoBin
+{
+ template <class Storage>
+ struct Bin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char ptr[sizeof(Storage)];
+
+ public:
+ bool initialized() const { return true; }
+ void init(const Params &params) {
+ new (ptr) Storage(params);
+ }
+ int size() const{ return 1; }
+ Storage *data(const Params &params) {
+ assert(initialized());
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ struct VectorBin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char *ptr;
+ int _size;
+
+ public:
+ VectorBin() : ptr(NULL) { }
+ ~VectorBin() {
+ if (initialized())
+ delete [] ptr;
+ }
+ bool initialized() const { return ptr != NULL; }
+ void init(int s, const Params &params) {
+ assert(s > 0 && "size must be positive!");
+ assert(!initialized());
+ _size = s;
+ ptr = new char[_size * sizeof(Storage)];
+ for (int i = 0; i < _size; ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Visible Statistics Types
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T = Counter, class Bin = NoBin>
+class Scalar : public Detail::ScalarBase<T, Detail::StatStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::StatStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Average : public Detail::ScalarBase<T, Detail::AvgStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::AvgStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector : public Detail::VectorBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageVector : public Detail::VectorBase<T, Detail::AvgStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector2d : public Detail::Vector2dBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Distribution : public Detail::DistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ Distribution &init(T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class StandardDeviation : public Detail::DistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ StandardDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageDeviation : public Detail::DistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ AverageDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorDistribution
+ : public Detail::VectorDistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorDistribution &init(int size, T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorStandardDeviation
+ : public Detail::VectorDistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::FancyStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorStandardDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorAverageDeviation
+ : public Detail::VectorDistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::AvgFancy, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorAverageDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+class Formula : public Detail::VectorStat
+{
+ private:
+ Detail::NodePtr root;
+ friend class Detail::Temp;
+
+ public:
+ Formula() : VectorStat(true) { setInit(); }
+ Formula(Detail::Temp r) : VectorStat(true) {
+ root = r;
+ assert(size());
+ }
+
+ const Formula &operator=(Detail::Temp r) {
+ assert(!root && "Can't change formulas");
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const Formula &operator+=(Detail::Temp r) {
+ using namespace Detail;
+ if (root)
+ root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
+ else
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const rvec_t &val() const { return root->val(); }
+ result_t total() const { return root->total(); }
+
+ size_t size() const {
+ if (!root)
+ return 0;
+ else
+ return root->size();
+ }
+};
+
+void check();
+void dump(std::ostream &stream);
+
+inline Detail::Temp
+operator+(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::plus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::minus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator*(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::multiplies<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator/(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::divides<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator%(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::modulus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l)
+{
+ using namespace Detail;
+ return NodePtr(new UnaryNode<std::negate<result_t> >(l));
+}
+
+template <typename T>
+inline Detail::Temp
+constant(T val)
+{
+ using namespace Detail;
+ return NodePtr(new ConstNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+functor(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new FunctorNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+scalar(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new ScalarNode<T>(val));
+}
+
+inline Detail::Temp
+sum(Detail::Temp val)
+{
+ using namespace Detail;
+ return NodePtr(new SumNode<std::plus<result_t> >(val));
+}
+
+extern bool PrintDescriptions;
+
+} // namespace statistics
+
+#endif // __STATISTICS_HH__
diff --git a/base/str.cc b/base/str.cc
new file mode 100644
index 000000000..f54729813
--- /dev/null
+++ b/base/str.cc
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2003 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.h>
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+
+#include "intmath.h"
+#include "str.hh"
+
+using namespace std;
+
+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 (ignore) {
+ if (last == first) {
+ while (last == first)
+ last = s.find_first_of(token, ++first);
+
+ if (last == string::npos) {
+ v.push_back(s);
+ 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));
+}
+
+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 T hexmax = maxnum & (((T)1 << (sizeof(T) * 8 - 4)) - 1);
+ static const T octmax = maxnum & (((T)1 << (sizeof(T) * 8 - 3)) - 1);
+ static const T signmax =
+ (sign) ? maxnum & (((T)1 << (sizeof(T) * 8 - 1)) - 1) : maxnum;
+ static const T decmax = signmax / 10 - 1;
+
+#if 0
+ cout << "maxnum = 0x" << hex << maxnum << "\n"
+ << "sign = 0x" << hex << sign << "\n"
+ << "hexmax = 0x" << hex << hexmax << "\n"
+ << "octmax = 0x" << hex << octmax << "\n"
+ << "signmax = 0x" << hex << signmax << "\n"
+ << "decmax = 0x" << hex << 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;
+ retval *= 10;
+ retval += c - '0';
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+
+ c = value[last];
+ if (IsDec(c)) {
+
+ if (retval > decmax) return false;
+ retval *= 10;
+ retval += c - '0';
+ 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/base/str.hh b/base/str.hh
new file mode 100644
index 000000000..29d2c03db
--- /dev/null
+++ b/base/str.hh
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003 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;
+}
+
+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>
+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/base/symtab.cc b/base/symtab.cc
new file mode 100644
index 000000000..7beee182b
--- /dev/null
+++ b/base/symtab.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2003 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 "host.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+bool
+SymbolTable::insert(Addr address, string symbol)
+{
+ 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) {
+ cerr << "Can't open symbol table file " << filename << endl;
+ fatal("file error");
+ }
+
+ 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;
+}
+
+bool
+SymbolTable::findSymbol(Addr address, string &symbol) const
+{
+ ATable::const_iterator i = addrTable.find(address);
+ if (i == addrTable.end())
+ return false;
+
+ symbol = (*i).second;
+ return true;
+}
+
+bool
+SymbolTable::findAddress(const string &symbol, Addr &address) const
+{
+ STable::const_iterator i = symbolTable.find(symbol);
+ if (i == symbolTable.end())
+ return false;
+
+ address = (*i).second;
+ return true;
+}
+
+string
+SymbolTable::find(Addr addr) const
+{
+ string s;
+ findSymbol(addr, s);
+ return s;
+}
+
+Addr
+SymbolTable::find(const string &symbol) const
+{
+ Addr a = 0;
+ findAddress(symbol, a);
+ return a;
+}
diff --git a/base/symtab.hh b/base/symtab.hh
new file mode 100644
index 000000000..073325eba
--- /dev/null
+++ b/base/symtab.hh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 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 "hashmap.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable
+{
+ private:
+ typedef m5::hash_map<Addr, std::string> ATable;
+ typedef m5::hash_map<std::string, Addr> STable;
+
+ ATable addrTable;
+ STable symbolTable;
+
+ public:
+ SymbolTable() {}
+ SymbolTable(const std::string &file) { load(file); }
+ ~SymbolTable() {}
+
+ bool insert(Addr address, std::string symbol);
+ bool load(const std::string &file);
+
+ bool findSymbol(Addr address, std::string &symbol) const;
+ bool findAddress(const std::string &symbol, Addr &address) const;
+
+ std::string find(Addr addr) const;
+ Addr find(const std::string &symbol) const;
+};
+
+#endif // __SYMTAB_HH__
diff --git a/base/trace.cc b/base/trace.cc
new file mode 100644
index 000000000..d1baf3000
--- /dev/null
+++ b/base/trace.cc
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2003 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 "misc.hh"
+#include "trace.hh"
+#include "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 = NULL;
+
+int dprintf_ignore_size;
+vector<string> dprintf_ignore;
+vector<vector<string> > ignore_tokens;
+vector<int> ignore_size;
+
+bool
+dprintf_ignore_name(const string &name)
+{
+ vector<string> name_tokens;
+ tokenize(name_tokens, name, '.');
+ int ntsize = name_tokens.size();
+
+ for (int i = 0; i < dprintf_ignore_size; ++i) {
+ bool match = true;
+ int jstop = ignore_size[i];
+ for (int j = 0; j < jstop; ++j) {
+ if (j >= ntsize)
+ break;
+
+ const string &ignore = ignore_tokens[i][j];
+ if (ignore != "*" && ignore != name_tokens[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match == true)
+ return true;
+ }
+
+ return false;
+}
+
+
+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);
+ }
+
+ // 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();
+}
+
+
+
+RawDataRecord::RawDataRecord(Tick _cycle,
+ const uint8_t *_data, int _len)
+ : Record(_cycle), len(_len)
+{
+ data = new uint8_t[len];
+ memcpy(data, _data, len);
+}
+
+
+RawDataRecord::~RawDataRecord()
+{
+ delete [] data;
+}
+
+
+void
+RawDataRecord::dump(ostream &os)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ ccprintf(os, "%08x ", 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()
+{
+ if (Trace::dprintf_stream)
+ return *Trace::dprintf_stream;
+ else
+ return cerr;
+}
+
+/////////////////////////////////////////////
+//
+// 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;
+ }
+ }
+}
diff --git a/base/trace.hh b/base/trace.hh
new file mode 100644
index 000000000..42cd1722b
--- /dev/null
+++ b/base/trace.hh
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2003 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 __TRACE_HH__
+#define __TRACE_HH__
+
+#include <vector>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "universe.hh"
+
+#ifndef TRACING_ON
+#ifdef DEBUG
+#define TRACING_ON 1
+#else
+#define TRACING_ON 0
+#endif
+#endif
+
+#include "trace_flags.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 RawDataRecord : public Record
+ {
+ private:
+ uint8_t *data;
+ int len;
+
+ public:
+ RawDataRecord(Tick cycle, const uint8_t *_data, int _len);
+ virtual ~RawDataRecord();
+
+ 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 int dprintf_ignore_size;
+
+ bool
+ dprintf_ignore_name(const std::string &name);
+
+ inline void
+ dprintf(const char *format, cp::ArgList &args, Tick cycle,
+ const std::string &name)
+ {
+ if (!dprintf_ignore_size || name.empty() || !dprintf_ignore_name(name))
+ theLog.append(new Trace::PrintfRecord(format, args, cycle, name));
+ }
+
+ inline void
+ rawDump(const uint8_t *data, int len)
+ {
+ theLog.append(new Trace::RawDataRecord(curTick, data, len));
+ }
+
+ extern const std::string DefaultName;
+};
+
+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 { \
+ using namespace Trace; \
+ if (Trace::IsOn(Trace::x)) \
+ rawDump(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, string(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFN(args...) \
+do { \
+ __dprintf(curTick, name(), 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 DDUMP(x, data, count) do {} while(0)
+
+#endif // TRACING_ON
+
+#endif // __TRACE_HH__