diff options
Diffstat (limited to 'sim')
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(®s, 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 ®s); + + 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 ®s) +{ + 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 §ion); + ~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 §ion) + : 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; +} |