base.cc revision 612
16145Snate@binkert.org/* 26145Snate@binkert.org * Copyright (c) 2003 The Regents of The University of Michigan 36145Snate@binkert.org * All rights reserved. 46145Snate@binkert.org * 56145Snate@binkert.org * Redistribution and use in source and binary forms, with or without 66145Snate@binkert.org * modification, are permitted provided that the following conditions are 76145Snate@binkert.org * met: redistributions of source code must retain the above copyright 86145Snate@binkert.org * notice, this list of conditions and the following disclaimer; 96145Snate@binkert.org * redistributions in binary form must reproduce the above copyright 106145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 116145Snate@binkert.org * documentation and/or other materials provided with the distribution; 126145Snate@binkert.org * neither the name of the copyright holders nor the names of its 136145Snate@binkert.org * contributors may be used to endorse or promote products derived from 146145Snate@binkert.org * this software without specific prior written permission. 156145Snate@binkert.org * 166145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176145Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186145Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196145Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206145Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216145Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226145Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236145Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246145Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256145Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266145Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276145Snate@binkert.org */ 286145Snate@binkert.org 297048Snate@binkert.org#include <string> 307048Snate@binkert.org#include <sstream> 316145Snate@binkert.org#include <iostream> 327055Snate@binkert.org 337055Snate@binkert.org#include "cpu/base_cpu.hh" 347048Snate@binkert.org#include "base/cprintf.hh" 357048Snate@binkert.org#include "cpu/exec_context.hh" 3614184Sgabeblack@google.com#include "base/misc.hh" 3714184Sgabeblack@google.com#include "sim/param.hh" 386145Snate@binkert.org#include "sim/sim_events.hh" 396145Snate@binkert.org 406145Snate@binkert.orgusing namespace std; 417048Snate@binkert.org 427048Snate@binkert.orgvector<BaseCPU *> BaseCPU::cpuList; 437048Snate@binkert.org 447455Snate@binkert.org// This variable reflects the max number of threads in any CPU. Be 457455Snate@binkert.org// careful to only use it once all the CPUs that you care about have 467455Snate@binkert.org// been initialized 477455Snate@binkert.orgint maxThreadsPerCPU = 1; 487048Snate@binkert.org 496145Snate@binkert.org#ifdef FULL_SYSTEM 5011025Snilay@cs.wisc.eduBaseCPU::BaseCPU(const string &_name, int _number_of_threads, 518165Snilay@cs.wisc.edu Counter max_insts_any_thread, 527048Snate@binkert.org Counter max_insts_all_threads, 537048Snate@binkert.org Counter max_loads_any_thread, 547048Snate@binkert.org Counter max_loads_all_threads, 557048Snate@binkert.org System *_system, Tick freq) 5611025Snilay@cs.wisc.edu : SimObject(_name), frequency(freq), 577048Snate@binkert.org number_of_threads(_number_of_threads), system(_system) 586145Snate@binkert.org#else 597055Snate@binkert.orgBaseCPU::BaseCPU(const string &_name, int _number_of_threads, 606145Snate@binkert.org Counter max_insts_any_thread, 617456Snate@binkert.org Counter max_insts_all_threads, 627456Snate@binkert.org Counter max_loads_any_thread, 637456Snate@binkert.org Counter max_loads_all_threads) 647456Snate@binkert.org : SimObject(_name), number_of_threads(_number_of_threads) 657456Snate@binkert.org#endif 667456Snate@binkert.org{ 677456Snate@binkert.org // add self to global list of CPUs 687048Snate@binkert.org cpuList.push_back(this); 6911025Snilay@cs.wisc.edu 7011061Snilay@cs.wisc.edu if (number_of_threads > maxThreadsPerCPU) 7111061Snilay@cs.wisc.edu maxThreadsPerCPU = number_of_threads; 7211061Snilay@cs.wisc.edu 7311061Snilay@cs.wisc.edu // allocate per-thread instruction-based event queues 7411061Snilay@cs.wisc.edu comInstEventQueue = new (EventQueue *)[number_of_threads]; 7511061Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 767048Snate@binkert.org comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 777048Snate@binkert.org 786145Snate@binkert.org // 796145Snate@binkert.org // set up instruction-count-based termination events, if any 807055Snate@binkert.org // 817055Snate@binkert.org if (max_insts_any_thread != 0) 827048Snate@binkert.org for (int i = 0; i < number_of_threads; ++i) 837048Snate@binkert.org new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 847055Snate@binkert.org "a thread reached the max instruction count"); 857048Snate@binkert.org 867048Snate@binkert.org if (max_insts_all_threads != 0) { 877048Snate@binkert.org // allocate & initialize shared downcounter: each event will 887048Snate@binkert.org // decrement this when triggered; simulation will terminate 89 // when counter reaches 0 90 int *counter = new int; 91 *counter = number_of_threads; 92 for (int i = 0; i < number_of_threads; ++i) 93 new CountedExitEvent(comInstEventQueue[i], 94 "all threads reached the max instruction count", 95 max_insts_all_threads, *counter); 96 } 97 98 // allocate per-thread load-based event queues 99 comLoadEventQueue = new (EventQueue *)[number_of_threads]; 100 for (int i = 0; i < number_of_threads; ++i) 101 comLoadEventQueue[i] = new EventQueue("load-based event queue"); 102 103 // 104 // set up instruction-count-based termination events, if any 105 // 106 if (max_loads_any_thread != 0) 107 for (int i = 0; i < number_of_threads; ++i) 108 new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 109 "a thread reached the max load count"); 110 111 if (max_loads_all_threads != 0) { 112 // allocate & initialize shared downcounter: each event will 113 // decrement this when triggered; simulation will terminate 114 // when counter reaches 0 115 int *counter = new int; 116 *counter = number_of_threads; 117 for (int i = 0; i < number_of_threads; ++i) 118 new CountedExitEvent(comLoadEventQueue[i], 119 "all threads reached the max load count", 120 max_loads_all_threads, *counter); 121 } 122 123#ifdef FULL_SYSTEM 124 memset(interrupts, 0, sizeof(interrupts)); 125 intstatus = 0; 126#endif 127} 128 129 130void 131BaseCPU::regStats() 132{ 133 int size = execContexts.size(); 134 if (size > 1) { 135 for (int i = 0; i < size; ++i) { 136 stringstream namestr; 137 ccprintf(namestr, "%s.ctx%d", name(), i); 138 execContexts[i]->regStats(namestr.str()); 139 } 140 } else if (size == 1) 141 execContexts[0]->regStats(name()); 142} 143 144 145void 146BaseCPU::registerExecContexts() 147{ 148 for (int i = 0; i < execContexts.size(); ++i) { 149 ExecContext *xc = execContexts[i]; 150 int cpu_id; 151 152#ifdef FULL_SYSTEM 153 cpu_id = system->registerExecContext(xc); 154#else 155 cpu_id = xc->process->registerExecContext(xc); 156#endif 157 158 xc->cpu_id = cpu_id; 159 } 160} 161 162 163void 164BaseCPU::switchOut() 165{ 166 // default: do nothing 167} 168 169void 170BaseCPU::takeOverFrom(BaseCPU *oldCPU) 171{ 172 assert(execContexts.size() == oldCPU->execContexts.size()); 173 174 for (int i = 0; i < execContexts.size(); ++i) { 175 ExecContext *newXC = execContexts[i]; 176 ExecContext *oldXC = oldCPU->execContexts[i]; 177 178 newXC->takeOverFrom(oldXC); 179 assert(newXC->cpu_id == oldXC->cpu_id); 180#ifdef FULL_SYSTEM 181 system->replaceExecContext(newXC->cpu_id, newXC); 182#else 183 assert(newXC->process == oldXC->process); 184 newXC->process->replaceExecContext(newXC->cpu_id, newXC); 185#endif 186 } 187 188#ifdef FULL_SYSTEM 189 for (int i = 0; i < NumInterruptLevels; ++i) 190 interrupts[i] = oldCPU->interrupts[i]; 191 intstatus = oldCPU->intstatus; 192#endif 193} 194 195 196#ifdef FULL_SYSTEM 197void 198BaseCPU::post_interrupt(int int_num, int index) 199{ 200 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 201 202 if (int_num < 0 || int_num >= NumInterruptLevels) 203 panic("int_num out of bounds\n"); 204 205 if (index < 0 || index >= sizeof(uint8_t) * 8) 206 panic("int_num out of bounds\n"); 207 208 AlphaISA::check_interrupts = 1; 209 interrupts[int_num] |= 1 << index; 210 intstatus |= (ULL(1) << int_num); 211} 212 213void 214BaseCPU::clear_interrupt(int int_num, int index) 215{ 216 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 217 218 if (int_num < 0 || int_num >= NumInterruptLevels) 219 panic("int_num out of bounds\n"); 220 221 if (index < 0 || index >= sizeof(uint8_t) * 8) 222 panic("int_num out of bounds\n"); 223 224 interrupts[int_num] &= ~(1 << index); 225 if (interrupts[int_num] == 0) 226 intstatus &= ~(ULL(1) << int_num); 227} 228 229void 230BaseCPU::clear_interrupts() 231{ 232 DPRINTF(Interrupt, "Interrupts all cleared\n"); 233 234 memset(interrupts, 0, sizeof(interrupts)); 235 intstatus = 0; 236} 237 238#endif // FULL_SYSTEM 239 240// 241// This declaration is not needed now that SamplingCPU provides a 242// BaseCPUBuilder object. 243// 244#if 0 245DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 246#endif 247