00001 // Copyright 2010 Sandia Corporation. Under the terms 00002 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. 00003 // Government retains certain rights in this software. 00004 // 00005 // Copyright (c) 2005-2010, Sandia Corporation 00006 // All rights reserved. 00007 // Copyright (c) 2003-2005, University of Notre Dame 00008 // All rights reserved. 00009 // 00010 // This file is part of the SST software package. For license 00011 // information, see the LICENSE file in the top level directory of the 00012 // distribution. 00013 00014 00015 #ifndef THREAD_H 00016 #define THREAD_H 00017 00018 #include "instruction.h" 00019 #include "fe_memory.h" 00020 00021 #include <vector> 00022 using namespace std; 00023 00024 #include <string> 00025 using std::string; 00026 00027 //#include "sst/boost.h" 00028 #include "sst/core/component.h" 00029 00030 // forward declare function from ppcMachine.h so that we don't ahve to 00031 // drag all that code into here. 00032 void md_init_decoder(void); 00033 00034 class processor; 00035 class thread; 00036 00037 class threadSource { 00038 friend class boost::serialization::access; 00039 template<class Archive> 00040 void save(Archive & ar, const unsigned int version) const 00041 { 00042 ar & BOOST_SERIALIZATION_NVP(firstThreads); 00043 ar & BOOST_SERIALIZATION_NVP(proc); 00044 } 00045 template<class Archive> 00046 void load(Archive & ar, const unsigned int version) 00047 { 00048 ar & BOOST_SERIALIZATION_NVP(firstThreads); 00049 ar & BOOST_SERIALIZATION_NVP(proc); 00050 md_init_decoder(); 00051 } 00052 BOOST_SERIALIZATION_SPLIT_MEMBER() 00053 00054 vector<thread*> firstThreads; 00055 processor *proc; 00056 public: 00057 void init(processor *, SST::Component::Params_t& paramsC); 00058 thread* getFirstThread(unsigned int); 00059 void deleteThread(thread *t); 00060 }; 00061 00062 //: Front End Thread 00063 // 00064 // Representation of a thread. 00065 // 00066 // Threads are factories for instructions which are consumed by 00067 // processors. 00068 // 00069 // For backends which which to model out-of-order execution or branch 00070 // prediction, things are a bit more complex. The back end it required 00071 // to track the program counter. Instead of simply asking for the next 00072 // instruction, the backend must provide a program counter. The 00073 // backEnd is responsible for detecting when a misprediction has 00074 // occured. If it wishes to model speculative execution, it must 00075 // inform the thread that it is beginning speculation and when it is 00076 // ending speculative execution. 00077 // 00078 // This allows the thread to do something similar to 00079 // simpleScalar. When speculative execution begins, a copy of the 00080 // threads state is made which is used during the speculative 00081 // execution. When speculation ends, the thread can simply discard the 00082 // speculative state. 00083 // 00084 //!SEC:Framework 00085 class thread { 00086 string Cfgstr; 00087 friend class boost::serialization::access; 00088 template<class Archive> 00089 void serialize(Archive & ar, const unsigned int version ) 00090 { 00091 ar & BOOST_SERIALIZATION_NVP(callStack); 00092 ar & BOOST_SERIALIZATION_NVP(stackStack); 00093 ar & BOOST_SERIALIZATION_NVP(targetStack); 00094 ar & BOOST_SERIALIZATION_NVP(mem_accs); 00095 ar & BOOST_SERIALIZATION_NVP(_isDead); 00096 ar & BOOST_SERIALIZATION_NVP(eviction); 00097 ar & BOOST_SERIALIZATION_NVP(migration); 00098 } 00099 protected: 00100 vector<simAddress> callStack; 00101 vector<simAddress> stackStack; 00102 vector<simAddress> targetStack; 00103 //: Is this thread active? 00104 // 00105 // A thread may be 'dead' but has not been collected yet. 00106 bool _isDead; 00107 00108 simAddress stack_top, stack_base; 00109 unsigned int call_count, max_call_stk; 00110 unsigned int mem_accs[MemTypes]; 00111 00112 bool eviction, migration; 00113 00114 public: 00115 00116 void setEvict(bool tf) {eviction = tf;} 00117 bool canEvict() {return eviction;} 00118 void setMigrate(bool tf) {migration = tf;} 00119 bool canMigrate() {return migration;} 00120 00121 thread() : stack_base(0), eviction(true), migration(true) { 00122 for (int i = 0; i < MemTypes; i++) 00123 mem_accs[i] = 0; 00124 } 00125 00126 void recordMemStat(); 00127 00128 void freeStack(); 00129 #if 0 00130 void setStackLimits (simAddress max, simAddress min); 00131 int checkAccess (simAddress sa); 00132 virtual void printCallStack(); 00133 virtual simAddress popFromCallStack(); 00134 virtual void pushToCallStack(simAddress lr, simAddress sp, simAddress target); 00135 #endif 00136 00137 virtual ~thread() {;} 00138 //: Accessor for 'death' status of thread 00139 bool isDead() {return _isDead;}; 00140 //: Returns the next instruction in the stream 00141 // 00142 // This function may return a NULL if the thread cannot produce 00143 // another instruction. For example, it may not support more than 00144 // one outstanding instruction, or it may not be able to speculate 00145 // beyond a branch. 00146 virtual instruction* getNextInstruction()=0; 00147 //: Cancel execution of an instruction 00148 // 00149 // If an instruction which may have been fetch()ed and issue()ed 00150 // needs to be cancled, squash() allows this. The thread should 00151 // rollback any state changes caused by this instruction. An 00152 // instruction which has been commit()ed cannot be squash()ed. 00153 virtual bool squash(instruction *)=0; 00154 //: Finish an instruction 00155 // 00156 // After an instruction has been commit()ed, it should be retire()ed 00157 // so the thread can know it has been completed and is no longer 00158 // outstanding. 00159 // 00160 // This may fail if the thread detects and error. ex: an instruction 00161 // which was not issued from the thread was retired. 00162 virtual bool retire(instruction *)=0; 00163 //: Acquaint a thread with a new processor 00164 // 00165 // Upon arriving (or being created) at a processor, assimilate() is 00166 // called to allows the thread to perform whatever book keeping or 00167 // resource managemnt it requires. For example, allocating a frame 00168 // and copying in data. 00169 virtual void assimilate(processor *)=0; 00170 //: Prepare a thread to be migrated 00171 // 00172 // Tells a thread to prepare for migration. This may include 00173 // deallocating frames, copying data, etc... 00174 virtual void packageToSend(processor *)=0; 00175 //: Get InitalPC 00176 // 00177 // Get the address of the instruction where execution should start 00178 // (or resetart, after a thread migration say) 00179 virtual simAddress getStartPC()=0; 00180 //: Check PC validity 00181 // 00182 // See if a given address contains a valid instruction. Useful for 00183 // checking after branch prediction. 00184 virtual bool isPCValid(const simAddress)=0; 00185 //: Get instruction at given address 00186 // 00187 // Request an instruction at the given address from the thread. This 00188 // is required by back ends which may predict branches. 00189 virtual instruction* getNextInstruction(const simAddress)=0; 00190 //: Squash speculative state 00191 // 00192 // A processor may begin speculating down a 'wrong' path. After it 00193 // wishes to stop this speculation, it calls squashSpec() to dump 00194 // any changes to state that the "wrong" path may have performed. 00195 virtual void squashSpec()=0; 00196 //: Prepare speculative state 00197 // 00198 // A processor may begin speculating down a 'wrong' path. When it 00199 // begins to do so (say, after a branch mispredict) it calls 00200 // prepareSpec() so the thread can initialize a special speculative 00201 // state area which will be dumped eventually. 00202 virtual void prepareSpec()=0; 00203 //: Get process ID 00204 virtual simPID pid() const =0; 00205 //: Set process ID 00206 virtual void changePid(const simPID) =0; 00207 //: return instruction size in bytes 00208 // Required for some branch predictors. 00209 virtual int getInstructionSize()=0; 00210 00211 //: Return Stack location 00212 // 00213 // Optional for threads to implement. Default returns 0. 00214 virtual simRegister getStack() const {return 0;} 00215 00216 //: Returns if a given address is constant 00217 // 00218 // If a given region of memory is determined to be constant (i.e. 00219 // cstring sections). 00220 virtual bool isConstSection(const simAddress, const simPID) const {return 0;} 00221 00222 //: squash an instruction but keep it around. 00223 // 00224 // This performs the actions of a squash, but does not yet reclaim 00225 // the instruction data structure. This allows an instruction which 00226 // we know will be squashed to be removed from any internal thread 00227 // structures, but still keep the instruction data structure active 00228 // and valid (i.e. it is not recycled). 00229 virtual bool condemn(instruction *)=0; 00230 }; 00231 00232 #endif