summaryrefslogtreecommitdiff
path: root/sim
diff options
context:
space:
mode:
Diffstat (limited to 'sim')
-rw-r--r--sim/async.hh49
-rw-r--r--sim/base_cpu.cc158
-rw-r--r--sim/base_cpu.hh122
-rw-r--r--sim/cache/lzss_compression.cc166
-rw-r--r--sim/cache/lzss_compression.hh100
-rw-r--r--sim/cache/null_compression.hh72
-rw-r--r--sim/debug.cc137
-rw-r--r--sim/debug.hh34
-rw-r--r--sim/eventq.cc212
-rw-r--r--sim/eventq.hh351
-rw-r--r--sim/exec_context.cc106
-rw-r--r--sim/exec_context.hh360
-rw-r--r--sim/exetrace.cc190
-rw-r--r--sim/exetrace.hh197
-rw-r--r--sim/host.hh57
-rw-r--r--sim/hybrid_pred.cc275
-rw-r--r--sim/hybrid_pred.hh203
-rw-r--r--sim/intr_control.cc59
-rw-r--r--sim/intr_control.hh61
-rw-r--r--sim/main.cc429
-rw-r--r--sim/memtest.cc324
-rw-r--r--sim/memtest.hh140
-rw-r--r--sim/op_class.hh64
-rw-r--r--sim/param.cc760
-rw-r--r--sim/param.hh757
-rw-r--r--sim/pc_event.cc231
-rw-r--r--sim/pc_event.hh215
-rw-r--r--sim/predictor.hh62
-rw-r--r--sim/prog.cc281
-rw-r--r--sim/prog.hh180
-rw-r--r--sim/sat_counter.cc270
-rw-r--r--sim/sat_counter.hh192
-rw-r--r--sim/serialize.cc353
-rw-r--r--sim/serialize.hh241
-rw-r--r--sim/sim_events.cc271
-rw-r--r--sim/sim_events.hh131
-rw-r--r--sim/sim_exit.hh41
-rw-r--r--sim/sim_object.cc280
-rw-r--r--sim/sim_object.hh261
-rw-r--r--sim/sim_time.cc152
-rw-r--r--sim/sim_time.hh84
-rw-r--r--sim/simple_cpu.cc747
-rw-r--r--sim/simple_cpu.hh280
-rw-r--r--sim/smt.hh64
-rw-r--r--sim/static_inst.cc88
-rw-r--r--sim/static_inst.hh433
-rw-r--r--sim/std_types.hh40
-rw-r--r--sim/system.cc250
-rw-r--r--sim/system.hh113
-rw-r--r--sim/universe.cc58
50 files changed, 10701 insertions, 0 deletions
diff --git a/sim/async.hh b/sim/async.hh
new file mode 100644
index 000000000..fb0e2ee06
--- /dev/null
+++ b/sim/async.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 __ASYNC_HH__
+#define __ASYNC_HH__
+
+///
+/// @file sim/async.hh
+/// This file defines flags used to handle asynchronous simulator events.
+///
+
+/// @name Asynchronous event flags.
+/// To avoid races, signal handlers simply set these flags, which are
+/// then checked in the main event loop. Defined in main.cc.
+/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm.
+//@{
+extern volatile bool async_event; ///< Some asynchronous event has happened.
+extern volatile bool async_dump; ///< Async request to dump stats.
+extern volatile bool async_exit; ///< Async request to exit simulator.
+extern volatile bool async_io; ///< Async I/O request (SIGIO).
+extern volatile bool async_alarm; ///< Async alarm event (SIGALRM).
+//@}
+
+#endif // __ASYNC_HH__
diff --git a/sim/base_cpu.cc b/sim/base_cpu.cc
new file mode 100644
index 000000000..43caa1fe4
--- /dev/null
+++ b/sim/base_cpu.cc
@@ -0,0 +1,158 @@
+/*
+ * 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 <string>
+#include <sstream>
+#include <iostream>
+
+#include "base_cpu.hh"
+#include "cprintf.hh"
+#include "stats.hh"
+#include "exec_context.hh"
+#include "misc.hh"
+#include "sim_events.hh"
+
+using namespace std;
+
+vector<BaseCPU *> BaseCPU::cpuList;
+
+// This variable reflects the max number of threads in any CPU. Be
+// careful to only use it once all the CPUs that you care about have
+// been initialized
+int maxThreadsPerCPU = 1;
+
+#ifdef FULL_SYSTEM
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ System *_system, int num, Tick freq)
+ : SimObject(_name), number(num), frequency(freq),
+ number_of_threads(_number_of_threads), system(_system)
+#else
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads)
+ : SimObject(_name), number_of_threads(_number_of_threads)
+#endif
+{
+ // add self to global list of CPUs
+ cpuList.push_back(this);
+
+ if (number_of_threads > maxThreadsPerCPU)
+ maxThreadsPerCPU = number_of_threads;
+
+ // allocate per-thread instruction-based event queues
+ comInsnEventQueue = new (EventQueue *)[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comInsnEventQueue[i] = new EventQueue("instruction-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (max_insts_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comInsnEventQueue[i], max_insts_any_thread,
+ "a thread reached the max instruction count");
+
+ if (max_insts_all_threads != 0) {
+ // allocate & initialize shared downcounter: each event will
+ // decrement this when triggered; simulation will terminate
+ // when counter reaches 0
+ int *counter = new int;
+ *counter = number_of_threads;
+ for (int i = 0; i < number_of_threads; ++i)
+ new CountedExitEvent(comInsnEventQueue[i],
+ "all threads reached the max instruction count",
+ max_insts_all_threads, *counter);
+ }
+
+#ifdef FULL_SYSTEM
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+#endif
+}
+
+void
+BaseCPU::regStats()
+{
+ int size = contexts.size();
+ if (size > 1) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ ccprintf(namestr, "%s.ctx%d", name(), i);
+ contexts[i]->regStats(namestr.str());
+ }
+ } else if (size == 1)
+ contexts[0]->regStats(name());
+}
+
+#ifdef FULL_SYSTEM
+void
+BaseCPU::post_interrupt(int int_num, int index)
+{
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+
+ if (int_num < 0 || int_num >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_t) * 8)
+ panic("int_num out of bounds\n");
+
+ AlphaISA::check_interrupts = 1;
+ interrupts[int_num] |= 1 << index;
+ intstatus |= (ULL(1) << int_num);
+}
+
+void
+BaseCPU::clear_interrupt(int int_num, int index)
+{
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+
+ if (int_num < 0 || int_num >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_t) * 8)
+ panic("int_num out of bounds\n");
+
+ interrupts[int_num] &= ~(1 << index);
+ if (interrupts[int_num] == 0)
+ intstatus &= ~(ULL(1) << int_num);
+}
+
+void
+BaseCPU::clear_interrupts()
+{
+ DPRINTF(Interrupt, "Interrupts all cleared\n");
+
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+}
+
+#endif // FULL_SYSTEM
+
+DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
diff --git a/sim/base_cpu.hh b/sim/base_cpu.hh
new file mode 100644
index 000000000..745220d85
--- /dev/null
+++ b/sim/base_cpu.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 __BASE_CPU_HH__
+#define __BASE_CPU_HH__
+
+#include <vector>
+
+#include "eventq.hh"
+#include "sim_object.hh"
+
+#include "isa_traits.hh" // for Addr
+
+#ifdef FULL_SYSTEM
+class System;
+#endif
+
+class BranchPred;
+class ExecContext;
+
+class BaseCPU : public SimObject
+{
+#ifdef FULL_SYSTEM
+ protected:
+ int number;
+ Tick frequency;
+ uint8_t interrupts[NumInterruptLevels];
+ uint64_t intstatus;
+
+ public:
+ virtual void post_interrupt(int int_num, int index);
+ virtual void clear_interrupt(int int_num, int index);
+ virtual void clear_interrupts();
+
+ bool check_interrupt(int int_num) const {
+ if (int_num > NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ return interrupts[int_num] != 0;
+ }
+
+ bool check_interrupts() const { return intstatus != 0; }
+ uint64_t intr_status() const { return intstatus; }
+
+ Tick getFreq() const { return frequency; }
+#endif
+
+ protected:
+ std::vector<ExecContext *> contexts;
+
+ public:
+ virtual void execCtxStatusChg() {}
+
+ public:
+
+#ifdef FULL_SYSTEM
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ System *_system,
+ int num, Tick freq);
+#else
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread = 0,
+ Counter max_insts_all_threads = 0);
+#endif
+
+ virtual ~BaseCPU() {}
+
+ virtual void regStats();
+
+ /// Number of threads we're actually simulating (<= SMT_MAX_THREADS).
+ /// This is a constant for the duration of the simulation.
+ int number_of_threads;
+
+ /// Vector of per-thread instruction-based event queues. Used for
+ /// scheduling events based on number of instructions committed by
+ /// a particular thread.
+ EventQueue **comInsnEventQueue;
+
+#ifdef FULL_SYSTEM
+ System *system;
+#endif
+
+ virtual bool filterThisInstructionPrefetch(int thread_number,
+ short asid, Addr prefetchTarget) const { return true; }
+
+ /// Return pointer to CPU's branch predictor (NULL if none).
+ virtual BranchPred *getBranchPred() { return NULL; };
+
+ private:
+ static std::vector<BaseCPU *> cpuList; //!< Static global cpu list
+
+ public:
+ static int numSimulatedCPUs() { return cpuList.size(); }
+};
+
+#endif // __BASE_CPU_HH__
diff --git a/sim/cache/lzss_compression.cc b/sim/cache/lzss_compression.cc
new file mode 100644
index 000000000..a1933215a
--- /dev/null
+++ b/sim/cache/lzss_compression.cc
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+/** @file
+ * LZSSCompression definitions.
+ */
+
+#include <assert.h>
+
+#include "lzss_compression.hh"
+
+#include "misc.hh" //for fatal
+
+int
+LZSSCompression::findSubString(uint8_t *src, int front, int back, int size)
+{
+ int subSize = 0;
+ int max_length = 2048;
+ if (size - back < max_length) {
+ max_length = size - back;
+ }
+ for (int i = 0; i < max_length; ++i) {
+ if (src[front+i] != src[back+i]) {
+ return subSize;
+ }
+ ++subSize;
+ }
+ return subSize;
+}
+
+int
+LZSSCompression::emitByte(uint8_t *dest, uint8_t byte)
+{
+ if ((byte >> 5 & 0x7) == 0 || (byte >> 5 & 0x7) == 7) {
+ // If the top 3 bits are the same, emit 00<6bits>
+ dest[0] = byte & 0x3f;
+ return 1;
+ } else {
+ // emit 01XXXXXX <8 bits>
+ dest[0] = 0x40;
+ dest[1] = byte;
+ return 2;
+ }
+}
+
+void
+LZSSCompression::emitString(uint8_t *dest, uint16_t P, uint16_t L)
+{
+ // Emit 1<7P> <5P><3L> <8L>
+ dest[0] = 1<<7 | (P >> 5 & 0x7f);
+ dest[1] = ((P & 0x1f) << 3) | (L>>8 & 0x3);
+ dest[2] = L & 0xFF;
+}
+
+int
+LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size)
+{
+ if (size > 4096) {
+ fatal("Compression can only handle block sizes of 4096 bytes or less");
+ }
+
+ // Encode the first byte.
+ int dest_index = emitByte(dest, src[0]);
+ int i = 1;
+ // A 11 bit field
+ uint16_t L;
+ // A 12 bit field
+ uint16_t P = 0;
+
+ while (i < size && dest_index < size) {
+ L = 0;
+
+ if (dest_index+3 >= size) {
+ dest_index = size;
+ continue;
+ }
+
+ if (i == size - 1) {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ continue;
+ }
+ for (int j = 0; j < i; ++j) {
+ int sub_size = findSubString(src, j, i, size);
+ if (sub_size >= L) {
+ L = sub_size;
+ P = j;
+ }
+ }
+ if (L > 1) {
+ // Output the string reference
+ emitString(&dest[dest_index], P, L);
+ dest_index += 3;
+ i = i+L;
+ } else {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ }
+ }
+
+ if (dest_index >= size) {
+ // Have expansion instead of compression, just copy.
+ memcpy(dest,src,size);
+ return size;
+ }
+ return dest_index;
+}
+
+int
+LZSSCompression::uncompress(uint8_t *dest, uint8_t *src, int size)
+{
+ int index = 0;
+ int i = 0;
+ while (i < size) {
+ if (src[i] & 1<<7 ) {
+ // We have a string
+ // Extract P
+ int start = (src[i] & 0x3f)<<5 | ((src[i+1] >> 3) & 0x1f);
+ // Extract L
+ int len = (src[i+1] & 0x07)<<8 | src[i+2];
+ i += 3;
+ for (int j = start; j < start+len; ++j) {
+ dest[index++] = dest[j];
+ }
+ } else {
+ // We have a character
+ if (src[i] & 1<<6) {
+ // Value is in the next byte
+ dest[index++] = src[i+1];
+ i += 2;
+ } else {
+ // just extend the lower 6 bits
+ dest[index++] = (src[i] & 0x3f) | ((src[i] & 1<<5) ? 0xC0 : 0);
+ ++i;
+ }
+ }
+ }
+ return index;
+}
diff --git a/sim/cache/lzss_compression.hh b/sim/cache/lzss_compression.hh
new file mode 100644
index 000000000..5fb47d3f1
--- /dev/null
+++ b/sim/cache/lzss_compression.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 __LZSS_COMPRESSION_HH__
+#define __LZSS_COMPRESSION_HH__
+
+/** @file
+ * LZSSCompression declarations.
+ */
+
+#include "host.hh" // for uint8_t
+
+/**
+ * Simple LZSS compression scheme.
+ */
+class LZSSCompression
+{
+ /**
+ * Finds the longest substrings that start at the given offsets.
+ * @param src The source block that we search for substrings.
+ * @param front The smaller offset.
+ * @param back The larger offset.
+ * @param size The size of the source block.
+ * @return The size of the longest substring.
+ */
+ int findSubString(uint8_t *src, int front, int back, int size);
+
+ /**
+ * Emit an encoded byte to the compressed data array. If the 2 high
+ * order bits can be signed extended, use 1 byte encoding, if not use 2
+ * bytes.
+ * @param dest The compressed data.
+ * @param byte The byte to emit.
+ * @return The number of bytes used to encode.
+ */
+ int emitByte(uint8_t *dest, uint8_t byte);
+
+ /**
+ * Emit a string reference to the compressed data array. A string reference
+ * always uses 3 bytes. 1 flag bit, 12 bits for the starting position, and
+ * 11 bits for the length of the string. This allows compression of 4096
+ * byte blocks with string lengths of up to 2048 bytes.
+ * @param dest The compressed data.
+ * @param P The starting position in the uncompressed data.
+ * @param L The length in bytes of the string.
+ */
+ void emitString(uint8_t *dest, uint16_t P, uint16_t L);
+
+ public:
+ /**
+ * Compresses the source block and stores it in the destination block. If
+ * the compressed block grows to larger than the source block, it aborts
+ * and just performs a copy.
+ * @param dest The destination block.
+ * @param src The block to be compressed.
+ * @param size The size of the source block.
+ * @return The size of the compressed block.
+ *
+ * @pre Destination has enough storage to hold the compressed block.
+ */
+ int compress(uint8_t *dest, uint8_t *src, int size);
+
+ /**
+ * Unompresses the source block and stores it in the destination block.
+ * @param dest The destination block.
+ * @param src The block to be uncompressed.
+ * @param size The size of the source block.
+ * @return The size of the uncompressed block.
+ *
+ * @pre Destination has enough storage to hold the uncompressed block.
+ */
+ int uncompress(uint8_t *dest, uint8_t *src, int size);
+};
+
+#endif //__LZSS_COMPRESSION_HH__
diff --git a/sim/cache/null_compression.hh b/sim/cache/null_compression.hh
new file mode 100644
index 000000000..d2bc76eef
--- /dev/null
+++ b/sim/cache/null_compression.hh
@@ -0,0 +1,72 @@
+/*
+ * 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 __NULL_COMPRESSION_HH__
+#define __NULL_COMPRESSION_HH__
+
+/**
+ * @file
+ * This file defines a doNothing compression algorithm.
+ */
+
+/**
+ * A dummy compression class to use when no data compression is desired.
+ */
+class NullCompression
+{
+ public:
+ /**
+ * Uncompress the data, causes a fatal since no data should be compressed.
+ * @param dest The output buffer.
+ * @param src The compressed data.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the uncompressed data.
+ */
+ static int uncompress(uint8_t * dest, uint8_t *src, int size)
+ {
+ fatal("Can't uncompress data");
+ }
+
+ /**
+ * Compress the data, just returns the source data.
+ * @param dest The output buffer.
+ * @param src The data to be compressed.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the compressed data.
+ */
+
+ static int compress(uint8_t *dest, uint8_t *src, int size)
+ {
+ memcpy(dest,src,size);
+ return size;
+ }
+};
+
+#endif //__NULL_COMPRESSION_HH__
diff --git a/sim/debug.cc b/sim/debug.cc
new file mode 100644
index 000000000..bfc5c9987
--- /dev/null
+++ b/sim/debug.cc
@@ -0,0 +1,137 @@
+/*
+ * 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 <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "debug.hh"
+#include "eventq.hh"
+#include "param.hh"
+#include "sim_events.hh"
+
+using namespace std;
+
+void
+debug_break()
+{
+ kill(getpid(), SIGTRAP);
+}
+
+//
+// Debug event: place a breakpoint on the process function and
+// schedule the event to break at a particular cycle
+//
+class DebugBreakEvent : public Event
+{
+ public:
+
+ DebugBreakEvent(EventQueue *q, Tick _when);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when)
+ : Event(q)
+{
+ schedule(_when, -20000);
+}
+
+//
+// handle debug event: set debugger breakpoint on this function
+//
+void
+DebugBreakEvent::process()
+{
+ debug_break();
+ delete this;
+}
+
+
+const char *
+DebugBreakEvent::description()
+{
+ return "debug break";
+}
+
+//
+// Parameter context for global debug options
+//
+class DebugContext : public ParamContext
+{
+ public:
+ DebugContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DebugContext debugParams("debug");
+
+VectorParam<Tick> break_cycles(&debugParams, "break_cycles",
+ "cycle(s) to create breakpoint events");
+
+void
+DebugContext::checkParams()
+{
+ if (break_cycles.isValid()) {
+ vector<Tick> &cycles = break_cycles;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DebugBreakEvent(&mainEventQueue, *i);
+ }
+}
+
+//
+// handy function to schedule DebugBreakEvent on main event queue
+// (callable from debugger)
+//
+extern "C" void sched_break_cycle(Tick when)
+{
+ new DebugBreakEvent(&mainEventQueue, when);
+}
+
+extern "C" void dump_stats()
+{
+ new DumpStatsEvent();
+}
+
+extern "C" void eventq_dump()
+{
+ mainEventQueue.dump();
+}
+
diff --git a/sim/debug.hh b/sim/debug.hh
new file mode 100644
index 000000000..eb0be772e
--- /dev/null
+++ b/sim/debug.hh
@@ -0,0 +1,34 @@
+/*
+ * 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 __DEBUG_HH__
+#define __DEBUG_HH__
+
+void debug_break();
+
+#endif // __DEBUG_HH__
diff --git a/sim/eventq.cc b/sim/eventq.cc
new file mode 100644
index 000000000..36ef8aab2
--- /dev/null
+++ b/sim/eventq.cc
@@ -0,0 +1,212 @@
+/*
+ * 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 <assert.h>
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "smt.hh"
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+const string Event::defaultName("event");
+
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+EventQueue mainEventQueue("Main Event Queue");
+
+void
+EventQueue::insert(Event *event)
+{
+ if (head == NULL || event->when() < head->when() ||
+ (event->when() == head->when() &&
+ event->priority() <= head->priority())) {
+ event->next = head;
+ head = event;
+ } else {
+ Event *prev = head;
+ Event *curr = head->next;
+
+ while (curr) {
+ if (event->when() <= curr->when() &&
+ (event->when() < curr->when() ||
+ event->priority() <= curr->priority()))
+ break;
+
+ prev = curr;
+ curr = curr->next;
+ }
+
+ event->next = curr;
+ prev->next = event;
+ }
+}
+
+void
+EventQueue::remove(Event *event)
+{
+ if (head == NULL)
+ return;
+
+ if (head == event){
+ head = event->next;
+ return;
+ }
+
+ Event *prev = head;
+ Event *curr = head->next;
+ while (curr && curr != event) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr == event)
+ prev->next = curr->next;
+}
+
+void
+EventQueue::serviceOne()
+{
+ Event *event = head;
+ event->clearFlags(Event::Scheduled);
+ head = event->next;
+
+ // handle action
+ if (!event->squashed())
+ event->process();
+ else
+ event->clearFlags(Event::Squashed);
+
+ if (event->getFlags(Event::AutoDelete))
+ delete event;
+}
+
+void
+EventQueue::nameChildren()
+{
+ int j = 0;
+
+ Event *event = head;
+ while (event) {
+ stringstream stream;
+ ccprintf(stream, "%s.event%d", name(), j++);
+ event->setName(stream.str());
+
+ event = event->next;
+ }
+}
+
+void
+EventQueue::serialize()
+{
+ string objects = "";
+
+ Event *event = head;
+ while (event) {
+ objects += event->name();
+ objects += " ";
+ event->serialize();
+
+ event = event->next;
+ }
+ nameOut("Serialized");
+ paramOut("objects",objects);
+}
+
+void
+EventQueue::dump()
+{
+ cprintf("============================================================\n");
+ cprintf("EventQueue Dump (cycle %d)\n", curTick);
+ cprintf("------------------------------------------------------------\n");
+
+ if (empty())
+ cprintf("<No Events>\n");
+ else {
+ Event *event = head;
+ while (event) {
+ event->dump();
+ event = event->next;
+ }
+ }
+
+ cprintf("============================================================\n");
+}
+
+
+const char *
+Event::description()
+{
+ return "generic";
+}
+
+#if TRACING_ON
+void
+Event::trace(const char *action)
+{
+ // This DPRINTF is unconditional because calls to this function
+ // are protected by an 'if (DTRACE(Event))' in the inlined Event
+ // methods.
+ //
+ // This is just a default implementation for derived classes where
+ // it's not worth doing anything special. If you want to put a
+ // more informative message in the trace, override this method on
+ // the particular subclass where you have the information that
+ // needs to be printed.
+ DPRINTFN("%s event %s @ %d\n", description(), action, when());
+}
+#endif
+
+void
+Event::dump()
+{
+#if TRACING_ON
+ cprintf(" Created: %d\n", when_created);
+#endif
+ if (scheduled()) {
+#if TRACING_ON
+ cprintf(" Scheduled at %d\n", when_scheduled);
+#endif
+ cprintf(" Scheduled for %d\n", when());
+ }
+ else {
+ cprintf(" Not Scheduled\n");
+ }
+}
diff --git a/sim/eventq.hh b/sim/eventq.hh
new file mode 100644
index 000000000..71b027768
--- /dev/null
+++ b/sim/eventq.hh
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * EventQueue interfaces
+ */
+
+#ifndef __EVENTQ_HH__
+#define __EVENTQ_HH__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "host.hh" // for Tick
+
+#include "fast_alloc.hh"
+#include "serialize.hh"
+#include "trace.hh"
+
+class EventQueue; // forward declaration
+
+/*
+ * An item on an event queue. The action caused by a given
+ * event is specified by deriving a subclass and overriding the
+ * process() member function.
+ */
+class Event : public Serializeable, public FastAlloc
+{
+ friend class EventQueue;
+
+ private:
+ /// queue to which this event belongs (though it may or may not be
+ /// scheduled on this queue yet)
+ EventQueue *queue;
+
+ Event *next;
+
+ Tick _when; //!< timestamp when event should be processed
+ int _priority; //!< event priority
+ char _flags;
+
+ protected:
+ enum Flags {
+ None = 0x0,
+ Squashed = 0x1,
+ Scheduled = 0x2,
+ AutoDelete = 0x4
+ };
+
+ bool getFlags(Flags f) const { return (_flags & f) == f; }
+ void setFlags(Flags f) { _flags |= f; }
+ void clearFlags(Flags f) { _flags &= ~f; }
+
+ protected:
+ EventQueue *theQueue() const { return queue; }
+
+#if TRACING_ON
+ Tick when_created; //!< Keep track of creation time For debugging
+ Tick when_scheduled; //!< Keep track of creation time For debugging
+
+ virtual void trace(const char *action); //!< trace event activity
+#else
+ void trace(const char *) {}
+#endif
+
+ unsigned annotated_value;
+
+ public:
+
+ static const std::string defaultName;
+
+ /*
+ * Event constructor
+ * @param queue that the event gets scheduled on
+ */
+ Event(EventQueue *q, int p = 0)
+ : Serializeable(defaultName), queue(q), next(NULL),
+ _priority(p), _flags(None),
+#if TRACING_ON
+ when_created(curTick), when_scheduled(0),
+#endif
+ annotated_value(0)
+ {
+ }
+
+ ~Event() {}
+
+ /// Determine if the current event is scheduled
+ bool scheduled() const { return getFlags(Scheduled); }
+
+ /// Schedule the event with the current priority or default priority
+ void schedule(Tick t);
+
+ /// Schedule the event with a specific priority
+ void schedule(Tick t, int priority);
+
+ /// Reschedule the event with the current priority
+ void reschedule(Tick t);
+
+ /// Reschedule the event with a specific priority
+ void reschedule(Tick t, int priority);
+
+ /// Remove the event from the current schedule
+ void deschedule();
+
+ /// Return a C string describing the event. This string should
+ /// *not* be dynamically allocated; just a const char array
+ /// describing the event class.
+ virtual const char *description();
+
+ /// Dump the current event data
+ void dump();
+
+ /*
+ * This member function is invoked when the event is processed
+ * (occurs). There is no default implementation; each subclass
+ * must provide its own implementation. The event is not
+ * automatically deleted after it is processed (to allow for
+ * statically allocated event objects).
+ *
+ * If the AutoDestroy flag is set, the object is deleted once it
+ * is processed.
+ */
+ virtual void process() = 0;
+
+ void annotate(unsigned value) { annotated_value = value; };
+ unsigned annotation() { return annotated_value; }
+
+ /// Squash the current event
+ void squash() { setFlags(Squashed); }
+
+ /// Check whether the event is squashed
+ bool squashed() { return getFlags(Squashed); }
+
+ /// Get the time that the event is scheduled
+ Tick when() const { return _when; }
+
+ /// Get the event priority
+ int priority() const { return _priority; }
+
+ struct priority_compare :
+ public std::binary_function<Event *, Event *, bool>
+ {
+ bool operator()(const Event *l, const Event *r) const {
+ return l->when() >= r->when() || l->priority() >= r->priority();
+ }
+ };
+};
+
+template <class T, void (T::* F)()>
+void
+DelayFunction(Tick when, T *object)
+{
+ class DelayEvent : public Event
+ {
+ private:
+ T *object;
+
+ public:
+ DelayEvent(Tick when, T *o)
+ : Event(&mainEventQueue), object(o)
+ { setFlags(AutoDestroy); schedule(when); }
+ void process() { (object->*F)(); }
+ const char *description() { return "delay"; }
+ };
+
+ new DelayEvent(when, object);
+}
+
+/*
+ * Queue of events sorted in time order
+ */
+class EventQueue : public Serializeable
+{
+ private:
+ Event *head;
+
+ void insert(Event *event);
+ void remove(Event *event);
+
+ public:
+
+ // constructor
+ EventQueue(const std::string &n)
+ : Serializeable(n), head(NULL)
+ {}
+
+ // schedule the given event on this queue
+ void schedule(Event *ev);
+ void deschedule(Event *ev);
+ void reschedule(Event *ev);
+
+ Tick nextTick() { return head->when(); }
+ void serviceOne();
+
+ // process all events up to the given timestamp. we inline a
+ // quick test to see if there are any events to process; if so,
+ // call the internal out-of-line version to process them all.
+ void serviceEvents(Tick when) {
+ while (!empty()) {
+ if (nextTick() > when)
+ break;
+
+ assert(head->when() >= when && "event scheduled in the past");
+ serviceOne();
+ }
+ }
+
+ // default: process all events up to 'now' (curTick)
+ void serviceEvents() { serviceEvents(curTick); }
+
+ // return true if no events are queued
+ bool empty() { return head == NULL; }
+
+ void dump();
+
+ Tick nextEventTime() { return empty() ? curTick : head->when(); }
+
+ virtual void nameChildren();
+ virtual void serialize();
+};
+
+
+//////////////////////
+//
+// inline functions
+//
+// can't put these inside declaration due to circular dependence
+// between Event and EventQueue classes.
+//
+//////////////////////
+
+// schedule at specified time (place on event queue specified via
+// constructor)
+inline void
+Event::schedule(Tick t)
+{
+ assert(!scheduled());
+ setFlags(Scheduled);
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->schedule(this);
+}
+
+inline void
+Event::schedule(Tick t, int p)
+{
+ _priority = p;
+ schedule(t);
+}
+
+inline void
+Event::deschedule()
+{
+ assert(scheduled());
+
+ clearFlags(Squashed);
+ clearFlags(Scheduled);
+ queue->deschedule(this);
+}
+
+inline void
+Event::reschedule(Tick t)
+{
+ assert(scheduled());
+ clearFlags(Squashed);
+
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->reschedule(this);
+}
+
+inline void
+Event::reschedule(Tick t, int p)
+{
+ _priority = p;
+ reschedule(t);
+}
+
+inline void
+EventQueue::schedule(Event *event)
+{
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("scheduled");
+}
+
+inline void
+EventQueue::deschedule(Event *event)
+{
+ remove(event);
+ if (DTRACE(Event))
+ event->trace("descheduled");
+}
+
+inline void
+EventQueue::reschedule(Event *event)
+{
+ remove(event);
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("rescheduled");
+}
+
+
+//////////////////////
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+// defined in eventq.cc
+//
+//////////////////////
+extern EventQueue mainEventQueue;
+
+#endif // __EVENTQ_HH__
diff --git a/sim/exec_context.cc b/sim/exec_context.cc
new file mode 100644
index 000000000..c81d172a8
--- /dev/null
+++ b/sim/exec_context.cc
@@ -0,0 +1,106 @@
+/*
+ * 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 <string>
+
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#ifdef FULL_SYSTEM
+#include "system.hh"
+#else
+#include "prog.hh"
+#endif
+
+using namespace std;
+
+// constructor
+#ifdef FULL_SYSTEM
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaItb *_itb, AlphaDtb *_dtb,
+ FunctionalMemory *_mem, int _cpu_id)
+ : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), mem(_mem),
+ itb(_itb), dtb(_dtb), cpu_id(_cpu_id), system(_sys),
+ memCtrl(_sys->memCtrl), physmem(_sys->physmem)
+{
+ memset(&regs, 0, sizeof(RegFile));
+ _status = Active;
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+ system->registerExecContext(this);
+}
+#else
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ Process *_process, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid)
+{
+
+ // Register with process object. Our 'active' will be set by the
+ // process iff we're the initial context. Others are reserved for
+ // dynamically created threads.
+ process->registerExecContext(this);
+
+ mem = process->getMemory();
+
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+}
+
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ FunctionalMemory *_mem, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem),
+ asid(_asid)
+{
+}
+#endif
+
+void
+ExecContext::setStatus(Status new_status)
+{
+#ifdef FULL_SYSTEM
+ if (status() == new_status)
+ return;
+
+ // Don't change the status from active if there are pending interrupts
+ if (new_status == Suspended && cpu->check_interrupts()) {
+ assert(status() == Active);
+ return;
+ }
+#endif
+
+ _status = new_status;
+ cpu->execCtxStatusChg();
+}
+
+void
+ExecContext::regStats(const string &name)
+{
+#ifdef FULL_SYSTEM
+ kernelStats.regStats(name + ".kern");
+#endif
+}
diff --git a/sim/exec_context.hh b/sim/exec_context.hh
new file mode 100644
index 000000000..56bce0aa9
--- /dev/null
+++ b/sim/exec_context.hh
@@ -0,0 +1,360 @@
+/*
+ * 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 __EXEC_CONTEXT_HH__
+#define __EXEC_CONTEXT_HH__
+
+#include "host.hh"
+#include "stats.hh"
+#include "mem_req.hh"
+
+// forward declaration: see functional_memory.hh
+class FunctionalMemory;
+class PhysicalMemory;
+class BaseCPU;
+
+#ifdef FULL_SYSTEM
+
+#include "alpha_memory.hh"
+class MemoryController;
+
+#include "kernel_stats.hh"
+#include "system.hh"
+
+#else // !FULL_SYSTEM
+
+#include "prog.hh"
+
+#endif // FULL_SYSTEM
+
+//
+// The ExecContext object represents a functional context for
+// instruction execution. It incorporates everything required for
+// architecture-level functional simulation of a single thread.
+//
+
+class ExecContext
+{
+ public:
+ enum Status { Unallocated, Active, Suspended, Halted };
+
+ private:
+ Status _status;
+
+ public:
+ Status status() const { return _status; }
+ void setStatus(Status new_status);
+
+#ifdef FULL_SYSTEM
+ public:
+ KernelStats kernelStats;
+#endif
+
+ public:
+ RegFile regs; // correct-path register context
+
+ // pointer to CPU associated with this context
+ BaseCPU *cpu;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int thread_num;
+
+#ifdef FULL_SYSTEM
+
+ FunctionalMemory *mem;
+ AlphaItb *itb;
+ AlphaDtb *dtb;
+ int cpu_id;
+ System *system;
+
+ // the following two fields are redundant, since we can always
+ // look them up through the system pointer, but we'll leave them
+ // here for now for convenience
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+#else
+ Process *process;
+
+ FunctionalMemory *mem; // functional storage for process address space
+
+ // Address space ID. Note that this is used for TIMING cache
+ // simulation only; all functional memory accesses should use
+ // one of the FunctionalMemory pointers above.
+ short asid;
+
+#endif
+
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter func_exe_insn;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+
+ // constructor: initialize context from given process structure
+#ifdef FULL_SYSTEM
+ ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem,
+ int _cpu_id);
+#else
+ ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
+ ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
+ int _asid);
+#endif
+ virtual ~ExecContext() {}
+
+ void regStats(const std::string &name);
+
+#ifdef FULL_SYSTEM
+ bool validInstAddr(Addr addr) { return true; }
+ bool validDataAddr(Addr addr) { return true; }
+ int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
+ int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }
+
+ Fault translateInstReq(MemReqPtr req)
+ {
+ return itb->translate(req);
+ }
+
+ Fault translateDataReadReq(MemReqPtr req)
+ {
+ return dtb->translate(req, false);
+ }
+
+ Fault translateDataWriteReq(MemReqPtr req)
+ {
+ return dtb->translate(req, true);
+ }
+
+
+#else
+ bool validInstAddr(Addr addr)
+ { return process->validInstAddr(addr); }
+
+ bool validDataAddr(Addr addr)
+ { return process->validDataAddr(addr); }
+
+ int getInstAsid() { return asid; }
+ int getDataAsid() { return asid; }
+
+ Fault dummyTranslation(MemReqPtr req)
+ {
+#if 0
+ assert((req->vaddr >> 48 & 0xffff) == 0);
+#endif
+
+ // put the asid in the upper 16 bits of the paddr
+ req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
+ req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
+ return No_Fault;
+ }
+ Fault translateInstReq(MemReqPtr req)
+ {
+ return dummyTranslation(req);
+ }
+ Fault translateDataReadReq(MemReqPtr req)
+ {
+ return dummyTranslation(req);
+ }
+ Fault translateDataWriteReq(MemReqPtr req)
+ {
+ return dummyTranslation(req);
+ }
+
+#endif
+
+ template <class T>
+ Fault read(MemReqPtr req, T& data)
+ {
+#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+ if (req->flags & LOCKED) {
+ MiscRegFile *cregs = &req->xc->regs.miscRegs;
+ cregs->lock_addr = req->paddr;
+ cregs->lock_flag = true;
+ }
+#endif
+ return mem->read(req, data);
+ }
+
+ template <class T>
+ Fault write(MemReqPtr req, T& data)
+ {
+#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+
+ MiscRegFile *cregs;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ cregs = &req->xc->regs.miscRegs;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see machine.def)
+ req->result = 2;
+ req->xc->storeCondFailures = 0;//Needed? [RGD]
+ } else {
+ req->result = cregs->lock_flag;
+ if (!cregs->lock_flag ||
+ ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ cregs->lock_flag = false;
+ if (((++req->xc->storeCondFailures) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << req->xc->storeCondFailures
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->cpu_id
+ << std::endl;
+ }
+ return No_Fault;
+ }
+ else req->xc->storeCondFailures = 0;
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for this
+ // address
+ // Only do this for succsful Store Conditionals and all other
+ // stores (WH64?)
+ // Unsuccesful Store Conditionals would have returned above,
+ // and wouldn't fall through
+ for(int i = 0; i < system->num_cpus; i++){
+ cregs = &system->xc_array[i]->regs.miscRegs;
+ if((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
+ cregs->lock_flag = false;
+ }
+ }
+
+#endif
+ return mem->write(req, data);
+ }
+
+ virtual bool misspeculating();
+
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ {
+ return regs.intRegFile[reg_idx];
+ }
+
+ float readFloatRegSingle(int reg_idx)
+ {
+ return (float)regs.floatRegFile.d[reg_idx];
+ }
+
+ double readFloatRegDouble(int reg_idx)
+ {
+ return regs.floatRegFile.d[reg_idx];
+ }
+
+ uint64_t readFloatRegInt(int reg_idx)
+ {
+ return regs.floatRegFile.q[reg_idx];
+ }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ regs.intRegFile[reg_idx] = val;
+ }
+
+ void setFloatRegSingle(int reg_idx, float val)
+ {
+ regs.floatRegFile.d[reg_idx] = (double)val;
+ }
+
+ void setFloatRegDouble(int reg_idx, double val)
+ {
+ regs.floatRegFile.d[reg_idx] = val;
+ }
+
+ void setFloatRegInt(int reg_idx, uint64_t val)
+ {
+ regs.floatRegFile.q[reg_idx] = val;
+ }
+
+ uint64_t readPC()
+ {
+ return regs.pc;
+ }
+
+ void setNextPC(uint64_t val)
+ {
+ regs.npc = val;
+ }
+
+ uint64_t readUniq()
+ {
+ return regs.miscRegs.uniq;
+ }
+
+ void setUniq(uint64_t val)
+ {
+ regs.miscRegs.uniq = val;
+ }
+
+ uint64_t readFpcr()
+ {
+ return regs.miscRegs.fpcr;
+ }
+
+ void setFpcr(uint64_t val)
+ {
+ regs.miscRegs.fpcr = val;
+ }
+
+#ifdef FULL_SYSTEM
+ uint64_t readIpr(int idx, Fault &fault);
+ Fault setIpr(int idx, uint64_t val);
+ Fault hwrei();
+ void ev5_trap(Fault fault);
+ bool simPalCheck(int palFunc);
+#endif
+
+#ifndef FULL_SYSTEM
+ void syscall()
+ {
+ process->syscall(this);
+ }
+#endif
+};
+
+
+// for non-speculative execution context, spec_mode is always false
+inline bool
+ExecContext::misspeculating()
+{
+ return false;
+}
+
+#endif // __EXEC_CONTEXT_HH__
diff --git a/sim/exetrace.cc b/sim/exetrace.cc
new file mode 100644
index 000000000..4c5d14893
--- /dev/null
+++ b/sim/exetrace.cc
@@ -0,0 +1,190 @@
+/*
+ * 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 <fstream>
+#include <iomanip>
+
+#include "dyn_inst.hh"
+#include "spec_state.hh"
+#include "issue.hh"
+#include "exetrace.hh"
+#include "exec_context.hh"
+#include "symtab.hh"
+#include "base_cpu.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Methods for the InstRecord object
+//
+
+
+const SymbolTable *debugSymbolTable = NULL;
+
+void
+Trace::InstRecord::dump(ostream &outs)
+{
+ if (flags[PRINT_CYCLE])
+ ccprintf(outs, "%7d: ", cycle);
+
+ outs << cpu->name() << " ";
+
+ if (flags[TRACE_MISSPEC])
+ outs << (misspeculating ? "-" : "+") << " ";
+
+ if (flags[PRINT_THREAD_NUM])
+ outs << "T" << thread << " : ";
+
+ outs << "0x" << hex << PC << " : ";
+
+ //
+ // Print decoded instruction
+ //
+
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // There's a bug in gcc 2.x library that prevents setw()
+ // from working properly on strings
+ string mc(staticInst->disassemble(PC, debugSymbolTable));
+ while (mc.length() < 25)
+ mc += " ";
+ outs << mc;
+#else
+ outs << setw(25) << staticInst->disassemble(PC, debugSymbolTable);
+#endif
+
+ outs << " : ";
+
+ if (flags[PRINT_OP_CLASS]) {
+ outs << opClassStrings[staticInst->opClass()] << " : ";
+ }
+
+ if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) {
+ outs << " D=";
+#if 0
+ if (data_status == DataDouble)
+ ccprintf(outs, "%f", data.as_double);
+ else
+ ccprintf(outs, "%#018x", data.as_int);
+#else
+ ccprintf(outs, "%#018x", data.as_int);
+#endif
+ }
+
+ if (flags[PRINT_EFF_ADDR] && addr_valid)
+ outs << " A=0x" << hex << addr;
+
+ if (flags[PRINT_INT_REGS] && regs_valid) {
+ for (int i = 0; i < 32;)
+ for (int j = i + 1; i <= j; i++)
+ ccprintf(outs, "r%02d = %#018x%s", i, iregs->regs[i],
+ ((i == j) ? "\n" : " "));
+ outs << "\n";
+ }
+
+ if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid)
+ outs << " FetchSeq=" << dec << fetch_seq;
+
+ if (flags[PRINT_CP_SEQ] && cp_seq_valid)
+ outs << " CPSeq=" << dec << cp_seq;
+
+ //
+ // End of line...
+ //
+ outs << endl;
+ outs.flush();
+}
+
+
+vector<bool> Trace::InstRecord::flags(NUM_BITS);
+
+////////////////////////////////////////////////////////////////////////
+//
+// Parameter space for per-cycle execution address tracing options.
+// Derive from ParamContext so we can override checkParams() function.
+//
+class ExecutionTraceParamContext : public ParamContext
+{
+ public:
+ ExecutionTraceParamContext(const string &_iniSection)
+ : ParamContext(_iniSection)
+ {
+ }
+
+ void checkParams(); // defined at bottom of file
+};
+
+ExecutionTraceParamContext exeTraceParams("exetrace");
+
+Param<bool> exe_trace_spec(&exeTraceParams, "speculative",
+ "capture speculative instructions", false);
+
+Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle",
+ "print cycle number", true);
+Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass",
+ "print op class", true);
+Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread",
+ "print thread number", true);
+Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr",
+ "print effective address", true);
+Param<bool> exe_trace_print_data(&exeTraceParams, "print_data",
+ "print result data", true);
+Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs",
+ "print all integer regs", false);
+Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq",
+ "print fetch sequence number", false);
+Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq",
+ "print correct-path sequence number", false);
+
+//
+// Helper function for ExecutionTraceParamContext::checkParams() just
+// to get us into the InstRecord namespace
+//
+void
+Trace::InstRecord::setParams()
+{
+ flags[TRACE_MISSPEC] = exe_trace_spec;
+
+ flags[PRINT_CYCLE] = exe_trace_print_cycle;
+ flags[PRINT_OP_CLASS] = exe_trace_print_opclass;
+ flags[PRINT_THREAD_NUM] = exe_trace_print_thread;
+ flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr;
+ flags[PRINT_EFF_ADDR] = exe_trace_print_data;
+ flags[PRINT_INT_REGS] = exe_trace_print_iregs;
+ flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq;
+ flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq;
+}
+
+void
+ExecutionTraceParamContext::checkParams()
+{
+ Trace::InstRecord::setParams();
+}
+
diff --git a/sim/exetrace.hh b/sim/exetrace.hh
new file mode 100644
index 000000000..d5b9dc218
--- /dev/null
+++ b/sim/exetrace.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 __EXETRACE_HH__
+#define __EXETRACE_HH__
+
+#include <fstream>
+#include <vector>
+
+#include "host.hh"
+#include "std_types.hh" // for InstSeqNum
+#include "trace.hh"
+#include "exec_context.hh"
+#include "static_inst.hh"
+
+class BaseCPU;
+
+
+namespace Trace {
+
+#if 0
+ static const FlagVec ALL = ULL(0x1);
+ static const FlagVec FULL = ULL(0x2);
+ static const FlagVec SYMBOLS = ULL(0x4);
+ static const FlagVec EXTENDED = ULL(0x8);
+ static const FlagVec BRANCH_TAKEN = ULL(0x10);
+ static const FlagVec BRANCH_NOTTAKEN = ULL(0x20);
+ static const FlagVec CALLPAL = ULL(0x40);
+ static const FlagVec SPECULATIVE = ULL(0x100);
+ static const FlagVec OMIT_COUNT = ULL(0x200);
+ static const FlagVec INCLUDE_THREAD_NUM = ULL(0x400);
+#endif
+
+class InstRecord : public Record
+{
+ protected:
+
+ // The following fields are initialized by the constructor and
+ // thus guaranteed to be valid.
+ BaseCPU *cpu;
+ // need to make this ref-counted so it doesn't go away before we
+ // dump the record
+ StaticInstPtr<TheISA> staticInst;
+ Addr PC;
+ bool misspeculating;
+ unsigned thread;
+
+ // The remaining fields are only valid for particular instruction
+ // types (e.g, addresses for memory ops) or when particular
+ // options are enabled (e.g., tracing full register contents).
+ // Each data field has an associated valid flag to indicate
+ // whether the data field is valid.
+ Addr addr;
+ bool addr_valid;
+
+ union {
+ uint64_t as_int;
+ double as_double;
+ } data;
+ enum {
+ DataInvalid = 0,
+ DataInt8 = 1, // set to equal number of bytes
+ DataInt16 = 2,
+ DataInt32 = 4,
+ DataInt64 = 8,
+ DataDouble = 3
+ } data_status;
+
+ InstSeqNum fetch_seq;
+ bool fetch_seq_valid;
+
+ InstSeqNum cp_seq;
+ bool cp_seq_valid;
+
+ struct iRegFile {
+ IntRegFile regs;
+ };
+ iRegFile *iregs;
+ bool regs_valid;
+
+ public:
+ InstRecord(Tick _cycle, BaseCPU *_cpu, StaticInstPtr<TheISA> _staticInst,
+ Addr _pc, bool spec, unsigned _thread)
+ : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc),
+ misspeculating(spec), thread(_thread)
+ {
+ data_status = DataInvalid;
+ addr_valid = false;
+ regs_valid = false;
+
+ fetch_seq_valid = false;
+ cp_seq_valid = false;
+ }
+
+ virtual ~InstRecord() { }
+
+ virtual void dump(std::ostream &outs);
+
+ void setAddr(Addr a) { addr = a; addr_valid = true; }
+
+ void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; }
+ void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; }
+ void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; }
+ void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; }
+
+ void setData(int64_t d) { setData((uint64_t)d); }
+ void setData(int32_t d) { setData((uint32_t)d); }
+ void setData(int16_t d) { setData((uint16_t)d); }
+ void setData(int8_t d) { setData((uint8_t)d); }
+
+ void setData(double d) { data.as_double = d; data_status = DataDouble; }
+
+ void setFetchSeq(InstSeqNum seq)
+ { fetch_seq = seq; fetch_seq_valid = true; }
+
+ void setCPSeq(InstSeqNum seq)
+ { cp_seq = seq; cp_seq_valid = true; }
+
+ void setRegs(const IntRegFile &regs);
+
+ void finalize() { theLog.append(this); }
+
+ enum InstExecFlagBits {
+ TRACE_MISSPEC = 0,
+ PRINT_CYCLE,
+ PRINT_OP_CLASS,
+ PRINT_THREAD_NUM,
+ PRINT_RESULT_DATA,
+ PRINT_EFF_ADDR,
+ PRINT_INT_REGS,
+ PRINT_FETCH_SEQ,
+ PRINT_CP_SEQ,
+ NUM_BITS
+ };
+
+ static std::vector<bool> flags;
+
+ static void setParams();
+
+ static bool traceMisspec() { return flags[TRACE_MISSPEC]; }
+};
+
+
+inline void
+InstRecord::setRegs(const IntRegFile &regs)
+{
+ if (!iregs)
+ iregs = new iRegFile;
+
+ memcpy(&iregs->regs, regs, sizeof(IntRegFile));
+ regs_valid = true;
+}
+
+inline
+InstRecord *
+getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu,
+ const StaticInstPtr<TheISA> staticInst,
+ Addr pc, int thread = 0)
+{
+ if (DTRACE(InstExec) &&
+ (InstRecord::traceMisspec() || !xc->misspeculating())) {
+ return new InstRecord(cycle, cpu, staticInst, pc,
+ xc->misspeculating(), thread);
+ }
+
+ return NULL;
+}
+
+
+}
+
+#endif // __EXETRACE_HH__
diff --git a/sim/host.hh b/sim/host.hh
new file mode 100644
index 000000000..489c4e042
--- /dev/null
+++ b/sim/host.hh
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Defines host-dependent types:
+ * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t.
+ */
+
+#ifndef __HOST_HH__
+#define __HOST_HH__
+
+#include <inttypes.h>
+
+/** uint64_t constant */
+#define ULL(N) N##ULL
+/** int64_t constant */
+#define LL(N) N##LL
+
+/** Statistics counter type. Not much excuse for not using a 64-bit
+ * integer here, but if you're desperate and only run short
+ * simulations you could make this 32 bits.
+ */
+typedef int64_t Counter;
+
+/**
+ * Clock cycle count type.
+ * @note using an unsigned breaks the cache.
+ */
+typedef int64_t Tick;
+
+#endif // __HOST_H__
diff --git a/sim/hybrid_pred.cc b/sim/hybrid_pred.cc
new file mode 100644
index 000000000..6a8384083
--- /dev/null
+++ b/sim/hybrid_pred.cc
@@ -0,0 +1,275 @@
+/*
+ * 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 <string>
+#include <sstream>
+
+#include "stats.hh"
+#include "hybrid_pred.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+HybridPredictor::HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits,
+ unsigned _global_thresh,
+ bool _reg_individual_stats)
+{
+ stringstream local_name, global_name;
+
+ pred_name = _p_name;
+ one_name = _o_name;
+ zero_name = _z_name;
+ reg_individual_stats = _reg_individual_stats;
+
+ local_name << pred_name.c_str() << ":L";
+ local = new SaturatingCounterPred(local_name.str(), zero_name, one_name,
+ _index_bits, _counter_bits,
+ _zero_change, _one_change, _thresh);
+
+ global_name << pred_name.c_str() << ":G";
+ global = new SaturatingCounterPred(global_name.str(), zero_name, one_name,
+ 0, _global_bits, 1, 1, _global_thresh);
+}
+
+void HybridPredictor::regStats()
+{
+ using namespace Statistics;
+
+ string p_name;
+ stringstream description;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+
+ //
+ // Number of predictions
+ //
+ stringstream num_zero_preds;
+ num_zero_preds << p_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ pred_zero
+ .name(num_zero_preds.str())
+ .desc(description.str());
+ description.str("");
+
+ stringstream num_one_preds;
+ num_one_preds << p_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ pred_one
+ .name(num_one_preds.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ stringstream num_zero_correct;
+ num_zero_correct << p_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds" ;
+ correct_pred_zero
+ .name(num_zero_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_correct;
+ num_one_correct << p_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds" ;
+ correct_pred_one
+ .name(num_one_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+
+ //
+ // Number of predictor updates
+ //
+ stringstream num_zero_updates;
+ num_zero_updates << p_name << ":" << zero_name << ":updates" ;
+ description << "number of actual " << zero_name << "s" ;
+ record_zero
+ .name(num_zero_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_updates;
+ num_one_updates << p_name << ":" << one_name << ":updates" ;
+ description << "number of actual " << one_name << "s" ;
+ record_one
+ .name(num_one_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regStats();
+ global->regStats();
+ }
+}
+
+void HybridPredictor::regFormulas()
+{
+ using namespace Statistics;
+
+ string p_name;
+ stringstream description;
+ stringstream name;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+ //
+ // Number of predictions
+ //
+ name << p_name << ":predictions" ;
+ total_preds
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ total_preds = pred_one + pred_zero;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << p_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name ;
+ frac_preds_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_zero = 100 * record_zero / total_preds;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name ;
+ frac_preds_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_one = 100 * record_one / total_preds;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << p_name << ":correct_preds" ;
+ total_correct
+ .name(name.str())
+ .desc("total number of correct predictions made")
+ ;
+ total_correct = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+
+ //
+ // Prediction accuracy rates
+ //
+ name << p_name << ":pred_rate";
+ total_accuracy
+ .name(name.str())
+ .desc("fraction of all preds that were correct")
+ ;
+ total_accuracy = 100 * total_correct / total_preds;
+ name.str("");
+
+ name << p_name << ":" << zero_name << ":pred_rate" ;
+ description << "fraction of "<< zero_name <<" preds that were correct";
+ zero_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_accuracy = 100 * correct_pred_zero / pred_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_rate" ;
+ description << "fraction of "<< one_name <<" preds that were correct";
+ one_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_accuracy = 100 * correct_pred_one / pred_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << p_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ zero_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_coverage = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ one_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_coverage = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regFormulas();
+ global->regFormulas();
+ }
+
+}
+
diff --git a/sim/hybrid_pred.hh b/sim/hybrid_pred.hh
new file mode 100644
index 000000000..f6e14e3e3
--- /dev/null
+++ b/sim/hybrid_pred.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 predictor takes the AND of a "local" and a "global" predictor
+// in order to determine its prediction.
+//
+//
+//
+//
+
+#ifndef __HYBRID_PRED_HH__
+#define __HYBRID_PRED_HH__
+
+#include <string>
+
+#include "sat_counter.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class HybridPredictor : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string one_name;
+ std::string zero_name;
+ bool reg_individual_stats;
+
+ SaturatingCounterPred *local;
+ SaturatingCounterPred *global;
+
+ unsigned long max_index;
+
+ //
+ // Stats
+ //
+ Statistics::Scalar<> pred_one; //num_one_preds
+ Statistics::Scalar<> pred_zero; //num_zero_preds
+ Statistics::Scalar<> correct_pred_one; //num_one_correct
+ Statistics::Scalar<> correct_pred_zero; //num_zero_correct
+ Statistics::Scalar<> record_one; //num_one_updates
+ Statistics::Scalar<> record_zero; //num_zero_updates
+
+ Statistics::Formula total_preds;
+ Statistics::Formula frac_preds_zero;
+ Statistics::Formula frac_preds_one;
+ Statistics::Formula total_correct;
+ Statistics::Formula total_accuracy;
+ Statistics::Formula zero_accuracy;
+ Statistics::Formula one_accuracy;
+ Statistics::Formula zero_coverage;
+ Statistics::Formula one_coverage;
+
+ public:
+ HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits, unsigned _global_thresh,
+ bool _reg_individual_stats = false);
+
+ void clear() {
+ global->clear();
+ local->clear();
+ }
+
+ unsigned peek(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ if (l && g)
+ return 1;
+
+ return 0;
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ l = l & 0xFFFF;
+ g = g & 0xFFFF;
+
+ return (l << 16) | g;
+
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+
+ //
+ // This version need only be used if local/global statistics
+ // will be maintained
+ //
+ unsigned predict(unsigned long _index, unsigned &_pdata) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ //
+ // bit 0 => local predictor result
+ // bit 1 => global predictor result
+ //
+ _pdata = 0;
+ if (l)
+ _pdata |= 1;
+ if (g)
+ _pdata |= 2;
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+
+ if (_val) {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_one;
+
+ if (_val == _predicted) {
+ ++correct_pred_one;
+ }
+ } else {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+
+ local->record(_index, _val, (_pdata & 1));
+ global->record(_index, _val, ((_pdata & 2) ? 1 : 0));
+
+
+ if (_val) {
+ ++record_one;
+
+ if (_val == _predicted)
+ ++correct_pred_one;
+ } else {
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // _HYBRID_PRED_HH__
+
diff --git a/sim/intr_control.cc b/sim/intr_control.cc
new file mode 100644
index 000000000..7ad32a2b9
--- /dev/null
+++ b/sim/intr_control.cc
@@ -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.
+ */
+
+#include <string>
+#include <vector>
+
+#include "base_cpu.hh"
+#include "intr_control.hh"
+#include "sim_object.hh"
+
+using namespace std;
+
+IntrControl::IntrControl(const string &name, BaseCPU *c)
+ : SimObject(name), cpu(c)
+{}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl)
+
+ SimObjectParam<BaseCPU *> cpu;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IntrControl)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+ INIT_PARAM(cpu, "the processor")
+
+END_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+CREATE_SIM_OBJECT(IntrControl)
+{
+ return new IntrControl(getInstanceName(), cpu);
+}
+
+REGISTER_SIM_OBJECT("IntrControl", IntrControl)
diff --git a/sim/intr_control.hh b/sim/intr_control.hh
new file mode 100644
index 000000000..660d6d704
--- /dev/null
+++ b/sim/intr_control.hh
@@ -0,0 +1,61 @@
+/*
+ * 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 __INTR_CONTROL_HH__
+#define __INTR_CONTROL_HH__
+
+#include "misc.hh"
+#include "base_cpu.hh"
+#include "sim_object.hh"
+
+class IntrControl : public SimObject
+{
+ public:
+ BaseCPU *cpu;
+ IntrControl(const std::string &name, BaseCPU *c);
+
+ void clear(int int_num, int index = 0);
+ void post(int int_num, int index = 0);
+};
+
+inline void
+IntrControl::post(int int_num, int index)
+{ cpu->post_interrupt(int_num, index); }
+
+inline void
+IntrControl::clear(int int_num, int index)
+{ cpu->clear_interrupt(int_num, index); }
+
+#endif // __INTR_CONTROL_HH__
+
+
+
+
+
+
+
diff --git a/sim/main.cc b/sim/main.cc
new file mode 100644
index 000000000..84f8e78cc
--- /dev/null
+++ b/sim/main.cc
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ */
+
+///
+/// @file sim/main.cc
+///
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <string>
+#include <vector>
+
+#include "host.hh"
+#include "misc.hh"
+#include "stats.hh"
+
+#include "copyright.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "pollevent.hh"
+#include "statistics.hh"
+#include "sim_events.hh"
+#include "sim_exit.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+#include "sim_time.hh"
+#include "smt.hh"
+
+#include "base_cpu.hh"
+#include "async.hh"
+
+using namespace std;
+
+// See async.h.
+volatile bool async_event = false;
+volatile bool async_dump = false;
+volatile bool async_exit = false;
+volatile bool async_io = false;
+volatile bool async_alarm = false;
+
+/// Stats signal handler.
+void
+dumpStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_dump = true;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Simulator executable name
+const char *myProgName = "";
+
+/// Show brief help message.
+static void
+showBriefHelp(ostream &out)
+{
+ out << "Usage: " << myProgName
+ << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] "
+ << "[--<section>:<param>=<value>] [<config file> ...]" << endl
+ << " -h: print long help (including parameter listing)" << endl
+ << " -n: don't load default.ini" << endl
+ << " -u: don't quit on unreferenced parameters" << endl
+ << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
+}
+
+/// Show verbose help message. Includes parameter listing from
+/// showBriefHelp(), plus an exhaustive list of ini-file parameters
+/// and SimObjects (with their parameters).
+static void
+showLongHelp(ostream &out)
+{
+ showBriefHelp(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Global Parameters" << endl
+ << "-----------------" << endl
+ << endl;
+
+ ParamContext::describeAllContexts(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Simulator Objects" << endl
+ << "-----------------" << endl
+ << endl;
+
+ SimObjectClass::describeAllClasses(out);
+}
+
+/// Print welcome message.
+static void
+sayHello(ostream &out)
+{
+ extern const char *compileDate; // from date.cc
+
+ ccprintf(out, "M5 Simulator System\n");
+ // display copyright
+ ccprintf(out, "%s\n", briefCopyright);
+ ccprintf(out, "M5 compiled on %d\n", compileDate);
+
+ char *host = getenv("HOSTNAME");
+ if (!host)
+ host = getenv("HOST");
+
+ if (host)
+ ccprintf(out, "M5 executing on %s\n", host);
+
+ ccprintf(out, "M5 simulation started %s\n", Time::start);
+}
+
+///
+/// Echo the command line for posterity in such a way that it can be
+/// used to rerun the same simulation (given the same .ini files).
+///
+static void
+echoCommandLine(int argc, char **argv, ostream &out)
+{
+ out << "command line: " << argv[0];
+ for (int i = 1; i < argc; i++) {
+ string arg(argv[i]);
+
+ out << ' ';
+
+ // If the arg contains spaces, we need to quote it.
+ // The rest of this is overkill to make it look purty.
+
+ // print dashes first outside quotes
+ int non_dash_pos = arg.find_first_not_of("-");
+ out << arg.substr(0, non_dash_pos); // print dashes
+ string body = arg.substr(non_dash_pos); // the rest
+
+ // if it's an assignment, handle the lhs & rhs separately
+ int eq_pos = body.find("=");
+ if (eq_pos == string::npos) {
+ out << quote(body);
+ }
+ else {
+ string lhs(body.substr(0, eq_pos));
+ string rhs(body.substr(eq_pos + 1));
+
+ out << quote(lhs) << "=" << quote(rhs);
+ }
+ }
+ out << endl << endl;
+}
+
+
+///
+/// The simulator configuration database. This is the union of all
+/// specified .ini files. This shouldn't need to be visible outside
+/// this file, as it is passed as a parameter to all the param-parsing
+/// routines.
+///
+static IniFile simConfigDB;
+
+/// Check for a default.ini file and load it if necessary.
+static void
+handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
+{
+ struct stat sb;
+
+ if (loadIt) {
+ if (stat("default.ini", &sb) == 0) {
+ if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
+ cout << "Error processing file default.ini" << endl;
+ exit(1);
+ }
+ }
+
+ // set this whether it actually was found or not, so we don't
+ // bother to check again next time
+ loadIt = false;
+ }
+}
+
+
+/// M5 entry point.
+int
+main(int argc, char **argv)
+{
+ // Save off program name
+ myProgName = argv[0];
+
+ signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTRAP, SIG_IGN);
+ signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
+ signal(SIGINT, exitNowHandler); // dump final stats and exit
+
+ sayHello(cerr);
+
+ // Initialize statistics database
+ init_old_stats();
+ initBaseStats();
+
+ vector<char *> cppArgs;
+
+ // Should we use default.ini if it exists? By default, yes. (Use
+ // -n to override.)
+ bool loadDefaultIni = true;
+
+ // Should we quit if there are unreferenced parameters? By
+ // default, yes... it's a good way of catching typos in
+ // section/parameter names (which otherwise go by silently). Use
+ // -u to override.
+ bool quitOnUnreferenced = true;
+
+ // Parse command-line options. The tricky part here is figuring
+ // out whether to look for & load default.ini, and if needed,
+ // doing so at the right time w.r.t. processing the other
+ // parameters.
+ //
+ // Since most of the complex options are handled through the
+ // config database, we don't mess with getopts, and just parse
+ // manually.
+ for (int i = 1; i < argc; ++i) {
+ char *arg_str = argv[i];
+
+ // if arg starts with '-', parse as option,
+ // else treat it as a configuration file name and load it
+ if (arg_str[0] == '-') {
+
+ // switch on second char
+ switch (arg_str[1]) {
+ case 'h':
+ // -h: show help
+ showLongHelp(cerr);
+ exit(1);
+
+ case 'n':
+ // -n: don't load default.ini
+ if (!loadDefaultIni) {
+ cerr << "Warning: -n option needs to precede any "
+ << "explicit configuration file name " << endl
+ << " or command-line configuration parameter."
+ << endl;
+ }
+ loadDefaultIni = false;
+ break;
+
+ case 'u':
+ // -u: don't quit on unreferenced parameters
+ quitOnUnreferenced = false;
+ break;
+
+ case 'D':
+ case 'U':
+ case 'I':
+ // cpp options: record & pass to cpp. Note that these
+ // cannot have spaces, i.e., '-Dname=val' is OK, but
+ // '-D name=val' is not. I don't consider this a
+ // problem, since even though gnu cpp accepts the
+ // latter, other cpp implementations do not (Tru64,
+ // for one).
+ cppArgs.push_back(arg_str);
+ break;
+
+ case '-':
+ // command-line configuration parameter:
+ // '--<section>:<parameter>=<value>'
+
+ // Load default.ini if necessary -- see comment in
+ // else clause below.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ if (!simConfigDB.add(arg_str + 2)) {
+ // parse error
+ ccprintf(cerr,
+ "Could not parse configuration argument '%s'\n"
+ "Expecting --<section>:<parameter>=<value>\n",
+ arg_str);
+ exit(0);
+ }
+ break;
+
+ default:
+ showBriefHelp(cerr);
+ ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
+ exit(0);
+ }
+ }
+ else {
+ // no '-', treat as config file name
+
+ // If we haven't loaded default.ini yet, and we want to,
+ // now is the time. Can't do it sooner because we need to
+ // look for '-n', can't do it later since we want
+ // default.ini loaded first (so that any other settings
+ // override it).
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
+ cprintf("Error processing file %s\n", arg_str);
+ exit(1);
+ }
+ }
+ }
+
+ // Final check for default.ini, in case no config files or
+ // command-line config parameters were given.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ // The configuration database is now complete; start processing it.
+
+ // Parse and check all non-config-hierarchy parameters.
+ ParamContext::parseAllContexts(simConfigDB);
+ ParamContext::checkAllContexts();
+
+ // Print header info into stats file. Can't do this sooner since
+ // the stat file name is set via a .ini param... thus it just got
+ // opened above during ParamContext::checkAllContexts().
+
+ // Print hello message to stats file if it's actually a file. If
+ // it's not (i.e. it's cout or cerr) then we already did it above.
+ if (statStreamIsFile)
+ sayHello(*statStream);
+
+ // Echo command line and all parameter settings to stats file as well.
+ echoCommandLine(argc, argv, *statStream);
+ ParamContext::showAllContexts(*statStream);
+
+ // Now process the configuration hierarchy and create the SimObjects.
+ ConfigHierarchy configHierarchy(simConfigDB);
+ configHierarchy.build();
+ configHierarchy.createSimObjects();
+
+ // Restore checkpointed state, if any.
+ configHierarchy.unserializeSimObjects();
+
+ // Done processing the configuration database.
+ // Check for unreferenced entries.
+ if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
+ cerr << "Fatal: unreferenced .ini sections/entries." << endl
+ << "If this is not an error, add 'unref_section_ok=y' or "
+ << "'unref_entries_ok=y' to the appropriate sections "
+ << "to suppress this message." << endl;
+ exit(1);
+ }
+
+ SimObject::regAllStats();
+
+ // uncomment the following to get PC-based execution-time profile
+#ifdef DO_PROFILE
+ init_profile((char *)&_init, (char *)&_fini);
+#endif
+
+ // Check to make sure that the stats package is properly initialized
+ Statistics::check();
+
+ // Nothing to simulate if we don't have at least one CPU somewhere.
+ if (BaseCPU::numSimulatedCPUs() == 0) {
+ cerr << "Fatal: no CPUs to simulate." << endl;
+ exit(1);
+ }
+
+ while (!mainEventQueue.empty()) {
+ assert(curTick <= mainEventQueue.nextTick() &&
+ "event scheduled in the past");
+
+ // forward current cycle to the time of the first event on the
+ // queue
+ curTick = mainEventQueue.nextTick();
+ mainEventQueue.serviceOne();
+
+ if (async_event) {
+ async_event = false;
+ if (async_dump) {
+ async_dump = false;
+ new DumpStatsEvent();
+ }
+
+ if (async_exit) {
+ async_exit = false;
+ new SimExitEvent("User requested STOP");
+ }
+
+ if (async_io || async_alarm) {
+ async_io = false;
+ async_alarm = false;
+ pollQueue.service();
+ }
+ }
+ }
+
+ // This should never happen... every conceivable way for the
+ // simulation to terminate (hit max cycles/insts, signal,
+ // simulated system halts/exits) generates an exit event, so we
+ // should never run out of events on the queue.
+ exitNow("improperly exited event loop!", 1);
+
+ return 0;
+}
diff --git a/sim/memtest.cc b/sim/memtest.cc
new file mode 100644
index 000000000..70b6fbf13
--- /dev/null
+++ b/sim/memtest.cc
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <vector>
+
+#include "memtest.hh"
+#include "misc.hh"
+#include "sim_events.hh"
+#include "main_memory.hh"
+#include "base_cache.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+MemTest::MemTest(const string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr)
+ : BaseCPU(name, 1),
+ tickEvent(this),
+ cacheInterface(_cache_interface),
+ mainMem(main_mem),
+ checkMem(check_mem),
+ size(_memorySize),
+ percentReads(_percentReads),
+ percentUncacheable(_percentUncacheable),
+ maxReads(_maxReads),
+ progressInterval(_progressInterval),
+ nextProgressMessage(_progressInterval)
+{
+ vector<string> cmd;
+ cmd.push_back("/bin/ls");
+ vector<string> null_vec;
+ xc = new ExecContext(this ,0,mainMem,0);
+
+ blockSize = cacheInterface->getBlockSize();
+ blockAddrMask = blockSize - 1;
+ traceBlockAddr = blockAddr(_traceAddr);
+
+ //setup data storage with interesting values
+ uint8_t *data1 = new uint8_t[size];
+ uint8_t *data2 = new uint8_t[size];
+ uint8_t *data3 = new uint8_t[size];
+ memset(data1, 1, size);
+ memset(data2, 2, size);
+ memset(data3, 3, size);
+ curTick = 0;
+
+ baseAddr1 = 0x100000;
+ baseAddr2 = 0x400000;
+ uncacheAddr = 0x800000;
+
+ // set up intial memory contents here
+ mainMem->prot_write(baseAddr1, data1, size);
+ checkMem->prot_write(baseAddr1, data1, size);
+ mainMem->prot_write(baseAddr2, data2, size);
+ checkMem->prot_write(baseAddr2, data2, size);
+ mainMem->prot_write(uncacheAddr, data3, size);
+ checkMem->prot_write(uncacheAddr, data3, size);
+
+ delete [] data1;
+ delete [] data2;
+ delete [] data3;
+
+ // set up counters
+ noResponseCycles = 0;
+ numReads = 0;
+ numWrites = 0;
+ tickEvent.schedule(0);
+}
+
+static void
+printData(ostream &os, uint8_t *data, int nbytes)
+{
+ os << hex << setfill('0');
+ // assume little-endian: print bytes from highest address to lowest
+ for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) {
+ os << setw(2) << (unsigned)*dp;
+ }
+ os << dec;
+}
+
+void
+MemTest::completeRequest(MemReqPtr req, uint8_t *data)
+{
+ switch (req->cmd) {
+ case Read:
+ if (memcmp(req->data, data, req->size) != 0) {
+ cerr << name() << ": on read of 0x" << hex << req->paddr
+ << " @ cycle " << dec << curTick
+ << ", cache returns 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ", expected 0x";
+ printData(cerr, data, req->size);
+ cerr << endl;
+ fatal("");
+ }
+
+ numReads++;
+
+ if (numReads.val() == nextProgressMessage) {
+ cerr << name() << ": completed " << numReads.val()
+ << " read accesses @ " << curTick << endl;
+ nextProgressMessage += progressInterval;
+ }
+
+ if (numReads.val() == maxReads) {
+ stringstream stream;
+ stream << name() << " reached max read count (" << maxReads
+ << ")" << endl;
+
+ new SimExitEvent(stream.str());
+ }
+ break;
+
+ case Write:
+ numWrites++;
+ break;
+
+
+ default:
+ panic("invalid command");
+ }
+
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": completed "
+ << (req->cmd.isWrite() ? "write" : "read") << " access of "
+ << req->size << " bytes at address 0x"
+ << hex << req->paddr << ", value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << endl;
+ }
+
+ noResponseCycles = 0;
+ delete [] data;
+}
+
+
+void
+MemTest::regStats()
+{
+ using namespace Statistics;
+
+ numReads
+ .name(name() + ".num_reads")
+ .desc("number of read accesses completed")
+ ;
+
+ numWrites
+ .name(name() + ".num_writes")
+ .desc("number of write accesses completed")
+ ;
+
+ numCopies
+ .name(name() + ".num_copies")
+ .desc("number of copy accesses completed")
+ ;
+}
+
+void
+MemTest::tick()
+{
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+
+ if (++noResponseCycles >= 5000) {
+ cerr << name() << ": deadlocked at cycle " << curTick << endl;
+ fatal("");
+ }
+
+ if (cacheInterface->isBlocked()) {
+ return;
+ }
+
+ //make new request
+ unsigned cmd = rand() % 100;
+ unsigned offset1 = random() % size;
+ unsigned base = random() % 2;
+ uint64_t data = random();
+ unsigned access_size = random() % 4;
+ unsigned cacheable = rand() % 100;
+
+ MemReqPtr req = new MemReq();
+
+ if (cacheable < percentUncacheable) {
+ req->flags |= UNCACHEABLE;
+ req->paddr = uncacheAddr + offset1;
+ } else {
+ req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
+ }
+
+ req->size = 1 << access_size;
+ req->data = new uint8_t[req->size];
+ req->paddr &= ~(req->size - 1);
+ req->time = curTick;
+ req->xc = xc;
+
+ if (cmd < percentReads) {
+ // read
+ req->cmd = Read;
+ uint8_t *result = new uint8_t[8];
+ checkMem->access(Read, req->paddr, result, req->size);
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": initiating read of "
+ << req->size << " bytes from addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+
+ req->completionEvent = new MemCompleteEvent(req, result, this);
+ cacheInterface->access(req);
+ } else {
+ // write
+ req->cmd = Write;
+ memcpy(req->data, &data, req->size);
+ checkMem->access(Write, req->paddr, req->data, req->size);
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": initiating write of "
+ << req->size << " bytes (value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ") to addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+ req->completionEvent = new MemCompleteEvent(req, NULL, this);
+ cacheInterface->access(req);
+ }
+}
+
+
+void
+MemCompleteEvent::process()
+{
+ tester->completeRequest(req, data);
+ delete this;
+}
+
+
+const char *
+MemCompleteEvent::description()
+{
+ return "memory access completion";
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
+
+ SimObjectParam<BaseCache *> cache;
+ SimObjectParam<FunctionalMemory *> main_mem;
+ SimObjectParam<FunctionalMemory *> check_mem;
+ Param<unsigned> memory_size;
+ Param<unsigned> percent_reads;
+ Param<unsigned> percent_uncacheable;
+ Param<unsigned> max_reads;
+ Param<unsigned> progress_interval;
+ Param<Addr> trace_addr;
+
+END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
+
+ INIT_PARAM(cache, "L1 cache"),
+ INIT_PARAM(main_mem, "hierarchical memory"),
+ INIT_PARAM(check_mem, "check memory"),
+ INIT_PARAM_DFLT(memory_size, "memory size", 65536),
+ INIT_PARAM_DFLT(percent_reads, "target read percentage", 65),
+ INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10),
+ INIT_PARAM_DFLT(max_reads, "number of reads to simulate", 0),
+ INIT_PARAM_DFLT(progress_interval,
+ "progress report interval (in accesses)", 1000000),
+ INIT_PARAM_DFLT(trace_addr, "address to trace", 0)
+
+END_INIT_SIM_OBJECT_PARAMS(MemTest)
+
+
+CREATE_SIM_OBJECT(MemTest)
+{
+ return new MemTest(getInstanceName(), cache->getInterface(), main_mem,
+ check_mem,
+ memory_size, percent_reads,
+ percent_uncacheable, max_reads, progress_interval,
+ trace_addr);
+}
+
+REGISTER_SIM_OBJECT("MemTest", MemTest)
diff --git a/sim/memtest.hh b/sim/memtest.hh
new file mode 100644
index 000000000..aa652abbd
--- /dev/null
+++ b/sim/memtest.hh
@@ -0,0 +1,140 @@
+/*
+ * 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 __MEMTEST_HH__
+#define __MEMTEST_HH__
+
+#include "sim_object.hh"
+#include "mem_interface.hh"
+#include "functional_memory.hh"
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class MemTest : public BaseCPU
+{
+ public:
+
+ MemTest(const std::string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr);
+
+ // register statistics
+ virtual void regStats();
+ // main simulation loop (one cycle)
+ void tick();
+
+ protected:
+ class TickEvent : public Event
+ {
+ private:
+ MemTest *cpu;
+ public:
+ TickEvent(MemTest *c)
+ : Event(&mainEventQueue, 100), cpu(c) {}
+ void process() {cpu->tick();}
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ MemInterface *cacheInterface;
+ FunctionalMemory *mainMem;
+ FunctionalMemory *checkMem;
+ ExecContext *xc;
+
+ unsigned size; // size of testing memory region
+
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentUncacheable;
+
+ Tick maxReads; // max # of reads to perform (then quit)
+
+ unsigned blockSize;
+
+ Addr blockAddrMask;
+
+ Addr blockAddr(Addr addr)
+ {
+ return (addr & ~blockAddrMask);
+ }
+
+ Addr traceBlockAddr;
+
+ Addr baseAddr1; // fix this to option
+ Addr baseAddr2; // fix this to option
+ Addr uncacheAddr;
+
+ unsigned progressInterval; // frequency of progress reports
+ Tick nextProgressMessage; // access # for next progress report
+
+ Tick noResponseCycles;
+
+ Statistics::Scalar<long long int> numReads;
+ Statistics::Scalar<long long int> numWrites;
+ Statistics::Scalar<long long int> numCopies;
+
+ // called by MemCompleteEvent::process()
+ void completeRequest(MemReqPtr req, uint8_t *data);
+
+ friend class MemCompleteEvent;
+};
+
+
+class MemCompleteEvent : public Event
+{
+ MemReqPtr req;
+ uint8_t *data;
+ MemTest *tester;
+
+ public:
+
+ MemCompleteEvent(MemReqPtr _req, uint8_t *_data, MemTest *_tester)
+ : Event(&mainEventQueue),
+ req(_req), data(_data), tester(_tester)
+ {
+ }
+
+ void process();
+
+ virtual const char *description();
+};
+
+#endif // __MEMTEST_HH__
+
+
+
diff --git a/sim/op_class.hh b/sim/op_class.hh
new file mode 100644
index 000000000..67ccaabad
--- /dev/null
+++ b/sim/op_class.hh
@@ -0,0 +1,64 @@
+/*
+ * 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 __OP_CLASS_HH__
+#define __OP_CLASS_HH__
+
+/**
+ * @file
+ * Definition of operation classes.
+ */
+
+/**
+ * Instruction operation classes. These classes are used for
+ * assigning instructions to functional units.
+ */
+enum OpClass {
+ No_OpClass = 0, /* inst does not use a functional unit */
+ IntALU, /* integer ALU */
+ IntMULT, /* integer multiplier */
+ IntDIV, /* integer divider */
+ FloatADD, /* floating point adder/subtractor */
+ FloatCMP, /* floating point comparator */
+ FloatCVT, /* floating point<->integer converter */
+ FloatMULT, /* floating point multiplier */
+ FloatDIV, /* floating point divider */
+ FloatSQRT, /* floating point square root */
+ RdPort, /* memory read port */
+ WrPort, /* memory write port */
+ LvqPort, /* load value queue read port (redundant threading) */
+ IPrefPort,
+ Num_OpClasses /* total functional unit classes */
+};
+
+/**
+ * Array mapping OpClass enum values to strings.
+ */
+extern const char *opClassStrings[];
+
+#endif // __OP_CLASS_HH__
diff --git a/sim/param.cc b/sim/param.cc
new file mode 100644
index 000000000..432953670
--- /dev/null
+++ b/sim/param.cc
@@ -0,0 +1,760 @@
+/*
+ * 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 <list>
+#include <string>
+#include <vector>
+#include <stdio.h> // for sscanf()
+
+#include <assert.h>
+
+#include "param.hh"
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "config_node.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "trace.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// BaseParam member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+void
+BaseParam::die(const string &err) const
+{
+ context->printErrorProlog(cerr);
+ cerr << " parameter '" << name << "': "
+ << err << endl;
+ abort();
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Param<T> and VectorParam<T> member definitions
+//
+// We implement parsing & displaying values for various parameter
+// types T using a set of overloaded functions:
+//
+// - parseParam(string s, T &value) parses s into value
+// - showParam(ostream &os, T &value) displays value on os
+//
+// By making these independent functions, we can reuse the same code
+// for type T in both Param<T> and VectorParam<T>.
+//
+// For enum types, the parseParam function requires additional
+// arguments, in which case we must specialize the Param<T>::parse and
+// VectorParam<T>::parse calls as well.
+//
+// Type-specific instances come first, followed by more generic
+// templated versions and their instantiations.
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Integer types all use to_number for parsing and '<<' for
+// displaying
+//
+#define INT_PARAM(type) \
+bool \
+parseParam(const string &s, type &value) \
+{ \
+ return to_number(s, value); \
+} \
+ \
+void \
+showParam(ostream &os, type value) \
+{ \
+ os << value; \
+}
+
+INT_PARAM(unsigned long long)
+INT_PARAM(signed long long)
+INT_PARAM(unsigned long)
+INT_PARAM(signed long)
+INT_PARAM(unsigned int)
+INT_PARAM(signed int)
+INT_PARAM(unsigned short)
+INT_PARAM(signed short)
+INT_PARAM(unsigned char)
+INT_PARAM(signed char)
+
+#undef INT_PARAM
+
+//
+// Floating-point types
+//
+bool
+parseParam(const string &s, float &value)
+{
+ return (sscanf(s.c_str(), "%f", &value) == 1);
+}
+
+bool
+parseParam(const string &s, double &value)
+{
+ return (sscanf(s.c_str(), "%lf", &value) == 1);
+}
+
+void showParam(ostream &os, float value) { os << value; }
+void showParam(ostream &os, double value) { os << value; }
+
+//
+// bool
+//
+bool
+parseParam(const string &s, bool &value)
+{
+ const string &lower = to_lower(s);
+
+ if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") {
+ value = true;
+ return true;
+ }
+
+ if (lower == "false" || lower == "f" || lower == "no" || lower == "n") {
+ value = false;
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+showParam(ostream &os, bool value)
+{
+ os << (value ? "true" : "false");
+}
+
+
+//
+// string
+//
+bool
+parseParam(const string &s, string &value)
+{
+ value = s;
+ return true;
+}
+
+
+void
+showParam(ostream &os, const string &value)
+{
+ os << value;
+}
+
+//
+// End of parseParam/showParam definitions. Now we move on to
+// incorporate them into the Param/VectorParam parse() and showValue()
+// methods.
+//
+
+// These definitions for Param<T>::parse and VectorParam<T>::parse
+// work for any type for which parseParam() takes only two arguments
+// (i.e., all the fundamental types like int, bool, etc.), thanks to
+// overloading.
+template <class T>
+void
+Param<T>::parse(const string &s)
+{
+ if (parseParam(s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class T>
+void
+VectorParam<T>::parse(const string &s)
+{
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+
+ // assign parsed value to vector
+ value[i] = scalar_value;
+ }
+
+ wasSet = true;
+}
+
+// These definitions for Param<T>::showValue() and
+// VectorParam<T>::showValue() work for any type where showParam()
+// takes only two arguments (i.e., everything but the SimpleEnum and
+// MappedEnum classes).
+template <class T>
+void
+Param<T>::showValue(ostream &os) const
+{
+ showParam(os, value);
+}
+
+template <class T>
+void
+VectorParam<T>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showParam(os, value[i]);
+ }
+}
+
+
+#ifdef INSURE_BUILD
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+} \
+template Param<type>; \
+template VectorParam<type>;
+
+#else
+// instantiate all four methods (parse/show, scalar/vector) for basic
+// types that can use the above templates
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+template void Param<type>::parse(const string &); \
+template void VectorParam<type>::parse(const string &); \
+template void Param<type>::showValue(ostream &) const; \
+template void VectorParam<type>::showValue(ostream &) const; \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+}
+#endif
+
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
+INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
+INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
+INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
+INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
+INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
+INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
+INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
+INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
+INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
+
+INSTANTIATE_PARAM_TEMPLATES(float, "float")
+INSTANTIATE_PARAM_TEMPLATES(double, "double")
+
+INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
+INSTANTIATE_PARAM_TEMPLATES(string, "string")
+
+#undef INSTANTIATE_PARAM_TEMPLATES
+
+//
+// SimpleEnumParam & MappedEnumParam must specialize their parse(),
+// showValue(), and showType() methods.
+//
+
+//
+// SimpleEnumParam & SimpleEnumVectorParam
+//
+bool
+parseEnumParam(const char *const *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i]) {
+ value = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const char *const *map, const int num_values,
+ int value)
+{
+ assert(0 <= value && value < num_values);
+ os << map[value];
+}
+
+void
+showEnumType(ostream &os,
+ const char *const *map, const int num_values)
+{
+ os << "{" << map[0];
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i];
+
+ os << "}";
+}
+
+
+//
+// MappedEnumParam & MappedEnumVectorParam
+//
+bool
+parseEnumParam(const EnumParamMap *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i].name) {
+ value = map[i].value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const EnumParamMap *map, const int num_values,
+ int value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (value == map[i].value) {
+ os << map[i].name;
+ return;
+ }
+ }
+
+ // if we can't find a reverse mapping just print the int value
+ os << value;
+}
+
+void
+showEnumType(ostream &os,
+ const EnumParamMap *map, const int num_values)
+{
+ os << "{" << map[0].name;
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i].name;
+
+ os << "}";
+}
+
+
+template <class Map>
+void
+EnumParam<Map>::parse(const string &s)
+{
+ if (parseEnumParam(map, num_values, s, value)) {
+ wasSet = true;
+ } else {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::parse(const string &s)
+{
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+template <class Map>
+void
+EnumParam<Map>::showValue(ostream &os) const
+{
+ showEnumParam(os, map, num_values, value);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showEnumParam(os, map, num_values, value[i]);
+ }
+}
+
+template <class Map>
+void
+EnumParam<Map>::showType(ostream &os) const
+{
+ showEnumType(os, map, num_values);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showType(ostream &os) const
+{
+ os << "vector of";
+ showEnumType(os, map, num_values);
+}
+
+template EnumParam<const char *>;
+template EnumVectorParam<const char *>;
+
+template EnumParam<EnumParamMap>;
+template EnumVectorParam<EnumParamMap>;
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectBaseParam methods
+//
+////////////////////////////////////////////////////////////////////////
+
+bool
+parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
+{
+ SimObject *obj;
+
+ if (to_lower(s) == "null") {
+ // explicitly set to null by user; assume that's OK
+ obj = NULL;
+ }
+ else {
+ obj = context->resolveSimObject(s);
+
+ if (obj == NULL)
+ return false;
+ }
+
+ value = obj;
+ return true;
+}
+
+
+void
+SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
+{
+ os << (value ? value->name() : "null");
+}
+
+void
+SimObjectBaseParam::parse(const string &s, SimObject *&value)
+{
+ if (parseSimObjectParam(context, s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+void
+SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
+{
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseSimObjectParam(context, tokens[i], value[i])) {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ParamContext member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+list<ParamContext *> *ParamContext::ctxList = NULL;
+
+ParamContext::ParamContext(const string &_iniSection, bool noAutoParse)
+ : iniFilePtr(NULL), // initialized on call to parseParams()
+ iniSection(_iniSection), paramList(NULL)
+{
+ if (!noAutoParse) {
+ if (ctxList == NULL)
+ ctxList = new list<ParamContext *>();
+
+ (*ctxList).push_back(this);
+ }
+}
+
+
+void
+ParamContext::addParam(BaseParam *param)
+{
+ getParamList()->push_back(param);
+}
+
+
+void
+ParamContext::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ string string_value;
+
+ if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ }
+}
+
+
+// Check parameter values for validity & consistency. Default
+// implementation is no-op; derive subclass & override to add
+// actual functionality here.
+void
+ParamContext::checkParams()
+{
+ // nada
+}
+
+
+// Clean up context-related objects at end of execution. Default
+// implementation is no-op; derive subclass & override to add actual
+// functionality here.
+void
+ParamContext::cleanup()
+{
+ // nada
+}
+
+
+void
+ParamContext::describeParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ os << p->name << " (";
+ p->showType(os);
+ os << "): " << p->description << "\n";
+ }
+}
+
+
+
+void
+ParamContext::showParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ if (p->isValid()) {
+ os << p->name << "=";
+ p->showValue(os);
+ os << endl;
+ }
+ else {
+ os << "// "<< p->name << " not specified" << endl;
+ }
+ }
+}
+
+
+void
+ParamContext::printErrorProlog(ostream &os)
+{
+ os << "Parameter error in section [" << iniSection << "]: " << endl;
+}
+
+//
+// Resolve an object name to a SimObject pointer. The object will be
+// created as a side-effect if necessary. If the name contains a
+// colon (e.g., "iq:IQ"), then the object is local (invisible to
+// outside this context). If there is no colon, the name needs to be
+// resolved through the configuration hierarchy (only possible for
+// SimObjectBuilder objects, which return non-NULL for configNode()).
+//
+SimObject *
+ParamContext::resolveSimObject(const string &_name)
+{
+ // look for a colon
+ string::size_type i = _name.find(':');
+ string name = _name;
+ if (i != string::npos) {
+ // colon found: local object
+ // add as child to current node and create it
+ name = _name.substr(0, i);
+ string objConfigClassName = _name.substr(i + 1);
+ getConfigNode()->addChild(name, objConfigClassName);
+ }
+ ConfigNode *n = getConfigNode();
+ return n ? n->resolveSimObject(name) : NULL;
+}
+
+
+//
+// static method: call parseParams() on all registered contexts
+//
+void
+ParamContext::parseAllContexts(IniFile &iniFile)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->parseParams(iniFile);
+ }
+}
+
+
+//
+// static method: call checkParams() on all registered contexts
+//
+void
+ParamContext::checkAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->checkParams();
+ }
+}
+
+
+//
+// static method: call showParams() on all registered contexts
+//
+void
+ParamContext::showAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]" << endl;
+ pc->showParams(os);
+ os << endl;
+ }
+}
+
+
+//
+// static method: call cleanup() on all registered contexts
+//
+void
+ParamContext::cleanupAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->cleanup();
+ }
+}
+
+
+//
+// static method: call describeParams() on all registered contexts
+//
+void
+ParamContext::describeAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]\n";
+ pc->describeParams(os);
+ os << endl;
+ }
+}
diff --git a/sim/param.hh b/sim/param.hh
new file mode 100644
index 000000000..983032854
--- /dev/null
+++ b/sim/param.hh
@@ -0,0 +1,757 @@
+/*
+ * 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 __PARAM_HH__
+#define __PARAM_HH__
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "configfile.hh"
+
+// forward decls
+class BaseParam;
+class SimObject;
+struct stat_sdb_t;
+
+//
+// The context of a parameter definition... usually a subclass of
+// SimObjectBuilder (which derives from ParamContext), but abstracted
+// here to support more global simulator control parameters as well.
+//
+class ParamContext
+{
+ private:
+
+ // static list of all ParamContext objects, built as a side effect
+ // of the ParamContext constructor
+ static std::list<ParamContext *> *ctxList;
+
+ protected:
+
+ // .ini file (database) for parameter lookup... initialized on call
+ // to parseParams()
+ IniFile *iniFilePtr;
+
+ // .ini file section for parameter lookup
+ const std::string iniSection;
+
+ typedef std::vector<BaseParam *> ParamList;
+
+ // list of parameters defined in this context
+ ParamList *paramList;
+
+ ParamList *getParamList() {
+ if (!paramList)
+ paramList = new ParamList;
+ return paramList;
+ }
+
+ public:
+
+ // Second arg, if set to true, says don't put on paramContextList
+ // (i.e. don't automatically parse params). Used by derived
+ // SimObjectBuilder class, where parsing is done in
+ // SimObject::create()
+ ParamContext(const std::string &_iniSection, bool noAutoParse = false);
+
+ virtual ~ParamContext() {}
+
+ // add a parameter to the context... called from the parameter
+ // object's constructor (see BaseParam::BaseParam())
+ void addParam(BaseParam *);
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // Check parameter values for validity & consistency. Default
+ // implementation is no-op; derive subclass & override to add
+ // actual functionality here
+ virtual void checkParams();
+
+ // Clean up at end of execution: close file descriptors, etc.
+ // Default implementation is no-op; derive subclass & override to
+ // add actual functionality here
+ virtual void cleanup();
+
+ // dump parameter descriptions
+ void describeParams(std::ostream &);
+
+ // Display the parameters & values used
+ void showParams(std::ostream &);
+
+ // print context information for parameter error
+ virtual void printErrorProlog(std::ostream &);
+
+ // resolve a SimObject name in this context to an object pointer.
+ virtual SimObject *resolveSimObject(const std::string &name);
+
+ // generate the name for this instance of this context (used as a
+ // prefix to create unique names in resolveSimObject()
+ virtual const std::string &getInstanceName() { return iniSection; }
+
+ // return the configuration hierarchy node for this context. Bare
+ // ParamContext objects have no corresponding node, so the default
+ // implementation returns NULL.
+ virtual ConfigNode *getConfigNode() { return NULL; }
+
+ // Parse all parameters registered with all ParamContext objects.
+ static void parseAllContexts(IniFile &iniFile);
+
+ // Check all parameters registered with all ParamContext objects.
+ // (calls checkParams() on each)
+ static void checkAllContexts();
+
+ // Print all parameter values on indicated ostream.
+ static void showAllContexts(std::ostream &os);
+
+ // Clean up all registered ParamContext objects. (calls cleanup()
+ // on each)
+ static void cleanupAllContexts();
+
+ // print descriptions of all parameters registered with all
+ // ParamContext objects
+ static void describeAllContexts(std::ostream &os);
+};
+
+
+//
+// Base class for all parameter objects
+//
+class BaseParam
+{
+ public:
+
+ ParamContext *context;
+ std::string name;
+ std::string description; // text description for help message
+ bool wasSet; // true if parameter was set by user
+ bool hasDefault; // true if parameter has default value
+
+ BaseParam(ParamContext *_context, const std::string &_name,
+ const std::string &_description, bool _hasDefault)
+ : context(_context), name(_name), description(_description),
+ wasSet(false), hasDefault(_hasDefault)
+ {
+ context->addParam(this);
+ }
+
+ virtual ~BaseParam() {}
+
+ // a parameter is valid only if its value was set by the user or
+ // it has a default value
+ bool isValid() const
+ {
+ return (wasSet || hasDefault);
+ }
+
+ // set value by parsing string
+ virtual void parse(const std::string &s) = 0;
+
+ // display value to stream
+ virtual void showValue(std::ostream &) const = 0;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const = 0;
+
+ // signal parse or usage error
+ virtual void die(const std::string &err) const;
+};
+
+//
+// Template classes to specialize parameters to specific types.
+//
+// Param<T> is for single-valued (scalar) parameters of type T.
+// VectorParam<T> is for multi-valued (vector) parameters of type T.
+// These are specified in the .ini file as a space-delimited list of
+// arguments.
+//
+template <class T>
+class Param : public BaseParam
+{
+ protected:
+
+ T value;
+
+ public:
+
+ // Param with default value: set value to default
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description, T dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~Param() {}
+
+ operator T&()
+ {
+ // if we attempt to reference an invalid parameter (i.e., one
+ // with no default value that was not set by the user), die.
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+
+//
+// Template class for vector-valued parameters (lists)
+//
+template <class T>
+class VectorParam : public BaseParam
+{
+ protected:
+
+ std::vector<T> value;
+
+ public:
+
+ typedef typename std::vector<T>::size_type size_type;
+
+ // Param with default value: set value to default
+ VectorParam(ParamContext *context, const std::string &name,
+ const std::string &description,
+ const std::vector<T> &dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ VectorParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~VectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ const T &operator[](size_type n) const
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Specialization of Param<int> and VectorParam<int> to handle
+// enumerated types is done in two ways, using SimpleEnumParam and
+// MappedEnumParam (and their vector counterparts,
+// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam
+// takes an array of strings and maps them to integers based on array
+// index. MappedEnumParam takes an array of string-to-int mappings,
+// allowing for mapping strings to non-contiguous integer values, or
+// mapping multiple strings to the same integer value.
+//
+// Both SimpleEnumParam and MappedEnumParam are implemented using a
+// single template class, EnumParam<Map>, which takes the type of the map
+// as a parameter (const char * or EnumParamMap). Similarly,
+// SimpleEnumVectorParam and MappedEnumVectorParam are both
+// implemented using EnumVectorParam<Map>.
+//
+template <class Map>
+class EnumParam : public Param<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ int dfltValue)
+ : Param<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : Param<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Vector counterpart to SimpleEnumParam
+//
+template <class Map>
+class EnumVectorParam : public VectorParam<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ std::vector<int> &dfltValue)
+ : VectorParam<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : VectorParam<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumVectorParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumParam : public EnumParam<const char *>
+{
+ public:
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM() const
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value;
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumVectorParam : public EnumVectorParam<const char *>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ SimpleEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const char **_map, int _num_values)
+ : EnumVectorParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Handle enums via string-to-int map (see comment above).
+//
+
+// An array of string-to-int mappings must be supplied using the
+// following type.
+typedef struct {
+ const char *name;
+ int value;
+} EnumParamMap;
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumParam : public EnumParam<EnumParamMap>
+{
+ public:
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM()
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ MappedEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumVectorParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Parameters that point to other simulation objects (e.g. caches,
+// busses, etc.) are handled by specializing SimObjectBaseParam to the
+// specific subtype. The main purpose of SimObjectBaseParam is to
+// provide a place to stick several helper functions common to all
+// SimObject-derived parameters.
+//
+class SimObjectBaseParam : public BaseParam
+{
+ public:
+
+ SimObjectBaseParam(ParamContext *context, const std::string &name,
+ const std::string &description, bool hasDefault)
+ : BaseParam(context, name, description, hasDefault)
+ {
+ }
+
+ virtual ~SimObjectBaseParam() {}
+
+ // helper function for SimObjectParam<T>::showValue()
+ void showValue(std::ostream &os, SimObject *obj) const;
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, SimObject *&value);
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, std::vector<SimObject *>&value_vec);
+};
+
+
+//
+// Parameter to a specific type of SimObject. Note that T must be a
+// pointer to a class derived from SimObject (e.g., <CPU *>).
+//
+
+template <class T> class SimObjectParam;
+
+template <class T>
+class SimObjectParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ T *value;
+
+ public:
+
+ // initialization w/o default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ // initialization wit=h default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ T *dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectParam() {}
+
+ // convert to pointer
+ operator T*()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ T *operator->() const
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ SimObjectBaseParam::showValue(os, value);
+ }
+
+ // display type to stream: see REGISTER_SIM_OBJECT macro in
+ // sim_object.hh for declaration
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ SimObject *so_ptr;
+ // first parse to generic SimObject *
+ SimObjectBaseParam::parse(s, so_ptr);
+ // now dynamic_cast to specific derived type
+ value = dynamic_cast<T *>(so_ptr);
+ // check for failure of dynamic_cast
+ if (value == NULL && so_ptr != NULL)
+ die("not of appropriate type");
+ }
+};
+
+
+//
+// Vector counterpart to SimObjectParam<T>
+//
+
+template <class T> class SimObjectVectorParam;
+
+template <class T>
+class SimObjectVectorParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ std::vector<T *> value;
+
+ public:
+
+ typedef typename std::vector<T *>::size_type size_type;
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ std::vector<T *> dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectVectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ T *&operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T *>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0)
+ os << " ";
+ SimObjectBaseParam::showValue(os, value[i]);
+ }
+ }
+
+ // display type to stream: see
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ std::vector<SimObject *> so_ptr_vec;
+ // first parse to generic SimObject * vector (from SimObjectBaseParam)
+ SimObjectBaseParam::parse(s, so_ptr_vec);
+
+ value.resize(so_ptr_vec.size());
+
+ for (int i = 0; i < so_ptr_vec.size(); ++i) {
+ // now dynamic_cast to specific derived type
+ value[i] = dynamic_cast<T *>(so_ptr_vec[i]);
+ // check for failure of dynamic_cast
+ if (value[i] == NULL && so_ptr_vec[i] != NULL)
+ die("not of appropriate type");
+ }
+ }
+};
+
+//
+// Macro to define showType() methods for SimObjectParam &
+// SimObjectVectorParam. Can't do this automatically as it requires a
+// string name for the type, which you can't get from a template
+// argument. For concrete derived SimObject types, this macro is
+// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh).
+//
+#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \
+void \
+SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << CLASS_NAME; \
+} \
+ \
+void \
+SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << "vector of " << CLASS_NAME; \
+}
+
+#endif // _PARAM_HH
diff --git a/sim/pc_event.cc b/sim/pc_event.cc
new file mode 100644
index 000000000..4de425199
--- /dev/null
+++ b/sim/pc_event.cc
@@ -0,0 +1,231 @@
+/*
+ * 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 <map>
+#include <string>
+#include <utility>
+
+#include "debug.hh"
+#include "exec_context.hh"
+#include "pc_event.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+#ifdef FULL_SYSTEM
+#include "arguments.hh"
+#include "pmap.h"
+#include "kernel.hh"
+#include "memory_control.hh"
+#include "cpu.hh"
+#include "system.hh"
+#include "bpred.hh"
+#endif
+
+using namespace std;
+
+PCEventQueue::PCEventQueue()
+{}
+
+PCEventQueue::~PCEventQueue()
+{}
+
+bool
+PCEventQueue::remove(PCEvent *event)
+{
+ int removed = 0;
+ range_t range = equal_range(event);
+ for (iterator i = range.first; i != range.second; ++i) {
+ if (*i == event) {
+ DPRINTF(PCEvent, "PC based event removed at %#x: %s\n",
+ event->pc(), event->descr());
+ pc_map.erase(i);
+ ++removed;
+ }
+ }
+
+ return removed > 0;
+}
+
+bool
+PCEventQueue::schedule(PCEvent *event)
+{
+ pc_map.push_back(event);
+ sort(pc_map.begin(), pc_map.end(), MapCompare());
+
+ DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n",
+ event->pc(), event->descr());
+
+ return true;
+}
+
+bool
+PCEventQueue::service(ExecContext *xc)
+{
+ Addr pc = xc->regs.pc;
+ int serviced = 0;
+ range_t range = equal_range(pc);
+ for (iterator i = range.first; i != range.second; ++i) {
+ // Make sure that the pc wasn't changed as the side effect of
+ // another event. This for example, prevents two invocations
+ // of the SkipFuncEvent. Maybe we should have separate PC
+ // event queues for each processor?
+ if (pc != xc->regs.pc)
+ continue;
+
+ DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
+ (*i)->pc(), (*i)->descr());
+
+ (*i)->process(xc);
+ ++serviced;
+ }
+
+ return serviced > 0;
+}
+
+void
+PCEventQueue::dump() const
+{
+ const_iterator i = pc_map.begin();
+ const_iterator e = pc_map.end();
+
+ for (; i != e; ++i)
+ cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(),
+ (*i)->descr());
+}
+
+PCEventQueue::range_t
+PCEventQueue::equal_range(Addr pc)
+{
+ return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare());
+}
+
+#ifdef FULL_SYSTEM
+void
+SkipFuncEvent::process(ExecContext *xc)
+{
+ Addr newpc = xc->regs.intRegFile[ReturnAddressReg];
+
+ DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
+ xc->regs.pc, newpc);
+
+ xc->regs.pc = newpc;
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ BranchPred *bp = xc->cpu->getBranchPred();
+ if (bp != NULL) {
+ bp->popRAS(xc->thread_num);
+ }
+}
+
+void
+BadAddrEvent::process(ExecContext *xc)
+{
+ // The following gross hack is the equivalent function to the
+ // annotation for vmunix::badaddr in:
+ // simos/simulation/apps/tcl/osf/tlaser.tcl
+
+ uint64_t a0 = xc->regs.intRegFile[ArgumentReg0];
+
+ if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE ||
+ xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) {
+
+ DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
+ xc->regs.intRegFile[ReturnValueReg] = 0x1;
+ SkipFuncEvent::process(xc);
+ }
+ else
+ DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
+}
+
+void
+PrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(Printf)) {
+ DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DebugPrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ if (!raw)
+ DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DumpMbufEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ AlphaArguments args(xc);
+ Kernel::DumpMbuf(args);
+ }
+}
+#endif
+
+BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
+ : PCEvent(q, desc), remove(del)
+{
+}
+
+void
+BreakPCEvent::process(ExecContext *xc)
+{
+ debug_break();
+ if (remove)
+ delete this;
+}
+
+#ifdef FULL_SYSTEM
+extern "C"
+void
+sched_break_pc_sys(System *sys, Addr addr)
+{
+ PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
+ event->schedule(addr);
+}
+
+extern "C"
+void
+sched_break_pc(Addr addr)
+{
+ for (vector<System *>::iterator sysi = System::systemList.begin();
+ sysi != System::systemList.end(); ++sysi) {
+ sched_break_pc_sys(*sysi, addr);
+ }
+
+}
+#endif
diff --git a/sim/pc_event.hh b/sim/pc_event.hh
new file mode 100644
index 000000000..24442f5f4
--- /dev/null
+++ b/sim/pc_event.hh
@@ -0,0 +1,215 @@
+/*
+ * 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 __PC_EVENT_HH__
+#define __PC_EVENT_HH__
+
+#include <vector>
+
+#include "mem_req.hh"
+
+class ExecContext;
+class PCEventQueue;
+
+class PCEvent
+{
+ protected:
+ static const Addr badpc = MemReq::inval_addr;
+
+ protected:
+ std::string description;
+ PCEventQueue *queue;
+ Addr evpc;
+
+ public:
+ PCEvent() : queue(0), evpc(badpc) { }
+
+ PCEvent(const std::string &desc)
+ : description(desc), queue(0), evpc(badpc) { }
+
+ PCEvent(PCEventQueue *q, Addr pc = badpc) : queue(q), evpc(pc) { }
+
+ PCEvent(PCEventQueue *q, const std::string &desc, Addr pc = badpc)
+ : description(desc), queue(q), evpc(pc) { }
+
+ virtual ~PCEvent() { if (queue) remove(); }
+
+ std::string descr() const { return description; }
+ Addr pc() const { return evpc; }
+
+ bool remove();
+ bool schedule();
+ bool schedule(Addr pc);
+ bool schedule(PCEventQueue *q, Addr pc);
+ virtual void process(ExecContext *xc) = 0;
+};
+
+class PCEventQueue
+{
+ protected:
+ typedef PCEvent * record_t;
+ class MapCompare {
+ public:
+ bool operator()(const record_t &l, const record_t &r) const {
+ return l->pc() < r->pc();
+ }
+ bool operator()(const record_t &l, Addr pc) const {
+ return l->pc() < pc;
+ }
+ bool operator()(Addr pc, const record_t &r) const {
+ return pc < r->pc();
+ }
+ };
+ typedef std::vector<record_t> map_t;
+
+ public:
+ typedef map_t::iterator iterator;
+ typedef map_t::const_iterator const_iterator;
+
+ protected:
+ typedef std::pair<iterator, iterator> range_t;
+ typedef std::pair<const_iterator, const_iterator> const_range_t;
+
+ protected:
+ map_t pc_map;
+
+ public:
+ PCEventQueue();
+ ~PCEventQueue();
+
+ bool remove(PCEvent *event);
+ bool schedule(PCEvent *event);
+ bool service(ExecContext *xc);
+
+ range_t equal_range(Addr pc);
+ range_t equal_range(PCEvent *event) { return equal_range(event->pc()); }
+
+ void dump() const;
+};
+
+inline bool
+PCEvent::remove()
+{
+ if (!queue)
+ panic("cannot remove an uninitialized event;");
+
+ return queue->remove(this);
+}
+
+inline bool
+PCEvent::schedule()
+{
+ if (!queue || evpc == badpc)
+ panic("cannot schedule an uninitialized event;");
+
+ return queue->schedule(this);
+}
+
+inline bool
+PCEvent::schedule(Addr pc)
+{
+ if (evpc != badpc)
+ panic("cannot switch PC");
+ evpc = pc;
+
+ return schedule();
+}
+
+inline bool
+PCEvent::schedule(PCEventQueue *q, Addr pc)
+{
+ if (queue)
+ panic("cannot switch event queues");
+
+ if (evpc != badpc)
+ panic("cannot switch addresses");
+
+ queue = q;
+ evpc = pc;
+
+ return schedule();
+}
+
+
+#ifdef FULL_SYSTEM
+class SkipFuncEvent : public PCEvent
+{
+ public:
+ SkipFuncEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class BadAddrEvent : public SkipFuncEvent
+{
+ public:
+ BadAddrEvent(PCEventQueue *q, const std::string &desc)
+ : SkipFuncEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class PrintfEvent : public PCEvent
+{
+ public:
+ PrintfEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DebugPrintfEvent : public PCEvent
+{
+ private:
+ bool raw;
+
+ public:
+ DebugPrintfEvent(PCEventQueue *q, const std::string &desc, bool r = false)
+ : PCEvent(q, desc), raw(r) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DumpMbufEvent : public PCEvent
+{
+ public:
+ DumpMbufEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+#endif
+
+class BreakPCEvent : public PCEvent
+{
+ protected:
+ bool remove;
+
+ public:
+ BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del = false);
+ virtual void process(ExecContext *xc);
+};
+
+
+#endif // __PC_EVENT_HH__
diff --git a/sim/predictor.hh b/sim/predictor.hh
new file mode 100644
index 000000000..7c446f26c
--- /dev/null
+++ b/sim/predictor.hh
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+//
+// Abstract base class for a generic predictor
+//
+//
+
+#ifndef __PREDICTOR_HH__
+#define __PREDICTOR_HH__
+
+struct stat_sdb_t;
+
+class GenericPredictor {
+
+ public:
+ virtual void clear() = 0;
+
+ virtual unsigned predict(unsigned long _index) = 0;
+ virtual unsigned predict(unsigned long _index, unsigned &pdata) = 0;
+
+ virtual unsigned peek(unsigned long _index) = 0;
+
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value) = 0;
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value, unsigned _pdata) = 0;
+
+ virtual unsigned value(unsigned long _index) = 0;
+
+ virtual void regStats() = 0;
+ virtual void regFormulas() = 0;
+
+ virtual ~GenericPredictor() {};
+};
+
+#endif // __PREDICTOR_HH__
diff --git a/sim/prog.cc b/sim/prog.cc
new file mode 100644
index 000000000..8615cab68
--- /dev/null
+++ b/sim/prog.cc
@@ -0,0 +1,281 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "main_memory.hh"
+#include "prog.hh"
+
+#include "eio.hh"
+#include "thread.hh"
+#include "fake_syscall.hh"
+#include "loader.hh"
+#include "exec_context.hh"
+#include "smt.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
+// mode when we do have an OS
+//
+#ifdef FULL_SYSTEM
+#error "prog.cc not compatible with FULL_SYSTEM"
+#endif
+
+// max allowable number of processes: should be no real cost to
+// cranking this up if necessary
+const int MAX_PROCESSES = 8;
+
+// current number of allocated processes
+int num_processes = 0;
+
+Process::Process(const string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd)
+ : SimObject(name)
+{
+ // allocate memory space
+ memory = new MainMemory(name + ".MainMem");
+
+ // allocate initial register file
+ init_regs = new RegFile;
+
+ // initialize first 3 fds (stdin, stdout, stderr)
+ fd_map[STDIN_FILENO] = stdin_fd;
+ fd_map[STDOUT_FILENO] = stdout_fd;
+ fd_map[STDERR_FILENO] = stderr_fd;
+
+ // mark remaining fds as free
+ for (int i = 3; i <= MAX_FD; ++i) {
+ fd_map[i] = -1;
+ }
+
+ numCpus = 0;
+
+ num_syscalls = 0;
+
+ // other parameters will be initialized when the program is loaded
+}
+
+void
+Process::regStats()
+{
+ using namespace Statistics;
+
+ num_syscalls
+ .name(name() + ".PROG:num_syscalls")
+ .desc("Number of system calls")
+ ;
+}
+
+//
+// static helper functions
+//
+int
+Process::openInputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_RDONLY);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for reading\n";
+ fatal("can't open input file");
+ }
+
+ return fd;
+}
+
+
+int
+Process::openOutputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for writing\n";
+ fatal("can't open output file");
+ }
+
+ return fd;
+}
+
+
+void
+Process::registerExecContext(ExecContext *ec)
+{
+ if (execContexts.empty()) {
+ // first exec context for this process... initialize & enable
+
+ // copy process's initial regs struct
+ ec->regs = *init_regs;
+
+ // mark this context as active
+ ec->setStatus(ExecContext::Active);
+ }
+ else {
+ ec->setStatus(ExecContext::Unallocated);
+ }
+
+ // add to list
+ execContexts.push_back(ec);
+
+ // increment available CPU count
+ ++numCpus;
+}
+
+
+// map simulator fd sim_fd to target fd tgt_fd
+void
+Process::dup_fd(int sim_fd, int tgt_fd)
+{
+ if (tgt_fd < 0 || tgt_fd > MAX_FD)
+ panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
+
+ fd_map[tgt_fd] = sim_fd;
+}
+
+
+// generate new target fd for sim_fd
+int
+Process::open_fd(int sim_fd)
+{
+ int free_fd;
+
+ // in case open() returns an error, don't allocate a new fd
+ if (sim_fd == -1)
+ return -1;
+
+ // find first free target fd
+ for (free_fd = 0; fd_map[free_fd] >= 0; ++free_fd) {
+ if (free_fd == MAX_FD)
+ panic("Process::open_fd: out of file descriptors!");
+ }
+
+ fd_map[free_fd] = sim_fd;
+
+ return free_fd;
+}
+
+
+// look up simulator fd for given target fd
+int
+Process::sim_fd(int tgt_fd)
+{
+ if (tgt_fd > MAX_FD)
+ return -1;
+
+ return fd_map[tgt_fd];
+}
+
+
+
+//
+// need to declare these here since there is no concrete Process type
+// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
+// which is where these get declared for concrete types).
+//
+DEFINE_SIM_OBJECT_CLASS_NAME("Process object", Process)
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// LiveProcess member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+LiveProcess::LiveProcess(const string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ vector<string> &argv, vector<string> &envp)
+ : Process(name, stdin_fd, stdout_fd, stderr_fd)
+{
+ smt_load_prog(argv, envp, init_regs, this);
+}
+
+
+void
+LiveProcess::syscall(ExecContext *xc)
+{
+ num_syscalls++;
+
+ fake_syscall(this, xc);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings")
+
+END_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+CREATE_SIM_OBJECT(LiveProcess)
+{
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd = input.isValid() ? Process::openInputFile(input) : 0;
+ int stdout_fd = output.isValid() ? Process::openOutputFile(output) : 1;
+ int stderr_fd = output.isValid() ? stdout_fd : 2;
+
+ // dummy for default env
+ vector<string> null_vec;
+
+ // We do this with "temp" because of the bogus compiler warning
+ // you get with g++ 2.95 -O if you just "return new LiveProcess(..."
+ LiveProcess *temp = new LiveProcess(getInstanceName(),
+ stdin_fd, stdout_fd, stderr_fd,
+ cmd,
+ env.isValid() ? env : null_vec);
+
+ return temp;
+}
+
+
+REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/sim/prog.hh b/sim/prog.hh
new file mode 100644
index 000000000..a38afee14
--- /dev/null
+++ b/sim/prog.hh
@@ -0,0 +1,180 @@
+/*
+ * 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 __PROG_HH__
+#define __PROG_HH__
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no reason to use it in FULL_SYSTEM
+// mode when we do have an OS.
+//
+#ifndef FULL_SYSTEM
+
+#include <list>
+
+#include "stats.hh"
+#include "sim_object.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class ExecContext;
+class FunctionalMemory;
+class Process : public SimObject
+{
+ public:
+
+ // have we initialized an execution context from this process? If
+ // yes, subsequent contexts are assumed to be for dynamically
+ // created threads and are not initialized.
+ bool initialContextLoaded;
+
+ // execution contexts associated with this process
+ std::list<ExecContext *> execContexts;
+ // number of CPUs assigned to this process: should match number of
+ // contexts in execContexts list
+ unsigned numCpus;
+
+ // record of blocked context
+ struct WaitRec
+ {
+ Addr waitChan;
+ ExecContext *waitingContext;
+
+ WaitRec(Addr chan, ExecContext *ctx)
+ : waitChan(chan), waitingContext(ctx)
+ {
+ }
+ };
+
+ // list of all blocked contexts
+ std::list<WaitRec> waitList;
+
+ RegFile *init_regs; // initial register contents
+
+ Addr text_base; // text (code) segment base
+ unsigned text_size; // text (code) size in bytes
+
+ Addr data_base; // initialized data segment base
+ unsigned data_size; // initialized data + bss size in bytes
+
+ Addr brk_point; // top of the data segment
+
+ Addr environ_base; // environment base address
+ Addr stack_base; // stack segment base (highest address)
+ unsigned stack_size; // initial stack size
+ Addr stack_min; // lowest address accessed on the stack
+
+
+ // addr to use for next stack region (for multithreaded apps)
+ Addr next_thread_stack_base;
+
+ std::string prog_fname; // file name
+ Addr prog_entry; // entry point (initial PC)
+
+ Statistics::Scalar<> num_syscalls; // number of syscalls executed
+
+
+ protected:
+ // constructor
+ Process(const std::string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd);
+
+
+ protected:
+ FunctionalMemory *memory;
+
+ private:
+ // file descriptor remapping support
+ static const int MAX_FD = 100; // max legal fd value
+ int fd_map[MAX_FD+1];
+
+ public:
+ // static helper functions to generate file descriptors for constructor
+ static int openInputFile(const std::string &filename);
+ static int openOutputFile(const std::string &filename);
+
+ // override of virtual SimObject method: register statistics
+ virtual void regStats();
+
+ // register an execution context for this process
+ void registerExecContext(ExecContext *);
+
+ // map simulator fd sim_fd to target fd tgt_fd
+ void dup_fd(int sim_fd, int tgt_fd);
+
+ // generate new target fd for sim_fd
+ int open_fd(int sim_fd);
+
+ // look up simulator fd for given target fd
+ int sim_fd(int tgt_fd);
+
+ // is this a valid instruction fetch address?
+ bool validInstAddr(Addr addr)
+ {
+ return (text_base <= addr &&
+ addr < text_base + text_size &&
+ !(addr & (sizeof(MachInst)-1)));
+ }
+
+ // is this a valid address? (used to filter data fetches)
+ // note that we just assume stack size <= 16MB
+ // this may be alpha-specific
+ bool validDataAddr(Addr addr)
+ {
+ return ((data_base <= addr && addr < brk_point) ||
+ ((stack_base - 16*1024*1024) <= addr && addr < stack_base) ||
+ (text_base <= addr && addr < (text_base + text_size)));
+ }
+
+ virtual void syscall(ExecContext *xc) = 0;
+
+ virtual FunctionalMemory *getMemory() { return memory; }
+};
+
+//
+// "Live" process with system calls redirected to host system
+//
+class MainMemory;
+class LiveProcess : public Process
+{
+ public:
+ LiveProcess(const std::string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual void syscall(ExecContext *xc);
+};
+
+#endif // !FULL_SYSTEM
+
+#endif // __PROG_HH__
diff --git a/sim/sat_counter.cc b/sim/sat_counter.cc
new file mode 100644
index 000000000..bd1b6de0b
--- /dev/null
+++ b/sim/sat_counter.cc
@@ -0,0 +1,270 @@
+/*
+ * 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 "stats.hh"
+#include "sat_counter.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+
+using namespace std;
+
+
+SaturatingCounterPred::SaturatingCounterPred(string p_name,
+ string z_name,
+ string o_name,
+ unsigned _index_bits,
+ unsigned _counter_bits,
+ unsigned _zero_change,
+ unsigned _one_change,
+ unsigned _thresh,
+ unsigned _init_value)
+{
+ pred_name = p_name;
+ zero_name = z_name;
+ one_name = o_name;
+
+ index_bits = _index_bits;
+ counter_bits = _counter_bits;
+ zero_change = _zero_change;
+ one_change = _one_change;
+ thresh = _thresh;
+ init_value = _init_value;
+
+ max_index = (1 << index_bits) - 1;
+ max_value = (1 << counter_bits) - 1;
+
+ table = new unsigned[max_index + 1];
+
+ // Initialize with the right parameters & clear the counter
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+}
+
+void SaturatingCounterPred::regStats()
+{
+ using namespace Statistics;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ predicted_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ predicted_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds";
+ correct_pred_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds";
+ correct_pred_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":" << zero_name << ":updates";
+ description << "number of actual " << zero_name << "s";
+ record_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":updates";
+ description << "number of actual " << one_name << "s";
+ record_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+}
+
+void SaturatingCounterPred::regFormulas()
+{
+ using namespace Statistics;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":predictions";
+ preds_total
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ preds_total = predicted_zero + predicted_one;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << pred_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name;
+ pred_frac_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_zero = 100 * predicted_zero / preds_total;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name;
+ pred_frac_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_one = 100 * predicted_one / preds_total;
+ description.str("");
+ name.str("");
+
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":correct_preds";
+ correct_total
+ .name(name.str())
+ .desc("total correct predictions made")
+ ;
+ correct_total = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":updates";
+ updates_total
+ .name(name.str())
+ .desc("total number of updates")
+ ;
+ updates_total = record_zero + record_one;
+ name.str("");
+
+ //
+ // Prediction accuracy rates
+ //
+ name << pred_name << ":pred_rate";
+ pred_rate
+ .name(name.str())
+ .desc("correct fraction of all preds")
+ ;
+ pred_rate = correct_total / updates_total;
+ name.str("");
+
+ name << pred_name << ":" << zero_name << ":pred_rate";
+ description << "fraction of " << zero_name << " preds that were correct";
+ frac_correct_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_zero = 100 * correct_pred_zero /
+ (correct_pred_zero + record_one - correct_pred_one);
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_rate";
+ description << "fraction of " << one_name << " preds that were correct";
+ frac_correct_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_one = 100 * correct_pred_one /
+ (correct_pred_one + record_zero - correct_pred_zero);
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << pred_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ coverage_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_zero = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ coverage_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_one = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/sim/sat_counter.hh b/sim/sat_counter.hh
new file mode 100644
index 000000000..18eab3574
--- /dev/null
+++ b/sim/sat_counter.hh
@@ -0,0 +1,192 @@
+/*
+ * 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 __SAT_COUNTER_HH__
+#define __SAT_COUNTER_HH__
+
+#include <string>
+
+#include "predictor.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+struct stat_sdb_t;
+
+//
+//
+// A simple saturating counter predictor
+//
+//
+class SaturatingCounterPred : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string zero_name;
+ std::string one_name;
+
+ unsigned index_bits;
+ unsigned counter_bits;
+ unsigned zero_change;
+ unsigned one_change;
+ unsigned thresh;
+ unsigned init_value;
+
+ unsigned max_value; // maximum counter value
+
+ unsigned long max_index; // also the index mask value
+ unsigned *table;
+
+ // Statistics
+ Statistics::Scalar<> predicted_one; // Total predictions of one, preds_one
+ Statistics::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
+ Statistics::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
+ Statistics::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+
+ Statistics::Scalar<> record_zero; //updates_zero
+ Statistics::Scalar<> record_one; //updates_one
+
+ Statistics::Formula preds_total;
+ Statistics::Formula pred_frac_zero;
+ Statistics::Formula pred_frac_one;
+ Statistics::Formula correct_total;
+ Statistics::Formula updates_total;
+ Statistics::Formula pred_rate;
+ Statistics::Formula frac_correct_zero;
+ Statistics::Formula frac_correct_one;
+ Statistics::Formula coverage_zero;
+ Statistics::Formula coverage_one;
+
+ private:
+ bool pred_one(unsigned &counter) { return counter > thresh; }
+ bool pred_zero(unsigned &counter) { return counter <= thresh; }
+
+ void update_one(unsigned &counter) {
+
+ if (one_change)
+ counter += one_change;
+ else
+ counter = 0;
+
+ // check for wrap
+ if (counter > max_value)
+ counter = max_value;
+ }
+
+ void update_zero(unsigned &counter) {
+ if (zero_change) {
+ // check for wrap
+ if (counter < zero_change)
+ counter = 0;
+ else
+ counter -= zero_change;
+ } else
+ counter = 0;
+ }
+
+
+ public:
+
+ SaturatingCounterPred(std::string p_name,
+ std::string z_name, std::string o_name,
+ unsigned _index_bits, unsigned _counter_bits = 2,
+ unsigned _zero_change = 1, unsigned _one_change = 1,
+ unsigned _thresh = 1, unsigned _init_value = 0);
+
+ void clear() {
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+ }
+
+ // Record the ACTUAL result... and indicate whether the prediction
+ // corresponding to this event was correct
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+ record(_index, _val, _predicted);
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+ unsigned long index = _index & max_index;
+
+ if (_val) {
+ update_one(table[index]);
+ ++record_one;
+
+ if (_predicted)
+ ++correct_pred_one;
+ } else {
+ update_zero(table[index]);
+ ++record_zero;
+
+ if (!_predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ return table[index];
+ }
+
+
+ unsigned predict(unsigned long _index, unsigned &pdata) {
+ return predict(_index);
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index])) {
+ ++predicted_one;
+ return 1;
+ }
+
+ ++predicted_zero;
+ return 0;
+ }
+
+ // No internal state is changed here
+ unsigned peek(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index]))
+ return 1;
+
+ return 0;
+ }
+
+
+ //=======================================================
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // __SAT_COUNTER_HH__
diff --git a/sim/serialize.cc b/sim/serialize.cc
new file mode 100644
index 000000000..a2e3d7250
--- /dev/null
+++ b/sim/serialize.cc
@@ -0,0 +1,353 @@
+/*
+ * 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/time.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "param.hh"
+#include "serialize.hh"
+#include "inifile.hh"
+#include "sim_events.hh"
+#include "sim_object.hh"
+#include "trace.hh"
+
+using namespace std;
+
+Serializer *Serializeable::serializer = NULL;
+
+Serializeable::Serializeable(const string &n)
+ : proxy(this), objName(n), serialized(false)
+{ }
+
+Serializeable::~Serializeable()
+{ }
+
+void
+Serializeable::mark()
+{
+ if (!serialized)
+ serializer->add_object(this);
+
+ serialized = true;
+}
+
+ostream &
+Serializeable::out() const
+{
+ return serializer->out();
+}
+
+void
+Serializeable::nameOut()
+{
+ out() << "\n[" << name() << "]\n";
+}
+
+void
+Serializeable::nameOut(const string &_name)
+{
+ out() << "\n[" << _name << "]\n";
+}
+
+template<> void
+Serializeable::paramOut(const string &name, const uint64_t& param)
+{
+ out() << name << "=0x" << hex << param << dec << "\n";
+}
+
+void
+Serializeable::childOut(const string &name, Serializeable *child)
+{
+ child->mark();
+ if (child->name() == "")
+ panic("child is unnamed");
+
+ out() << name << "=" << child->name() << "\n";
+}
+
+void
+Serializeable::setName(const string &name)
+{
+ if (objName != "")
+ panic("Cannot change object name");
+
+ objName = name;
+}
+
+Serializer::Serializer()
+{ }
+
+Serializer::~Serializer()
+{ }
+
+ostream &
+Serializer::out() const
+{
+ if (!output)
+ panic("must set output before serializing");
+
+ return *output;
+}
+
+void
+Serializer::add_object(Serializeable *obj)
+{
+ objects.push_back(obj);
+}
+
+void
+Serializer::add_objects()
+{
+ mainEventQueue.mark();
+
+ SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
+ SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
+
+ while (i != end) {
+ (*i)->mark();
+ ++i;
+ }
+}
+
+void
+Serializer::serialize(const string &f)
+{
+ if (Serializeable::serializer != NULL)
+ panic("in process of serializing!");
+
+ Serializeable::serializer = this;
+
+ file = f;
+ string cpt_file = file + ".cpt";
+ output = new ofstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ *output << "// checkpoint generated: " << ctime(&t);
+
+ serlist_t list;
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->nameChildren();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->serialize();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ Serializeable::serializer = NULL;
+
+ delete output;
+ output = NULL;
+ file = "";
+}
+
+class SerializeEvent : public Event
+{
+ protected:
+ string file;
+
+ public:
+ SerializeEvent(EventQueue *q, Tick when, const string &file);
+ ~SerializeEvent();
+
+ virtual void process();
+ virtual void serialize();
+};
+
+SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
+ : Event(q), file(f)
+{
+ setFlags(AutoDelete);
+ schedule(when);
+}
+
+SerializeEvent::~SerializeEvent()
+{
+}
+
+void
+SerializeEvent::process()
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+void
+SerializeEvent::serialize()
+{
+ panic("Cannot serialize the SerializeEvent");
+}
+
+class SerializeParamContext : public ParamContext
+{
+ private:
+ SerializeEvent *event;
+
+ public:
+ SerializeParamContext(const string &section);
+ ~SerializeParamContext();
+ void checkParams();
+};
+
+SerializeParamContext serialParams("serialize");
+
+Param<Counter> serialize_cycle(&serialParams,
+ "cycle",
+ "cycle to serialize",
+ 0);
+
+Param<string> serialize_file(&serialParams,
+ "file",
+ "file to write to", "");
+
+SerializeParamContext::SerializeParamContext(const string &section)
+ : ParamContext(section), event(NULL)
+{ }
+
+SerializeParamContext::~SerializeParamContext()
+{
+}
+
+void
+SerializeParamContext::checkParams()
+{
+ if (!((string)serialize_file).empty() && serialize_cycle > 0)
+ event = new SerializeEvent(&mainEventQueue, serialize_cycle,
+ serialize_file);
+}
+
+void
+debug_serialize(const char *file)
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializeableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializeableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializeableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
+
+// SerializeableClass constructor: add mapping to classMap
+SerializeableClass::SerializeableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializeableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializeable *
+SerializeableClass::createObject(IniFile &configDB,
+ const string &configClassName)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // builder instance
+ SerializeableBuilder *objectBuilder = (*createFunc)();
+
+ assert(objectBuilder != NULL);
+
+ // now create the actual simulation object
+ Serializeable *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // done with the SerializeableBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
diff --git a/sim/serialize.hh b/sim/serialize.hh
new file mode 100644
index 000000000..c5fb86140
--- /dev/null
+++ b/sim/serialize.hh
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * Serialization Interface Declarations
+ */
+
+#ifndef __SERIALIZE_HH__
+#define __SERIALIZE_HH__
+
+
+#include <list>
+#include <iostream>
+
+#include "host.hh"
+#include "configfile.hh"
+
+class IniFile;
+
+/*
+ * Basic support for object serialization.
+ */
+class Serializeable
+{
+ public:
+ // To allow other classes to do some of the serialization work.
+ class Proxy {
+ private:
+ Serializeable *obj;
+
+ // Make it so only Serializables can construct one of these.
+ Proxy(Serializeable *o) : obj(o) {};
+
+ friend class Serializeable;
+
+ public:
+ template <class T>
+ void paramOut(const std::string &name, const T& param) const {
+ obj->paramOut(name, param);
+ };
+ };
+
+ friend class Serializer;
+ friend class Proxy;
+
+ private:
+ Proxy proxy;
+
+ protected:
+ const Proxy &getProxy() { return(proxy); };
+
+ // object name: should be unique
+ std::string objName;
+
+ bool serialized;
+ static Serializer *serializer;
+
+ void mark();
+ void nameOut();
+ void nameOut(const std::string &_name);
+ void childOut(const std::string &name, Serializeable *child);
+ template <class T>
+ void paramOut(const std::string &name, const T& param);
+
+ std::ostream &out() const;
+
+ public:
+ Serializeable(const std::string &n);
+ virtual ~Serializeable();
+
+ void setName(const std::string &name);
+
+ // return name
+ const std::string &name() const { return objName; }
+
+ virtual void nameChildren() {}
+ virtual void serialize() {}
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node = NULL)
+ {
+ std::cout << name() << " is being unserialized" << std::endl;
+ }
+};
+
+class Serializer
+{
+ friend class Serializeable;
+
+ protected:
+ typedef std::list<Serializeable *> serlist_t;
+ serlist_t objects;
+ std::string file;
+ std::ostream *output;
+ std::ostream &out() const;
+
+ public:
+ Serializer();
+ virtual ~Serializer();
+
+ private:
+ void add_object(Serializeable *obj);
+ void add_objects();
+
+ public:
+ void serialize(const std::string &file);
+ const std::string &filename() const { return file; }
+};
+
+template <class T>
+inline void
+Serializeable::paramOut(const std::string &name, const T& param)
+{
+ out() << name << "=" << param << "\n";
+}
+
+template <> void
+Serializeable::paramOut(const std::string &name, const uint64_t& param);
+
+
+//
+// A SerializeableBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a Serializeable. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// Serializeable references. SerializeableBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// Serializeable (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SerializeableClass::createObject().
+//
+class SerializeableBuilder
+{
+ public:
+
+ SerializeableBuilder() {}
+
+ virtual ~SerializeableBuilder() {}
+
+ // Create the actual Serializeable corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of Serializeable.
+ virtual Serializeable *create() = 0;
+};
+
+//
+// An instance of SerializeableClass corresponds to a class derived from
+// Serializeable. The SerializeableClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SerializeableClass
+{
+ public:
+
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SerializeableBuilder is returned.
+ typedef SerializeableBuilder *(*CreateFunc)();
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SerializeableClass baseCacheSerializeableClass("BaseCacheSerializeable",
+ // newBaseCacheSerializeableBuilder);
+ //
+ SerializeableClass(const std::string &className, CreateFunc createFunc);
+
+ // create Serializeable given name of class and pointer to
+ // configuration hierarchy node
+ static Serializeable *createObject(IniFile &configDB,
+ const std::string &configClassName);
+
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SerializeableBuilder and SerializeableClass objects
+//
+
+#define CREATE_SERIALIZEABLE(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SerializeableBuilder \
+{ \
+ public: \
+ \
+ OBJ_CLASS##Builder() {} \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+}; \
+ \
+ \
+SerializeableBuilder * \
+new##OBJ_CLASS##Builder() \
+{ \
+ return new OBJ_CLASS##Builder(); \
+} \
+ \
+SerializeableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder);
+
+
+
+#endif // __SERIALIZE_HH__
diff --git a/sim/sim_events.cc b/sim/sim_events.cc
new file mode 100644
index 000000000..ffabc3006
--- /dev/null
+++ b/sim/sim_events.cc
@@ -0,0 +1,271 @@
+/*
+ * 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 <string>
+
+#include "cpu.hh"
+#include "eventq.hh"
+#include "sim_events.hh"
+#include "sim_exit.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+//
+// handle termination event
+//
+void
+SimExitEvent::process()
+{
+ // This event does not autodelete because exitNow may be called,
+ // and the function will never be allowed to finish.
+ if (theQueue() == &mainEventQueue) {
+ string _cause = cause;
+ int _code = code;
+ delete this;
+ exitNow(_cause, _code);
+ } else {
+ new SimExitEvent(cause, code);
+ delete this;
+ }
+}
+
+
+const char *
+SimExitEvent::description()
+{
+ return "simulation termination";
+}
+
+
+//
+// constructor: automatically schedules at specified time
+//
+CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter)
+ : Event(q),
+ cause(_cause),
+ downCounter(_downCounter)
+{
+ // catch stupid mistakes
+ assert(downCounter > 0);
+
+ schedule(_when, 1000);
+}
+
+
+//
+// handle termination event
+//
+void
+CountedExitEvent::process()
+{
+ if (--downCounter == 0) {
+ new SimExitEvent(cause, 1);
+ }
+}
+
+
+const char *
+CountedExitEvent::description()
+{
+ return "counted exit";
+}
+
+
+void
+DumpStatsEvent::process()
+{
+ dumpStats();
+}
+
+const char *
+DumpStatsEvent::description()
+{
+ return "stats dump";
+}
+
+
+#ifdef CHECK_SWAP_CYCLES
+new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES);
+#endif
+
+void
+CheckSwapEvent::process()
+{
+ /* Check the amount of free swap space */
+ long swap;
+
+ /* returns free swap in KBytes */
+ swap = proc_info("/proc/meminfo", "SwapFree:");
+
+ if (swap < 1000)
+ ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap);
+
+ if (swap < 100) {
+ cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
+ new SimExitEvent("Lack of swap space");
+ }
+
+ schedule(curTick + interval);
+}
+
+const char *
+CheckSwapEvent::description()
+{
+ return "check swap";
+}
+
+
+class DumpStatsContext : public ParamContext
+{
+ public:
+ DumpStatsContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DumpStatsContext dumpStatsParams("stats");
+
+VectorParam<Tick> dump_cycle(&dumpStatsParams, "dump_cycles",
+ "cycles on which to dump stats");
+
+void
+DumpStatsContext::checkParams()
+{
+ if (dump_cycle.isValid()) {
+ vector<Tick> &cycles = dump_cycle;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DumpStatsEvent(*i);
+ }
+}
+
+///////////////////////////////////////////////////
+//
+// Simulation termination parameters
+//
+///////////////////////////////////////////////////
+
+class TermParamContext : public ParamContext
+{
+ public:
+ TermParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+TermParamContext simTerminationParams("max");
+
+Param<Tick> max_cycle(&simTerminationParams, "cycle",
+ "maximum number of cycles to execute");
+
+void
+TermParamContext::checkParams()
+{
+ // if a max cycle count was specified, put a termination event on
+ // the event queue at that point
+ if (max_cycle.isValid())
+ new SimExitEvent(max_cycle, "reached maximum cycle count");
+}
+
+//
+// Progress event: print out cycle every so often so we know we're
+// making forward progress.
+//
+class ProgressEvent : public Event
+{
+ protected:
+ Tick interval;
+
+ public:
+ ProgressEvent(EventQueue *q, Tick interval);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+ProgressEvent::ProgressEvent(EventQueue *q, Tick _interval)
+ : Event(q), interval(_interval)
+{
+ schedule(interval);
+}
+
+//
+// handle progress event: print message and reschedule
+//
+void
+ProgressEvent::process()
+{
+ DPRINTFN("ProgressEvent\n");
+ // reschedule for next interval
+ schedule(curTick + interval);
+}
+
+
+const char *
+ProgressEvent::description()
+{
+ return "progress message";
+}
+
+/////////
+//
+// Periodic progress message support: print out a message every n
+// cycles so we know we're making forward progress.
+//
+/////////
+
+// Parameter space for execution address tracing options. Derive
+// from ParamContext so we can override checkParams() function.
+class ProgressParamContext : public ParamContext
+{
+ public:
+ ProgressParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+ProgressParamContext progessMessageParams("progress");
+
+Param<Tick> progress_interval(&progessMessageParams, "cycle",
+ "cycle interval for progress messages");
+
+/* check execute options */
+void
+ProgressParamContext::checkParams()
+{
+ if (progress_interval.isValid())
+ new ProgressEvent(&mainEventQueue, progress_interval);
+}
diff --git a/sim/sim_events.hh b/sim/sim_events.hh
new file mode 100644
index 000000000..e9a5f3251
--- /dev/null
+++ b/sim/sim_events.hh
@@ -0,0 +1,131 @@
+/*
+ * 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 __SIM_EVENTS_HH__
+#define __SIM_EVENTS_HH__
+
+#include "eventq.hh"
+
+//
+// Event to terminate simulation at a particular cycle/instruction
+//
+class SimExitEvent : public Event
+{
+ private:
+ // string explaining why we're terminating
+ std::string cause;
+ int code;
+
+ public:
+ SimExitEvent(const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue), cause(_cause),
+ code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue), cause(_cause),
+ code(c)
+ { schedule(_when, 1000); }
+
+ SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
+ int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(_when, 1000); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Event class to terminate simulation after 'n' related events have
+// occurred using a shared counter: used to terminate when *all*
+// threads have reached a particular instruction count
+//
+class CountedExitEvent : public Event
+{
+ private:
+ std::string cause; // string explaining why we're terminating
+ int &downCounter; // decrement & terminate if zero
+
+ public:
+ CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter);
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Event to cause a statistics dump
+//
+class DumpStatsEvent : public Event
+{
+ public:
+ DumpStatsEvent()
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(EventQueue *q)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(Tick when)
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ DumpStatsEvent(EventQueue *q, Tick when)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ void process();
+
+ virtual const char *description();
+};
+
+class CheckSwapEvent : public Event
+{
+ private:
+ int interval;
+
+ public:
+ CheckSwapEvent(EventQueue *q, int ival)
+ : Event(q), interval(ival)
+ { schedule(interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+#endif // __SIM_EVENTS_HH__
diff --git a/sim/sim_exit.hh b/sim/sim_exit.hh
new file mode 100644
index 000000000..847d9eb10
--- /dev/null
+++ b/sim/sim_exit.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 __SIM_EXIT_HH__
+#define __SIM_EXIT_HH__
+
+#include <string>
+
+class Callback;
+
+void registerExitCallback(Callback *);
+
+void exitNow(const std::string &cause, int exit_code);
+void exitNow(const char *cause, int exit_code);
+
+#endif // __SIM_EXIT_HH__
diff --git a/sim/sim_object.cc b/sim/sim_object.cc
new file mode 100644
index 000000000..e5506ee8f
--- /dev/null
+++ b/sim/sim_object.cc
@@ -0,0 +1,280 @@
+/*
+ * 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 <assert.h>
+
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "trace.hh"
+#include "sim_stats.hh"
+#include "stats.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObject member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// static list of all SimObjects, used for initialization etc.
+//
+SimObject::SimObjectList SimObject::simObjectList;
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(const string &_name)
+ : Serializeable(_name)
+{
+ simObjectList.push_back(this);
+}
+
+//
+// no default statistics, so nothing to do in base implementation
+//
+void
+SimObject::reg_stats(struct stat_sdb_t *sdb)
+{
+}
+
+void
+SimObject::regStats()
+{
+}
+
+void
+SimObject::regFormulas()
+{
+}
+
+//
+// no default extra output
+//
+void
+SimObject::printExtraOutput(ostream &os)
+{
+}
+
+//
+// static function: call reg_stats() on all SimObjects.
+//
+void
+SimObject::regAllStats()
+{
+ SimObjectList::iterator i;
+ SimObjectList::iterator end = simObjectList.end();
+
+ /**
+ * @todo change cprintfs to DPRINTFs
+ */
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering stats for %s\n", (*i)->name());
+#endif
+ (*i)->reg_stats(sim_sdb);
+ (*i)->regStats();
+ }
+
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering formulas for %s\n", (*i)->name());
+#endif
+ (*i)->regFormulas();
+ }
+}
+
+//
+// static function: call printExtraOutput() on all SimObjects.
+//
+void
+SimObject::printAllExtraOutput(ostream &os)
+{
+ SimObjectList::iterator i;
+
+ for (i = simObjectList.begin(); i != simObjectList.end(); ++i) {
+ (*i)->printExtraOutput(os);
+ }
+}
+
+///////////////////////////////////////////
+//
+// SimObjectBuilder member definitions
+//
+///////////////////////////////////////////
+
+// override ParamContext::parseParams() to check params based on
+// instance name first. If not found, then check based on iniSection
+// (as in default ParamContext implementation).
+void
+SimObjectBuilder::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = paramList->begin(); i != paramList->end(); ++i) {
+ string string_value;
+
+ if (iniFile.findDefault(instanceName, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ else if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ }
+}
+
+
+void
+SimObjectBuilder::printErrorProlog(ostream &os)
+{
+ os << "Error creating object '" << getInstanceName()
+ << "' of type '" << simObjClassName
+ << "', section '" << iniSection << "':" << endl;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SimObjectBuilder creation functions. Need to
+// make this a pointer so we can force initialization on the first
+// reference; otherwise, some SimObjectClass constructors may be invoked
+// before the classMap constructor.
+map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL;
+
+// SimObjectClass constructor: add mapping to classMap
+SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SimObjectClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+SimObject *
+SimObjectClass::createObject(IniFile &configDB,
+ const string &configClassName,
+ const string &objName,
+ ConfigNode *configNode)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // call createFunc with config hierarchy node to get object
+ // builder instance (context with parameters for object creation)
+ SimObjectBuilder *objectBuilder = (*createFunc)(configClassName,
+ objName, configNode,
+ simObjClassName);
+
+ assert(objectBuilder != NULL);
+
+ // parse all parameters in context to generate parameter values
+ objectBuilder->parseParams(configDB);
+
+ // now create the actual simulation object
+ SimObject *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // echo object parameters to stats file (for documenting the
+ // config used to generate the associated stats)
+ *statStream << "[" << object->name() << "]" << endl;
+ *statStream << "type=" << simObjClassName << endl;
+ objectBuilder->showParams(*statStream);
+ *statStream << endl;
+
+ // done with the SimObjectBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
+
+//
+// static method:
+//
+void
+SimObjectClass::describeAllClasses(ostream &os)
+{
+ map<string,CreateFunc>::iterator iter;
+
+ for (iter = classMap->begin(); iter != classMap->end(); ++iter) {
+ const string &className = iter->first;
+ CreateFunc createFunc = iter->second;
+
+ os << "[" << className << "]\n";
+
+ // create dummy object builder just to instantiate parameters
+ SimObjectBuilder *objectBuilder = (*createFunc)("", "", NULL, "");
+
+ // now get the object builder to describe ite params
+ objectBuilder->describeParams(os);
+
+ os << endl;
+
+ // done with the object builder now
+ delete objectBuilder;
+ }
+}
diff --git a/sim/sim_object.hh b/sim/sim_object.hh
new file mode 100644
index 000000000..051c7b304
--- /dev/null
+++ b/sim/sim_object.hh
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __SIM_OBJECT_HH__
+#define __SIM_OBJECT_HH__
+
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+#include "param.hh"
+#include "serialize.hh"
+
+/*
+ * Abstract superclass for simulation objects. Represents things that
+ * correspond to physical components and can be specified via the
+ * config file (CPUs, caches, etc.).
+ */
+class SimObject : public Serializeable
+{
+ private:
+ friend class Serializer;
+
+ typedef std::vector<SimObject *> SimObjectList;
+
+ // list of all instantiated simulation objects
+ static SimObjectList simObjectList;
+
+ public:
+ SimObject(const std::string &_name);
+
+ virtual ~SimObject() {}
+
+ // register statistics for this object
+ virtual void reg_stats(struct stat_sdb_t *sdb);
+ virtual void regStats();
+ virtual void regFormulas();
+
+ // print extra results for this object not covered by registered
+ // statistics (called at end of simulation)
+ virtual void printExtraOutput(std::ostream&);
+
+ // static: call reg_stats on all SimObjects
+ static void regAllStats();
+
+ // static: call printExtraOutput on all SimObjects
+ static void printAllExtraOutput(std::ostream&);
+};
+
+
+//
+// A SimObjectBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a SimObject. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// SimObject references. SimObjectBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// SimObject (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SimObjectClass::createObject().
+//
+class SimObjectBuilder : public ParamContext
+{
+ private:
+ // name of the instance we are creating
+ std::string instanceName;
+
+ // The corresponding node in the configuration hierarchy.
+ // (optional: may be null if the created object is not in the
+ // hierarchy)
+ ConfigNode *configNode;
+
+ // The external SimObject class name (for error messages)
+ std::string simObjClassName;
+
+ public:
+ SimObjectBuilder(const std::string &_configClass,
+ const std::string &_instanceName,
+ ConfigNode *_configNode,
+ const std::string &_simObjClassName)
+ : ParamContext(_configClass, true),
+ instanceName(_instanceName),
+ configNode(_configNode),
+ simObjClassName(_simObjClassName)
+ {
+ }
+
+ virtual ~SimObjectBuilder() {}
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // parameter error prolog (override of ParamContext)
+ virtual void printErrorProlog(std::ostream &);
+
+ // generate the name for this SimObject instance (derived from the
+ // configuration hierarchy node label and position)
+ virtual const std::string &getInstanceName() { return instanceName; }
+
+ // return the configuration hierarchy node for this context.
+ virtual ConfigNode *getConfigNode() { return configNode; }
+
+ // Create the actual SimObject corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of SimObject.
+ virtual SimObject *create() = 0;
+};
+
+
+//
+// Handy macros for initializing parameter members of classes derived
+// from SimObjectBuilder. Assumes that the name of the parameter
+// member object is the same as the textual parameter name seen by the
+// user. (Note that '#p' is expanded by the preprocessor to '"p"'.)
+//
+#define INIT_PARAM(p, desc) p(this, #p, desc)
+#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt)
+
+//
+// Initialize an enumeration variable... assumes that 'map' is the
+// name of an array of mappings (char * for SimpleEnumParam, or
+// EnumParamMap for MappedEnumParam).
+//
+#define INIT_ENUM_PARAM(p, desc, map) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]))
+#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt)
+
+//
+// An instance of SimObjectClass corresponds to a class derived from
+// SimObject. The SimObjectClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SimObjectClass
+{
+ public:
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SimObjectBuilder is returned.
+ typedef SimObjectBuilder *(*CreateFunc)(const std::string &configClassName,
+ const std::string &objName,
+ ConfigNode *configNode,
+ const std::string &simObjClassName);
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder);
+ //
+ SimObjectClass(const std::string &className, CreateFunc createFunc);
+
+ // create SimObject given name of class and pointer to
+ // configuration hierarchy node
+ static SimObject *createObject(IniFile &configDB,
+ const std::string &configClassName,
+ const std::string &objName,
+ ConfigNode *configNode);
+
+ // print descriptions of all parameters registered with all
+ // SimObject classes
+ static void describeAllClasses(std::ostream &os);
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SimObjectBuilder and SimObjectClass objects
+//
+
+#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SimObjectBuilder \
+{ \
+ public:
+
+#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+ \
+ OBJ_CLASS##Builder(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName); \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+ : SimObjectBuilder(configClass, instanceName, \
+ configNode, simObjClassName),
+
+
+#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+{ \
+}
+
+#define CREATE_SIM_OBJECT(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
+SimObjectBuilder * \
+new##OBJ_CLASS##Builder(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+{ \
+ return new OBJ_CLASS##Builder(configClass, instanceName, \
+ configNode, simObjClassName); \
+} \
+ \
+SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS)
+
+
+#endif // __SIM_OBJECT_HH__
diff --git a/sim/sim_time.cc b/sim/sim_time.cc
new file mode 100644
index 000000000..c235be5db
--- /dev/null
+++ b/sim/sim_time.cc
@@ -0,0 +1,152 @@
+/*
+ * 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/time.h>
+#include <time.h>
+#include <iostream>
+
+#include "sim_time.hh"
+
+using namespace std;
+
+namespace Time
+{
+ struct _timeval
+ {
+ timeval tv;
+ };
+
+ double
+ convert(const timeval &tv)
+ {
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+ }
+
+ Start::Start()
+ {
+ start = new _timeval;
+ ::gettimeofday(&start->tv, NULL);
+ }
+
+ Start::~Start()
+ {
+ delete start;
+ }
+
+ const timeval &
+ Start::get() const
+ {
+ return start->tv;
+ }
+
+ double
+ Start::operator()() const
+ {
+ return convert(get());
+ }
+
+ Now::Now()
+ : now(0)
+ {
+ }
+
+ Now::~Now()
+ {
+ if (now)
+ delete now;
+ }
+
+ const timeval &
+ Now::get() const
+ {
+ if (!now)
+ now = new _timeval;
+
+ ::gettimeofday(&now->tv, NULL);
+ return now->tv;
+ }
+
+ double
+ Now::operator()() const
+ {
+ return convert(get());
+ }
+
+
+ Elapsed::Elapsed()
+ : elapsed(0)
+ {}
+
+ Elapsed::~Elapsed()
+ {
+ if (elapsed)
+ delete elapsed;
+ }
+
+ const timeval &
+ Elapsed::get() const
+ {
+ if (!elapsed)
+ elapsed = new _timeval;
+
+ timersub(&now.get(), &start.get(), &elapsed->tv);
+ return elapsed->tv;
+ }
+
+ double
+ Elapsed::operator()() const
+ {
+ return convert(get());
+ }
+
+ Start start;
+ Now now;
+ Elapsed elapsed;
+
+ ostream &
+ operator<<(ostream &out, const Start &start)
+ {
+ out << ::ctime(&start.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Now &now)
+ {
+ out << ::ctime(&now.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Elapsed &elapsed)
+ {
+ out << ::ctime(&elapsed.get().tv_sec);
+ return out;
+ }
+}
diff --git a/sim/sim_time.hh b/sim/sim_time.hh
new file mode 100644
index 000000000..dbba42aa7
--- /dev/null
+++ b/sim/sim_time.hh
@@ -0,0 +1,84 @@
+/*
+ * 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 __SIM_TIME_HH__
+#define __SIM_TIME_HH__
+
+#include <iosfwd>
+
+namespace Time {
+ struct _timeval;
+ class Start
+ {
+ private:
+ mutable _timeval *start;
+
+ public:
+ Start();
+ ~Start();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Now
+ {
+ private:
+ mutable _timeval *now;
+
+ public:
+ Now();
+ ~Now();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Elapsed
+ {
+ private:
+ mutable _timeval *elapsed;
+
+ public:
+ Elapsed();
+ ~Elapsed();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ extern Start start;
+ extern Now now;
+ extern Elapsed elapsed;
+
+ std::ostream &operator<<(std::ostream &out, const Start &start);
+ std::ostream &operator<<(std::ostream &out, const Now &now);
+ std::ostream &operator<<(std::ostream &out, const Elapsed &elapsed);
+}
+
+#endif // __SIM_TIME_HH__
diff --git a/sim/simple_cpu.cc b/sim/simple_cpu.cc
new file mode 100644
index 000000000..96743d0fa
--- /dev/null
+++ b/sim/simple_cpu.cc
@@ -0,0 +1,747 @@
+/*
+ * 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 <iomanip>
+#include <list>
+#include <sstream>
+#include <string>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "stats.hh"
+#include "smt.hh"
+
+#include "annotation.hh"
+#include "exec_context.hh"
+#include "base_cpu.hh"
+#include "debug.hh"
+#include "simple_cpu.hh"
+#include "inifile.hh"
+#include "mem_interface.hh"
+#include "base_mem.hh"
+#include "static_inst.hh"
+
+#ifdef FULL_SYSTEM
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "alpha_memory.hh"
+#include "system.hh"
+#else // !FULL_SYSTEM
+#include "functional_memory.hh"
+#include "prog.hh"
+#include "eio.hh"
+#endif // FULL_SYSTEM
+
+#include "exetrace.hh"
+#include "trace.hh"
+#include "sim_events.hh"
+#include "pollevent.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+
+#include "range.hh"
+#include "symtab.hh"
+
+#ifdef FULL_SYSTEM
+#include "vtophys.hh"
+#include "pciareg.h"
+#include "remote_gdb.hh"
+#include "alpha_access.h"
+#endif
+
+
+using namespace std;
+
+SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
+ : Event(&mainEventQueue),
+ cpu(_cpu)
+{
+}
+
+void SimpleCPU::CacheCompletionEvent::process()
+{
+ cpu->processCacheCompletion();
+}
+
+const char *
+SimpleCPU::CacheCompletionEvent::description()
+{
+ return "cache completion event";
+}
+
+#ifdef FULL_SYSTEM
+SimpleCPU::SimpleCPU(const string &_name,
+ System *_system,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb,
+ FunctionalMemory *mem,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface,
+ int cpu_id, Tick freq)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads,
+ _system, cpu_id, freq),
+#else
+SimpleCPU::SimpleCPU(const string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads),
+#endif
+ tickEvent(this), xc(NULL), cacheCompletionEvent(this)
+{
+#ifdef FULL_SYSTEM
+ xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id);
+
+ _status = Running;
+ if (cpu_id != 0) {
+
+ xc->setStatus(ExecContext::Unallocated);
+
+ //Open a GDB debug session on port (7000 + the cpu_id)
+ (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen();
+
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc =
+ ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Idle;
+ }
+ else {
+ system->initBootContext(xc);
+
+ // Reset the system
+ //
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Running;
+ tickEvent.schedule(0);
+ }
+
+#else
+ xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
+ fault = No_Fault;
+ if (xc->status() == ExecContext::Active) {
+ _status = Running;
+ tickEvent.schedule(0);
+ } else
+ _status = Idle;
+#endif // !FULL_SYSTEM
+
+ icacheInterface = icache_interface;
+ dcacheInterface = dcache_interface;
+
+ memReq = new MemReq();
+ memReq->xc = xc;
+ memReq->asid = 0;
+
+ numInst = 0;
+ last_idle = 0;
+ lastIcacheStall = 0;
+ lastDcacheStall = 0;
+
+ contexts.push_back(xc);
+}
+
+SimpleCPU::~SimpleCPU()
+{
+}
+
+void
+SimpleCPU::regStats()
+{
+ BaseCPU::regStats();
+
+ numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ idleCycles
+ .name(name() + ".idle_cycles")
+ .desc("Number of idle cycles")
+ ;
+
+ idleFraction
+ .name(name() + ".idle_fraction")
+ .desc("Percentage of idle cycles")
+ ;
+
+ icacheStallCycles
+ .name(name() + ".icache_stall_cycles")
+ .desc("ICache total stall cycles")
+ .prereq(icacheStallCycles)
+ ;
+
+ dcacheStallCycles
+ .name(name() + ".dcache_stall_cycles")
+ .desc("DCache total stall cycles")
+ .prereq(dcacheStallCycles)
+ ;
+
+ idleFraction = idleCycles / simTicks;
+
+ numInsts = Statistics::scalar(numInst);
+ simInsts += numInsts;
+}
+
+void
+SimpleCPU::serialize()
+{
+ nameOut();
+
+#ifdef FULL_SYSTEM
+#if 0
+ // do we need this anymore?? egh
+ childOut("itb", xc->itb);
+ childOut("dtb", xc->dtb);
+ childOut("physmem", physmem);
+#endif
+#endif
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ paramOut(buf.str(), xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ paramOut(buf.str(), xc->regs.floatRegFile.d[i]);
+ }
+ // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs);
+}
+
+void
+SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node)
+{
+ string data;
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data,xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ db.findDefault(category, buf.str(), data);
+ xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL);
+ }
+
+ // Read in Special registers
+
+ // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs);
+}
+
+void
+change_thread_state(int thread_number, int activate, int priority)
+{
+}
+
+// precise architected memory state accessor macros
+template <class T>
+Fault
+SimpleCPU::read(Addr addr, T& data, unsigned flags)
+{
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataReadReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->read(memReq, data);
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ if (fault == No_Fault)
+ traceData->setData(data);
+ }
+
+ // if we have a cache, do cache access too
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Read;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ return fault;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, double& data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, float& data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, int32_t& data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+
+template <class T>
+Fault
+SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataWriteReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->write(memReq, data);
+
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Write;
+ memReq->data = (uint8_t *)&data;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ if (res && (fault == No_Fault))
+ *res = memReq->result;
+
+ return fault;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+#ifdef FULL_SYSTEM
+Addr
+SimpleCPU::dbg_vtophys(Addr addr)
+{
+ return vtophys(xc, addr);
+}
+#endif // FULL_SYSTEM
+
+Tick save_cycle = 0;
+
+
+void
+SimpleCPU::processCacheCompletion()
+{
+ switch (status()) {
+ case IcacheMissStall:
+ icacheStallCycles += curTick - lastIcacheStall;
+ setStatus(IcacheMissComplete);
+ break;
+ case DcacheMissStall:
+ dcacheStallCycles += curTick - lastDcacheStall;
+ setStatus(Running);
+ break;
+ default:
+ panic("SimpleCPU::processCacheCompletion: bad state");
+ break;
+ }
+}
+
+#ifdef FULL_SYSTEM
+void
+SimpleCPU::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (xc->status() == ExecContext::Suspended) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+ xc->setStatus(ExecContext::Active);
+ Annotate::Resume(xc);
+ }
+}
+#endif // FULL_SYSTEM
+
+/* start simulation, program loaded, processor precise state initialized */
+void
+SimpleCPU::tick()
+{
+ traceData = NULL;
+
+#ifdef FULL_SYSTEM
+ if (fault == No_Fault && AlphaISA::check_interrupts &&
+ xc->cpu->check_interrupts() &&
+ !PC_PAL(xc->regs.pc) &&
+ status() != IcacheMissComplete) {
+ int ipl = 0;
+ int summary = 0;
+ AlphaISA::check_interrupts = 0;
+ IntReg *ipr = xc->regs.ipr;
+
+ if (xc->regs.ipr[TheISA::IPR_SIRR]) {
+ for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
+ i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
+ if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = xc->cpu->intr_status();
+ for(int i = TheISA::INTLEVEL_EXTERNAL_MIN;
+ i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+
+ if (ipr[TheISA::IPR_ASTRR])
+ panic("asynchronous traps not implemented\n");
+
+ if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
+ ipr[TheISA::IPR_ISR] = summary;
+ ipr[TheISA::IPR_INTID] = ipl;
+ xc->ev5_trap(Interrupt_Fault);
+
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ ipr[TheISA::IPR_IPLR], ipl, summary);
+ }
+ }
+#endif
+
+ // maintain $r0 semantics
+ xc->regs.intRegFile[ZeroReg] = 0;
+#ifdef TARGET_ALPHA
+ xc->regs.floatRegFile.d[ZeroReg] = 0.0;
+#endif // TARGET_ALPHA
+
+ if (status() == IcacheMissComplete) {
+ // We've already fetched an instruction and were stalled on an
+ // I-cache miss. No need to fetch it again.
+
+ setStatus(Running);
+ }
+ else {
+ // Try to fetch an instruction
+
+ // set up memory request for instruction fetch
+#ifdef FULL_SYSTEM
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#else
+#define IFETCH_FLAGS(pc) 0
+#endif
+
+ memReq->cmd = Read;
+ memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
+ IFETCH_FLAGS(xc->regs.pc));
+
+ fault = xc->translateInstReq(memReq);
+
+ if (fault == No_Fault)
+ fault = xc->mem->read(memReq, inst);
+
+ if (icacheInterface && fault == No_Fault) {
+ memReq->completionEvent = NULL;
+
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = icacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && icacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(IcacheMissStall);
+ return;
+ }
+ }
+ }
+
+ // If we've got a valid instruction (i.e., no fault on instruction
+ // fetch), then execute it.
+ if (fault == No_Fault) {
+
+ // keep an instruction count
+ numInst++;
+
+ // check for instruction-count-based events
+ comInsnEventQueue[0]->serviceEvents(numInst);
+
+ // decode the instruction
+ StaticInstPtr<TheISA> si(inst);
+
+ traceData = Trace::getInstRecord(curTick, xc, this, si,
+ xc->regs.pc);
+
+#ifdef FULL_SYSTEM
+ xc->regs.opcode = (inst >> 26) & 0x3f;
+ xc->regs.ra = (inst >> 21) & 0x1f;
+#endif // FULL_SYSTEM
+
+ xc->func_exe_insn++;
+
+ fault = si->execute(this, xc, traceData);
+
+ if (si->isMemRef()) {
+ numMemRefs++;
+ }
+
+ if (traceData)
+ traceData->finalize();
+
+ } // if (fault == No_Fault)
+
+ if (fault != No_Fault) {
+#ifdef FULL_SYSTEM
+ xc->ev5_trap(fault);
+#else // !FULL_SYSTEM
+ fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
+#endif // FULL_SYSTEM
+ }
+ else {
+ // go to the next instruction
+ xc->regs.pc = xc->regs.npc;
+ xc->regs.npc += sizeof(MachInst);
+ }
+
+#ifdef FULL_SYSTEM
+ Addr oldpc;
+ do {
+ oldpc = xc->regs.pc;
+ system->pcEventQueue.service(xc);
+ } while (oldpc != xc->regs.pc);
+#endif
+
+ assert(status() == Running ||
+ status() == Idle ||
+ status() == DcacheMissStall);
+
+ if (status() == Running && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimpleCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+
+#ifdef FULL_SYSTEM
+ SimObjectParam<AlphaItb *> itb;
+ SimObjectParam<AlphaDtb *> dtb;
+ SimObjectParam<FunctionalMemory *> mem;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<int> mult;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "terminate when any thread reaches this insn count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "terminate when all threads have reached this insn count",
+ 0),
+
+#ifdef FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(mem, "memory"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0),
+ INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
+ INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+
+CREATE_SIM_OBJECT(SimpleCPU)
+{
+#ifdef FULL_SYSTEM
+ if (mult != 1)
+ panic("processor clock multiplier must be 1\n");
+
+ return new SimpleCPU(getInstanceName(), system,
+ max_insts_any_thread, max_insts_all_threads,
+ itb, dtb, mem,
+ (icache) ? icache->getInterface() : NULL,
+ (dcache) ? dcache->getInterface() : NULL,
+ cpu_id, ticksPerSecond * mult);
+#else
+
+ return new SimpleCPU(getInstanceName(), workload,
+ max_insts_any_thread, max_insts_all_threads,
+ icache->getInterface(), dcache->getInterface());
+
+#endif // FULL_SYSTEM
+}
+
+REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
diff --git a/sim/simple_cpu.hh b/sim/simple_cpu.hh
new file mode 100644
index 000000000..c5671eb6f
--- /dev/null
+++ b/sim/simple_cpu.hh
@@ -0,0 +1,280 @@
+/*
+ * 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 __SIMPLE_CPU_HH__
+#define __SIMPLE_CPU_HH__
+
+#include "base_cpu.hh"
+#include "eventq.hh"
+#include "symtab.hh"
+#include "pc_event.hh"
+#include "statistics.hh"
+
+
+// forward declarations
+#ifdef FULL_SYSTEM
+class Processor;
+class Kernel;
+class AlphaItb;
+class AlphaDtb;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+#endif // FULL_SYSTEM
+
+class MemInterface;
+class IniFile;
+
+namespace Trace {
+ class InstRecord;
+}
+
+class SimpleCPU : public BaseCPU
+{
+ public:
+ // main simulation loop (one cycle)
+ void tick();
+
+ private:
+ class TickEvent : public Event
+ {
+ private:
+ SimpleCPU *cpu;
+
+ public:
+ TickEvent(SimpleCPU *c)
+ : Event(&mainEventQueue, 100), cpu(c) { }
+ void process() { cpu->tick(); }
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ private:
+ Trace::InstRecord *traceData;
+ template<typename T>
+ void trace_data(T data) {
+ if (traceData) {
+ traceData->setData(data);
+ }
+ };
+
+ public:
+ //
+ enum Status {
+ Running,
+ Idle,
+ IcacheMissStall,
+ IcacheMissComplete,
+ DcacheMissStall
+ };
+
+ private:
+ Status _status;
+
+ public:
+ void post_interrupt(int int_num, int index);
+
+ void zero_fill_64(Addr addr) {
+ static int warned = 0;
+ if (!warned) {
+ warn ("WH64 is not implemented");
+ warned = 1;
+ }
+ };
+
+#ifdef FULL_SYSTEM
+
+ SimpleCPU(const std::string &_name,
+ System *_system,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem,
+ MemInterface *icache_interface, MemInterface *dcache_interface,
+ int cpu_id, Tick freq);
+
+#else
+
+ SimpleCPU(const std::string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface, MemInterface *dcache_interface);
+
+#endif
+
+ virtual ~SimpleCPU();
+
+ // execution context
+ ExecContext *xc;
+
+#ifdef FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+
+ bool interval_stats;
+#endif
+
+ // L1 instruction cache
+ MemInterface *icacheInterface;
+
+ // L1 data cache
+ MemInterface *dcacheInterface;
+
+ // current instruction
+ MachInst inst;
+
+ // current fault status
+ Fault fault;
+
+ // Refcounted pointer to the one memory request.
+ MemReqPtr memReq;
+
+ class CacheCompletionEvent : public Event
+ {
+ private:
+ SimpleCPU *cpu;
+
+ public:
+ CacheCompletionEvent(SimpleCPU *_cpu);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ CacheCompletionEvent cacheCompletionEvent;
+
+ Status status() const { return _status; }
+ virtual void execCtxStatusChg() {
+ if (xc) {
+ if (xc->status() == ExecContext::Active)
+ setStatus(Running);
+ else
+ setStatus(Idle);
+ }
+ }
+
+ void setStatus(Status new_status) {
+ Status old_status = status();
+ _status = new_status;
+
+ switch (status()) {
+ case IcacheMissStall:
+ assert(old_status == Running);
+ lastIcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case IcacheMissComplete:
+ assert(old_status == IcacheMissStall);
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ case DcacheMissStall:
+ assert(old_status == Running);
+ lastDcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Idle:
+ assert(old_status == Running);
+ last_idle = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Running:
+ assert(old_status == Idle ||
+ old_status == DcacheMissStall ||
+ old_status == IcacheMissComplete);
+ if (old_status == Idle)
+ idleCycles += curTick - last_idle;
+
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ default:
+ panic("can't get here");
+ }
+ }
+
+ // statistics
+ void regStats();
+
+ // number of simulated instructions
+ Counter numInst;
+ Statistics::Formula numInsts;
+
+ // number of simulated memory references
+ Statistics::Scalar<> numMemRefs;
+
+ // number of idle cycles
+ Statistics::Scalar<> idleCycles;
+ Statistics::Formula idleFraction;
+ Counter last_idle;
+
+ // number of cycles stalled for I-cache misses
+ Statistics::Scalar<> icacheStallCycles;
+ Counter lastIcacheStall;
+
+ // number of cycles stalled for D-cache misses
+ Statistics::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ void processCacheCompletion();
+
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+
+ template <class T>
+ Fault read(Addr addr, T& data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags,
+ uint64_t *res);
+
+ Fault prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ return No_Fault;
+ }
+
+ void writeHint(Addr addr, int size)
+ {
+ // need to do this...
+ }
+};
+
+#endif // __SIMPLE_CPU_HH__
diff --git a/sim/smt.hh b/sim/smt.hh
new file mode 100644
index 000000000..f9c1e4614
--- /dev/null
+++ b/sim/smt.hh
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Defines SMT_MAX_CPUS and SMT_MAX_THREADS.
+ */
+
+#ifndef __SMT_HH__
+#define __SMT_HH__
+
+#ifndef SMT_MAX_CPUS
+/** The maximum number of cpus in any one system. */
+#define SMT_MAX_CPUS 4
+#endif
+
+#ifndef SMT_MAX_THREADS
+/** The number of TPUs in any processor. */
+#define SMT_MAX_THREADS 4
+#endif
+
+/**
+ * The maximum number of active threads across all cpus. Used to
+ * initialize per-thread statistics in the cache.
+ *
+ * NB: Be careful to only use it once all the CPUs that you care about
+ * have been initialized
+ */
+extern int maxThreadsPerCPU;
+
+/**
+ * Changes the status and priority of the thread with the given number.
+ * @param thread_number The thread to change.
+ * @param activate The new active status.
+ * @param priority The new priority.
+ */
+void change_thread_state(int thread_number, int activate, int priority);
+
+#endif // __SMT_HH__
diff --git a/sim/static_inst.cc b/sim/static_inst.cc
new file mode 100644
index 000000000..cf25d5f05
--- /dev/null
+++ b/sim/static_inst.cc
@@ -0,0 +1,88 @@
+/*
+ * 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 "static_inst.hh"
+#include "universe.hh"
+
+template <class ISA>
+StaticInstPtr<ISA> StaticInst<ISA>::nullStaticInstPtr;
+
+template <class ISA>
+typename StaticInst<ISA>::DecodeCache StaticInst<ISA>::decodeCache;
+
+// Define the decode cache hash map.
+template StaticInst<AlphaISA>::DecodeCache
+StaticInst<AlphaISA>::decodeCache;
+
+template <class ISA>
+void
+StaticInst<ISA>::dumpDecodeCacheStats()
+{
+ using namespace std;
+
+ cerr << "Decode hash table stats @ " << curTick << ":" << endl;
+ cerr << "\tnum entries = " << decodeCache.size() << endl;
+ cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl;
+ vector<int> hist(100, 0);
+ int max_hist = 0;
+ for (int i = 0; i < decodeCache.bucket_count(); ++i) {
+ int count = decodeCache.elems_in_bucket(i);
+ if (count > max_hist)
+ max_hist = count;
+ hist[count]++;
+ }
+ for (int i = 0; i <= max_hist; ++i) {
+ cerr << "\tbuckets of size " << i << " = " << hist[i] << endl;
+ }
+}
+
+
+template StaticInstPtr<AlphaISA>
+StaticInst<AlphaISA>::nullStaticInstPtr;
+
+template <class ISA>
+bool
+StaticInst<ISA>::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt)
+{
+ if (isDirectCtrl()) {
+ tgt = branchTarget(pc);
+ return true;
+ }
+
+ if (isIndirectCtrl()) {
+ tgt = branchTarget(xc);
+ return true;
+ }
+
+ return false;
+}
+
+
+// force instantiation of template function(s) above
+template StaticInst<AlphaISA>;
diff --git a/sim/static_inst.hh b/sim/static_inst.hh
new file mode 100644
index 000000000..b8f9cc00a
--- /dev/null
+++ b/sim/static_inst.hh
@@ -0,0 +1,433 @@
+/*
+ * 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 __STATIC_INST_HH__
+#define __STATIC_INST_HH__
+
+#include <bitset>
+#include <string>
+
+#include "host.hh"
+#include "hashmap.hh"
+#include "refcnt.hh"
+
+#include "op_class.hh"
+#include "isa_traits.hh"
+
+// forward declarations
+class ExecContext;
+class SpecExecContext;
+class SimpleCPU;
+class CPU;
+class DynInst;
+class SymbolTable;
+
+namespace Trace {
+ class InstRecord;
+}
+
+/**
+ * Base, ISA-independent static instruction class.
+ *
+ * The main component of this class is the vector of flags and the
+ * associated methods for reading them. Any object that can rely
+ * solely on these flags can process instructions without being
+ * recompiled for multiple ISAs.
+ */
+class StaticInstBase : public RefCounted
+{
+ protected:
+
+ /// Set of boolean static instruction properties.
+ ///
+ /// Notes:
+ /// - The IsInteger and IsFloating flags are based on the class of
+ /// registers accessed by the instruction. Although most
+ /// instructions will have exactly one of these two flags set, it
+ /// is possible for an instruction to have neither (e.g., direct
+ /// unconditional branches, memory barriers) or both (e.g., an
+ /// FP/int conversion).
+ /// - If IsMemRef is set, then exactly one of IsLoad or IsStore
+ /// will be set. Prefetches are marked as IsLoad, even if they
+ /// prefetch exclusive copies.
+ /// - If IsControl is set, then exactly one of IsDirectControl or
+ /// IsIndirect Control will be set, and exactly one of
+ /// IsCondControl or IsUncondControl will be set.
+ ///
+ enum Flags {
+ IsNop, ///< Is a no-op (no effect at all).
+
+ IsInteger, ///< References integer regs.
+ IsFloating, ///< References FP regs.
+
+ IsMemRef, ///< References memory (load, store, or prefetch).
+ IsLoad, ///< Reads from memory (load or prefetch).
+ IsStore, ///< Writes to memory.
+ IsInstPrefetch, ///< Instruction-cache prefetch.
+ IsDataPrefetch, ///< Data-cache prefetch.
+
+ IsControl, ///< Control transfer instruction.
+ IsDirectControl, ///< PC relative control transfer.
+ IsIndirectControl, ///< Register indirect control transfer.
+ IsCondControl, ///< Conditional control transfer.
+ IsUncondControl, ///< Unconditional control transfer.
+ IsCall, ///< Subroutine call.
+ IsReturn, ///< Subroutine return.
+
+ IsThreadSync, ///< Thread synchronization operation.
+
+ NumFlags
+ };
+
+ /// Flag values for this instruction.
+ std::bitset<NumFlags> flags;
+
+ /// See opClass().
+ OpClass _opClass;
+
+ /// See numSrcRegs().
+ int8_t _numSrcRegs;
+
+ /// See numDestRegs().
+ int8_t _numDestRegs;
+
+ /// The following are used to track physical register usage
+ /// for machines with separate int & FP reg files.
+ //@{
+ int8_t _numFPDestRegs;
+ int8_t _numIntDestRegs;
+ //@}
+
+ /// Constructor.
+ /// It's important to initialize everything here to a sane
+ /// default, since the decoder generally only overrides
+ /// the fields that are meaningful for the particular
+ /// instruction.
+ StaticInstBase(OpClass __opClass)
+ : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0),
+ _numFPDestRegs(0), _numIntDestRegs(0)
+ {
+ }
+
+ public:
+
+ /// @name Register information.
+ /// The sum of numFPDestRegs() and numIntDestRegs() equals
+ /// numDestRegs(). The former two functions are used to track
+ /// physical register usage for machines with separate int & FP
+ /// reg files.
+ //@{
+ /// Number of source registers.
+ int8_t numSrcRegs() const { return _numSrcRegs; }
+ /// Number of destination registers.
+ int8_t numDestRegs() const { return _numDestRegs; }
+ /// Number of floating-point destination regs.
+ int8_t numFPDestRegs() const { return _numFPDestRegs; }
+ /// Number of integer destination regs.
+ int8_t numIntDestRegs() const { return _numIntDestRegs; }
+ //@}
+
+ /// @name Flag accessors.
+ /// These functions are used to access the values of the various
+ /// instruction property flags. See StaticInstBase::Flags for descriptions
+ /// of the individual flags.
+ //@{
+
+ bool isNop() const { return flags[IsNop]; }
+
+ bool isMemRef() const { return flags[IsMemRef]; }
+ bool isLoad() const { return flags[IsLoad]; }
+ bool isStore() const { return flags[IsStore]; }
+ bool isInstPrefetch() const { return flags[IsInstPrefetch]; }
+ bool isDataPrefetch() const { return flags[IsDataPrefetch]; }
+
+ bool isInteger() const { return flags[IsInteger]; }
+ bool isFloating() const { return flags[IsFloating]; }
+
+ bool isControl() const { return flags[IsControl]; }
+ bool isCall() const { return flags[IsCall]; }
+ bool isReturn() const { return flags[IsReturn]; }
+ bool isDirectCtrl() const { return flags[IsDirectControl]; }
+ bool isIndirectCtrl() const { return flags[IsIndirectControl]; }
+ bool isCondCtrl() const { return flags[IsCondControl]; }
+ bool isUncondCtrl() const { return flags[IsUncondControl]; }
+
+ bool isThreadSync() const { return flags[IsThreadSync]; }
+ //@}
+
+ /// Operation class. Used to select appropriate function unit in issue.
+ OpClass opClass() const { return _opClass; }
+};
+
+
+// forward declaration
+template <class ISA>
+class StaticInstPtr;
+
+/**
+ * Generic yet ISA-dependent static instruction class.
+ *
+ * This class builds on StaticInstBase, defining fields and interfaces
+ * that are generic across all ISAs but that differ in details
+ * according to the specific ISA being used.
+ */
+template <class ISA>
+class StaticInst : public StaticInstBase
+{
+ public:
+
+ /// Binary machine instruction type.
+ typedef typename ISA::MachInst MachInst;
+ /// Memory address type.
+ typedef typename ISA::Addr Addr;
+ /// Logical register index type.
+ typedef typename ISA::RegIndex RegIndex;
+
+ enum {
+ MaxInstSrcRegs = ISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = ISA::MaxInstDestRegs, //< Max dest regs
+ };
+
+
+ /// Return logical index (architectural reg num) of i'th destination reg.
+ /// Only the entries from 0 through numDestRegs()-1 are valid.
+ RegIndex destRegIdx(int i) { return _destRegIdx[i]; }
+
+ /// Return logical index (architectural reg num) of i'th source reg.
+ /// Only the entries from 0 through numSrcRegs()-1 are valid.
+ RegIndex srcRegIdx(int i) { return _srcRegIdx[i]; }
+
+ /// Pointer to a statically allocated "null" instruction object.
+ /// Used to give eaCompInst() and memAccInst() something to return
+ /// when called on non-memory instructions.
+ static StaticInstPtr<ISA> nullStaticInstPtr;
+
+ /**
+ * Memory references only: returns "fake" instruction representing
+ * the effective address part of the memory operation. Used to
+ * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
+ * just the EA computation.
+ */
+ virtual StaticInstPtr<ISA> eaCompInst() { return nullStaticInstPtr; }
+
+ /**
+ * Memory references only: returns "fake" instruction representing
+ * the memory access part of the memory operation. Used to
+ * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
+ * just the memory access (not the EA computation).
+ */
+ virtual StaticInstPtr<ISA> memAccInst() { return nullStaticInstPtr; }
+
+ /// The binary machine instruction.
+ const MachInst machInst;
+
+ protected:
+
+ /// See destRegIdx().
+ RegIndex _destRegIdx[MaxInstDestRegs];
+ /// See srcRegIdx().
+ RegIndex _srcRegIdx[MaxInstSrcRegs];
+
+ /**
+ * Base mnemonic (e.g., "add"). Used by generateDisassembly()
+ * methods. Also useful to readily identify instructions from
+ * within the debugger when #cachedDisassembly has not been
+ * initialized.
+ */
+ const char *mnemonic;
+
+ /**
+ * String representation of disassembly (lazily evaluated via
+ * disassemble()).
+ */
+ std::string *cachedDisassembly;
+
+ /**
+ * Internal function to generate disassembly string.
+ */
+ virtual std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) = 0;
+
+ /// Constructor.
+ StaticInst(const char *_mnemonic, MachInst _machInst, OpClass __opClass)
+ : StaticInstBase(__opClass),
+ machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0)
+ {
+ }
+
+ public:
+
+ virtual ~StaticInst()
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+ }
+
+ /**
+ * Execute this instruction under SimpleCPU model.
+ */
+ virtual Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * Execute this instruction under detailed CPU model.
+ */
+ virtual Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * Return the target address for a PC-relative branch.
+ * Invalid if not a PC-relative branch (i.e. isDirectCtrl()
+ * should be true).
+ */
+ virtual Addr branchTarget(Addr branchPC)
+ {
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not a PC-relative branch.");
+ }
+
+ /**
+ * Return the target address for an indirect branch (jump).
+ * The register value is read from the supplied execution context.
+ * Invalid if not an indirect branch (i.e. isIndirectCtrl()
+ * should be true).
+ */
+ virtual Addr branchTarget(ExecContext *xc)
+ {
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not an indirect branch.");
+ }
+
+ /**
+ * Return true if the instruction is a control transfer, and if so,
+ * return the target address as well.
+ */
+ bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt);
+
+ /**
+ * Return string representation of disassembled instruction.
+ * The default version of this function will call the internal
+ * virtual generateDisassembly() function to get the string,
+ * then cache it in #cachedDisassembly. If the disassembly
+ * should not be cached, this function should be overridden directly.
+ */
+ virtual const std::string &disassemble(Addr pc,
+ const SymbolTable *symtab = 0)
+ {
+ if (!cachedDisassembly)
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+
+ return *cachedDisassembly;
+ }
+
+ /// Decoded instruction cache type.
+ /// For now we're using a generic hash_map; this seems to work
+ /// pretty well.
+ typedef m5::hash_map<MachInst, StaticInstPtr<ISA> > DecodeCache;
+
+ /// A cache of decoded instruction objects.
+ static DecodeCache decodeCache;
+
+ /**
+ * Dump some basic stats on the decode cache hash map.
+ * Only gets called if DECODE_CACHE_HASH_STATS is defined.
+ */
+ static void dumpDecodeCacheStats();
+
+ /// Decode a machine instruction.
+ /// @param mach_inst The binary instruction to decode.
+ /// @retval A pointer to the corresponding StaticInst object.
+ static
+ StaticInstPtr<ISA> decode(MachInst mach_inst)
+ {
+#ifdef DECODE_CACHE_HASH_STATS
+ // Simple stats on decode hash_map. Turns out the default
+ // hash function is as good as anything I could come up with.
+ const int dump_every_n = 10000000;
+ static int decodes_til_dump = dump_every_n;
+
+ if (--decodes_til_dump == 0) {
+ dumpDecodeCacheStats();
+ decodes_til_dump = dump_every_n;
+ }
+#endif
+
+ typename DecodeCache::iterator iter = decodeCache.find(mach_inst);
+ if (iter != decodeCache.end()) {
+ return iter->second;
+ }
+
+ StaticInstPtr<ISA> si = ISA::decodeInst(mach_inst);
+ decodeCache[mach_inst] = si;
+ return si;
+ }
+};
+
+typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
+
+/// Reference-counted pointer to a StaticInst object.
+/// This type should be used instead of "StaticInst<ISA> *" so that
+/// StaticInst objects can be properly reference-counted.
+template <class ISA>
+class StaticInstPtr : public RefCountingPtr<StaticInst<ISA> >
+{
+ public:
+ /// Constructor.
+ StaticInstPtr()
+ : RefCountingPtr<StaticInst<ISA> >()
+ {
+ }
+
+ /// Conversion from "StaticInst<ISA> *".
+ StaticInstPtr(StaticInst<ISA> *p)
+ : RefCountingPtr<StaticInst<ISA> >(p)
+ {
+ }
+
+ /// Copy constructor.
+ StaticInstPtr(const StaticInstPtr &r)
+ : RefCountingPtr<StaticInst<ISA> >(r)
+ {
+ }
+
+ /// Construct directly from machine instruction.
+ /// Calls StaticInst<ISA>::decode().
+ StaticInstPtr(typename ISA::MachInst mach_inst)
+ : RefCountingPtr<StaticInst<ISA> >(StaticInst<ISA>::decode(mach_inst))
+ {
+ }
+
+ /// Convert to pointer to StaticInstBase class.
+ operator const StaticInstBasePtr()
+ {
+ return get();
+ }
+};
+
+#endif // __STATIC_INST_HH__
diff --git a/sim/std_types.hh b/sim/std_types.hh
new file mode 100644
index 000000000..9c3898ff7
--- /dev/null
+++ b/sim/std_types.hh
@@ -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.
+ */
+
+#ifndef __STD_TYPES_HH__
+#define __STD_TYPES_HH__
+
+// inst sequence type, used to order instructions in the ready list,
+// if this rolls over the ready list order temporarily will get messed
+// up, but execution will continue and complete correctly
+typedef unsigned long long InstSeqNum;
+
+// inst tag type, used to tag an operation instance in the IQ
+typedef unsigned int InstTag;
+
+#endif // __STD_TYPES_HH__
diff --git a/sim/system.cc b/sim/system.cc
new file mode 100644
index 000000000..04db8b134
--- /dev/null
+++ b/sim/system.cc
@@ -0,0 +1,250 @@
+/*
+ * 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 "kernel_loader.hh"
+#include "exec_context.hh"
+#include "object_file.hh"
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "symtab.hh"
+#include "remote_gdb.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "trace.hh"
+
+using namespace std;
+
+vector<System *> System::systemList;
+
+int System::numSystemsRunning = 0;
+
+System::System(const std::string _name,
+ MemoryController *_memCtrl,
+ PhysicalMemory *_physmem,
+ const std::string &kernel_path,
+ const std::string &console_path,
+ const std::string &palcode,
+ const std::string &boot_osflags)
+ : SimObject(_name),
+ kernel_panic_event(&pcEventQueue, "kernel panic"),
+ console_panic_event(&pcEventQueue, "console panic"),
+ badaddr_event(&pcEventQueue, "badaddr"),
+ skip_power_state(&pcEventQueue, "tl_v48_capture_power_state"),
+ skip_scavenge_boot(&pcEventQueue, "pmap_scavenge_boot"),
+ printf_event(&pcEventQueue, "printf"),
+ debug_printf_event(&pcEventQueue, "debug_printf", false),
+ debug_printfr_event(&pcEventQueue, "debug_printfr", true),
+ dump_mbuf_event(&pcEventQueue, "dump_mbuf"),
+ memCtrl(_memCtrl),
+ physmem(_physmem),
+ remoteGDB(NULL),
+ gdbListen(NULL)
+{
+ kernelSymtab = new SymbolTable;
+ consoleSymtab = new SymbolTable;
+
+ EcoffObject kernel(kernel_path);
+ EcoffObject console(console_path);
+
+ if (!kernel.loadGlobals(kernelSymtab))
+ panic("could not load kernel symbols\n");
+
+ if (!console.loadGlobals(consoleSymtab))
+ panic("could not load console symbols\n");
+
+ // Load pal file
+ loadPal(palcode, physmem, PAL_BASE);
+
+ // copy of initial reg file contents
+ initRegs = new RegFile;
+ memset(initRegs, 0, sizeof(RegFile));
+
+ // Load console file
+ loadKernel(console_path, physmem);
+
+ // Load kernel file
+ loadKernel(kernel_path, physmem, initRegs,
+ &kernelStart, &kernelEnd, &kernelEntry);
+
+ DPRINTF(Loader, "Kernel loaded...\n");
+
+#ifdef FULL_SYSTEM
+ Addr addr = 0;
+
+ for(int i = 0; i < 12/*MAX_CPUS*/; i++)
+ xc_array[i] = (ExecContext *) 0;
+
+ num_cpus = 0;
+
+ if (kernelSymtab->findAddress("enable_async_printf", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ uint8_t *enable_async_printf =
+ physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ if (enable_async_printf)
+ *(uint32_t *)enable_async_printf = 0;
+ }
+
+ if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ if (osflags)
+ strcpy(osflags, boot_osflags.c_str());
+ }
+
+ if (kernelSymtab->findAddress("panic", addr))
+ kernel_panic_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'panic\'");
+
+ if (consoleSymtab->findAddress("panic", addr))
+ console_panic_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("badaddr", addr))
+ badaddr_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'badaddr\'");
+
+ if (kernelSymtab->findAddress("tl_v48_capture_power_state", addr))
+ skip_power_state.schedule(addr);
+
+ if (kernelSymtab->findAddress("pmap_scavenge_boot", addr))
+ skip_scavenge_boot.schedule(addr);
+
+#if TRACING_ON
+ if (kernelSymtab->findAddress("printf", addr))
+ printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printf", addr))
+ debug_printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printfr", addr))
+ debug_printfr_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5_dump_mbuf", addr))
+ dump_mbuf_event.schedule(addr);
+#endif
+
+#endif
+
+ // add self to global system list
+ systemList.push_back(this);
+
+ numSystemsRunning++;
+}
+
+
+System::~System()
+{
+ delete kernelSymtab;
+ delete consoleSymtab;
+ delete initRegs;
+}
+
+
+void
+System::initBootContext(ExecContext *xc)
+{
+ xc->regs = *initRegs;
+
+ remoteGDB = new RemoteGDB(this, xc);
+ gdbListen = new GDBListener(remoteGDB, 7000);
+ gdbListen->listen();
+
+ // Reset the system
+ //
+ TheISA::init(physmem, &xc->regs);
+}
+
+
+void
+System::registerExecContext(ExecContext *xc)
+{
+ if (num_cpus == 12/*MAX_CPUS*/)
+ panic("Too many CPU's\n");
+ xc_array[xc->cpu_id] = xc;
+ num_cpus++;
+}
+
+
+void
+System::printSystems()
+{
+ vector<System *>::iterator i = systemList.begin();
+ vector<System *>::iterator end = systemList.end();
+ for (; i != end; ++i) {
+ System *sys = *i;
+ cerr << "System " << sys->name() << ": " << hex << sys << endl;
+ }
+}
+
+
+extern "C"
+void
+printSystems()
+{
+ System::printSystems();
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
+
+ SimObjectParam<MemoryController *> mem_ctl;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel_code;
+ Param<string> console_code;
+ Param<string> pal_code;
+ Param<string> boot_osflags;
+
+END_DECLARE_SIM_OBJECT_PARAMS(System)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(System)
+
+ INIT_PARAM(mem_ctl, "memory controller"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel_code, "file that contains the kernel code"),
+ INIT_PARAM(console_code, "file that contains the console code"),
+ INIT_PARAM(pal_code, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a")
+
+END_INIT_SIM_OBJECT_PARAMS(System)
+
+
+CREATE_SIM_OBJECT(System)
+{
+ System *sys = new System(getInstanceName(), mem_ctl, physmem,
+ kernel_code, console_code, pal_code,
+ boot_osflags);
+
+ return sys;
+}
+
+REGISTER_SIM_OBJECT("System", System)
diff --git a/sim/system.hh b/sim/system.hh
new file mode 100644
index 000000000..bd2fd89b1
--- /dev/null
+++ b/sim/system.hh
@@ -0,0 +1,113 @@
+/*
+ * 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 __SYSTEM_HH__
+#define __SYSTEM_HH__
+
+#include <string>
+
+#include "sim_object.hh"
+#include "pc_event.hh"
+#include "symtab.hh"
+
+class MemoryController;
+class PhysicalMemory;
+class RemoteGDB;
+class GDBListener;
+
+class ExecContext;
+
+class System : public SimObject
+{
+ private:
+
+ SymbolTable *kernelSymtab;
+ SymbolTable *consoleSymtab;
+
+ BreakPCEvent kernel_panic_event;
+ BreakPCEvent console_panic_event;
+ BadAddrEvent badaddr_event;
+ SkipFuncEvent skip_power_state;
+ SkipFuncEvent skip_scavenge_boot;
+ PrintfEvent printf_event;
+ DebugPrintfEvent debug_printf_event;
+ DebugPrintfEvent debug_printfr_event;
+ DumpMbufEvent dump_mbuf_event;
+
+ RegFile *initRegs;
+
+ Addr kernelStart;
+ Addr kernelEnd;
+ Addr kernelEntry;
+
+ public:
+
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+ PCEventQueue pcEventQueue;
+
+ ExecContext *xc_array[12/*MAX_CPUS*/];
+ int num_cpus;
+
+ RemoteGDB *remoteGDB;
+ GDBListener *gdbListen;
+
+ System(const std::string name,
+ MemoryController *, PhysicalMemory *,
+ const std::string &kernel_path, const std::string &console_path,
+ const std::string &palcode, const std::string &boot_osflags);
+
+ ~System();
+
+ const SymbolTable *getKernelSymtab() const { return kernelSymtab; }
+ const SymbolTable *getConsoleSymtab() const { return consoleSymtab; }
+
+ Addr getKernelStart() const { return kernelStart; }
+ Addr getKernelEnd() const { return kernelEnd; }
+ Addr getKernelEntry() const { return kernelEntry; }
+
+ void initBootContext(ExecContext *xc);
+ void registerExecContext(ExecContext *xc);
+
+ ////////////////////////////////////////////
+ //
+ // STATIC GLOBAL SYSTEM LIST
+ //
+ ////////////////////////////////////////////
+
+ public:
+
+ static std::vector<System *> systemList;
+
+ static int numSystemsRunning;
+
+ static void printSystems();
+};
+
+#endif // __SYSTEM_HH__
diff --git a/sim/universe.cc b/sim/universe.cc
new file mode 100644
index 000000000..83f268b14
--- /dev/null
+++ b/sim/universe.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 <list>
+#include <string>
+#include <vector>
+
+#include "universe.hh"
+#include "host.hh"
+#include "param.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+Tick ticksPerSecond;
+
+class UniverseParamContext : public ParamContext
+{
+ public:
+ UniverseParamContext(const string &is) : ParamContext(is) {}
+ void checkParams();
+};
+
+UniverseParamContext universe("Universe");
+
+Param<Tick> universe_freq(&universe, "frequency", "tick frequency",
+ 200000000);
+
+void
+UniverseParamContext::checkParams()
+{
+ ticksPerSecond = universe_freq;
+}