base.cc revision 1062
1/* 2 * Copyright (c) 2002-2004 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <string> 30#include <sstream> 31#include <iostream> 32 33#include "cpu/base_cpu.hh" 34#include "base/cprintf.hh" 35#include "cpu/exec_context.hh" 36#include "base/misc.hh" 37#include "sim/param.hh" 38#include "sim/sim_events.hh" 39 40#include "base/trace.hh" 41 42using namespace std; 43 44vector<BaseCPU *> BaseCPU::cpuList; 45 46// This variable reflects the max number of threads in any CPU. Be 47// careful to only use it once all the CPUs that you care about have 48// been initialized 49int maxThreadsPerCPU = 1; 50 51extern void debug_break(); 52#ifdef FULL_SYSTEM 53BaseCPU::BaseCPU(const string &_name, int _number_of_threads, 54 Counter max_insts_any_thread, 55 Counter max_insts_all_threads, 56 Counter max_loads_any_thread, 57 Counter max_loads_all_threads, 58 System *_system, Tick freq) 59 : SimObject(_name), frequency(freq), 60 number_of_threads(_number_of_threads), system(_system) 61#else 62BaseCPU::BaseCPU(const string &_name, int _number_of_threads, 63 Counter max_insts_any_thread, 64 Counter max_insts_all_threads, 65 Counter max_loads_any_thread, 66 Counter max_loads_all_threads) 67 : SimObject(_name), number_of_threads(_number_of_threads) 68#endif 69{ 70 DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); 71 72 debug_break(); 73 74 // add self to global list of CPUs 75 cpuList.push_back(this); 76 77 DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", 78 this); 79 80 if (number_of_threads > maxThreadsPerCPU) 81 maxThreadsPerCPU = number_of_threads; 82 83 // allocate per-thread instruction-based event queues 84 comInstEventQueue = new (EventQueue *)[number_of_threads]; 85 for (int i = 0; i < number_of_threads; ++i) 86 comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 87 88 // 89 // set up instruction-count-based termination events, if any 90 // 91 if (max_insts_any_thread != 0) 92 for (int i = 0; i < number_of_threads; ++i) 93 new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 94 "a thread reached the max instruction count"); 95 96 if (max_insts_all_threads != 0) { 97 // allocate & initialize shared downcounter: each event will 98 // decrement this when triggered; simulation will terminate 99 // when counter reaches 0 100 int *counter = new int; 101 *counter = number_of_threads; 102 for (int i = 0; i < number_of_threads; ++i) 103 new CountedExitEvent(comInstEventQueue[i], 104 "all threads reached the max instruction count", 105 max_insts_all_threads, *counter); 106 } 107 108 // allocate per-thread load-based event queues 109 comLoadEventQueue = new (EventQueue *)[number_of_threads]; 110 for (int i = 0; i < number_of_threads; ++i) 111 comLoadEventQueue[i] = new EventQueue("load-based event queue"); 112 113 // 114 // set up instruction-count-based termination events, if any 115 // 116 if (max_loads_any_thread != 0) 117 for (int i = 0; i < number_of_threads; ++i) 118 new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 119 "a thread reached the max load count"); 120 121 if (max_loads_all_threads != 0) { 122 // allocate & initialize shared downcounter: each event will 123 // decrement this when triggered; simulation will terminate 124 // when counter reaches 0 125 int *counter = new int; 126 *counter = number_of_threads; 127 for (int i = 0; i < number_of_threads; ++i) 128 new CountedExitEvent(comLoadEventQueue[i], 129 "all threads reached the max load count", 130 max_loads_all_threads, *counter); 131 } 132 133#ifdef FULL_SYSTEM 134 memset(interrupts, 0, sizeof(interrupts)); 135 intstatus = 0; 136#endif 137} 138 139 140void 141BaseCPU::regStats() 142{ 143 using namespace Stats; 144 145 numCycles 146 .name(name() + ".numCycles") 147 .desc("number of cpu cycles simulated") 148 ; 149 150 int size = execContexts.size(); 151 if (size > 1) { 152 for (int i = 0; i < size; ++i) { 153 stringstream namestr; 154 ccprintf(namestr, "%s.ctx%d", name(), i); 155 execContexts[i]->regStats(namestr.str()); 156 } 157 } else if (size == 1) 158 execContexts[0]->regStats(name()); 159} 160 161 162void 163BaseCPU::registerExecContexts() 164{ 165 for (int i = 0; i < execContexts.size(); ++i) { 166 ExecContext *xc = execContexts[i]; 167 int cpu_id; 168 169#ifdef FULL_SYSTEM 170 cpu_id = system->registerExecContext(xc); 171#else 172 cpu_id = xc->process->registerExecContext(xc); 173#endif 174 175 xc->cpu_id = cpu_id; 176 } 177} 178 179 180void 181BaseCPU::switchOut() 182{ 183 // default: do nothing 184} 185 186void 187BaseCPU::takeOverFrom(BaseCPU *oldCPU) 188{ 189 assert(execContexts.size() == oldCPU->execContexts.size()); 190 191 for (int i = 0; i < execContexts.size(); ++i) { 192 ExecContext *newXC = execContexts[i]; 193 ExecContext *oldXC = oldCPU->execContexts[i]; 194 195 newXC->takeOverFrom(oldXC); 196 assert(newXC->cpu_id == oldXC->cpu_id); 197#ifdef FULL_SYSTEM 198 system->replaceExecContext(newXC->cpu_id, newXC); 199#else 200 assert(newXC->process == oldXC->process); 201 newXC->process->replaceExecContext(newXC->cpu_id, newXC); 202#endif 203 } 204 205#ifdef FULL_SYSTEM 206 for (int i = 0; i < NumInterruptLevels; ++i) 207 interrupts[i] = oldCPU->interrupts[i]; 208 intstatus = oldCPU->intstatus; 209#endif 210} 211 212 213#ifdef FULL_SYSTEM 214void 215BaseCPU::post_interrupt(int int_num, int index) 216{ 217 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 218 219 if (int_num < 0 || int_num >= NumInterruptLevels) 220 panic("int_num out of bounds\n"); 221 222 if (index < 0 || index >= sizeof(uint64_t) * 8) 223 panic("int_num out of bounds\n"); 224 225 AlphaISA::check_interrupts = 1; 226 interrupts[int_num] |= 1 << index; 227 intstatus |= (ULL(1) << int_num); 228} 229 230void 231BaseCPU::clear_interrupt(int int_num, int index) 232{ 233 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 234 235 if (int_num < 0 || int_num >= NumInterruptLevels) 236 panic("int_num out of bounds\n"); 237 238 if (index < 0 || index >= sizeof(uint64_t) * 8) 239 panic("int_num out of bounds\n"); 240 241 interrupts[int_num] &= ~(1 << index); 242 if (interrupts[int_num] == 0) 243 intstatus &= ~(ULL(1) << int_num); 244} 245 246void 247BaseCPU::clear_interrupts() 248{ 249 DPRINTF(Interrupt, "Interrupts all cleared\n"); 250 251 memset(interrupts, 0, sizeof(interrupts)); 252 intstatus = 0; 253} 254 255 256void 257BaseCPU::serialize(std::ostream &os) 258{ 259 SERIALIZE_ARRAY(interrupts, NumInterruptLevels); 260 SERIALIZE_SCALAR(intstatus); 261} 262 263void 264BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 265{ 266 UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels); 267 UNSERIALIZE_SCALAR(intstatus); 268} 269 270#endif // FULL_SYSTEM 271 272DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 273