base.cc revision 707
110008Snilay@cs.wisc.edu/* 210008Snilay@cs.wisc.edu * Copyright (c) 2003 The Regents of The University of Michigan 310008Snilay@cs.wisc.edu * All rights reserved. 410008Snilay@cs.wisc.edu * 510008Snilay@cs.wisc.edu * Redistribution and use in source and binary forms, with or without 610008Snilay@cs.wisc.edu * modification, are permitted provided that the following conditions are 710008Snilay@cs.wisc.edu * met: redistributions of source code must retain the above copyright 810008Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer; 910008Snilay@cs.wisc.edu * redistributions in binary form must reproduce the above copyright 1010008Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer in the 1110008Snilay@cs.wisc.edu * documentation and/or other materials provided with the distribution; 1210008Snilay@cs.wisc.edu * neither the name of the copyright holders nor the names of its 1310008Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from 1410008Snilay@cs.wisc.edu * this software without specific prior written permission. 1510008Snilay@cs.wisc.edu * 1610008Snilay@cs.wisc.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710008Snilay@cs.wisc.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810008Snilay@cs.wisc.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910008Snilay@cs.wisc.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010008Snilay@cs.wisc.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110008Snilay@cs.wisc.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210008Snilay@cs.wisc.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310008Snilay@cs.wisc.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410008Snilay@cs.wisc.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510008Snilay@cs.wisc.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610008Snilay@cs.wisc.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710008Snilay@cs.wisc.edu */ 2810008Snilay@cs.wisc.edu 2910008Snilay@cs.wisc.edu#include <string> 3010008Snilay@cs.wisc.edu#include <sstream> 3110008Snilay@cs.wisc.edu#include <iostream> 3210008Snilay@cs.wisc.edu 3310008Snilay@cs.wisc.edu#include "cpu/base_cpu.hh" 3410008Snilay@cs.wisc.edu#include "base/cprintf.hh" 3510008Snilay@cs.wisc.edu#include "cpu/exec_context.hh" 3610008Snilay@cs.wisc.edu#include "base/misc.hh" 3710008Snilay@cs.wisc.edu#include "sim/param.hh" 3810008Snilay@cs.wisc.edu#include "sim/sim_events.hh" 3910008Snilay@cs.wisc.edu 4010008Snilay@cs.wisc.eduusing namespace std; 4110008Snilay@cs.wisc.edu 4210008Snilay@cs.wisc.eduvector<BaseCPU *> BaseCPU::cpuList; 4310008Snilay@cs.wisc.edu 4410008Snilay@cs.wisc.edu// This variable reflects the max number of threads in any CPU. Be 4510008Snilay@cs.wisc.edu// careful to only use it once all the CPUs that you care about have 4610008Snilay@cs.wisc.edu// been initialized 4710008Snilay@cs.wisc.eduint maxThreadsPerCPU = 1; 4810008Snilay@cs.wisc.edu 4910008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 5010008Snilay@cs.wisc.eduBaseCPU::BaseCPU(const string &_name, int _number_of_threads, 5110008Snilay@cs.wisc.edu Counter max_insts_any_thread, 5210008Snilay@cs.wisc.edu Counter max_insts_all_threads, 5310008Snilay@cs.wisc.edu Counter max_loads_any_thread, 5410008Snilay@cs.wisc.edu Counter max_loads_all_threads, 5510008Snilay@cs.wisc.edu System *_system, Tick freq) 5610008Snilay@cs.wisc.edu : SimObject(_name), frequency(freq), 5710008Snilay@cs.wisc.edu number_of_threads(_number_of_threads), system(_system) 5810008Snilay@cs.wisc.edu#else 5910116Snilay@cs.wisc.eduBaseCPU::BaseCPU(const string &_name, int _number_of_threads, 6010008Snilay@cs.wisc.edu Counter max_insts_any_thread, 6110008Snilay@cs.wisc.edu Counter max_insts_all_threads, 6210008Snilay@cs.wisc.edu Counter max_loads_any_thread, 6310008Snilay@cs.wisc.edu Counter max_loads_all_threads) 6410008Snilay@cs.wisc.edu : SimObject(_name), number_of_threads(_number_of_threads) 6510008Snilay@cs.wisc.edu#endif 6610008Snilay@cs.wisc.edu{ 6710008Snilay@cs.wisc.edu // add self to global list of CPUs 6810008Snilay@cs.wisc.edu cpuList.push_back(this); 6910008Snilay@cs.wisc.edu 7010008Snilay@cs.wisc.edu if (number_of_threads > maxThreadsPerCPU) 7110008Snilay@cs.wisc.edu maxThreadsPerCPU = number_of_threads; 7210008Snilay@cs.wisc.edu 7310008Snilay@cs.wisc.edu // allocate per-thread instruction-based event queues 7410008Snilay@cs.wisc.edu comInstEventQueue = new (EventQueue *)[number_of_threads]; 7510008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 7610008Snilay@cs.wisc.edu comInstEventQueue[i] = new EventQueue("instruction-based event queue"); 7710008Snilay@cs.wisc.edu 7810008Snilay@cs.wisc.edu // 7910008Snilay@cs.wisc.edu // set up instruction-count-based termination events, if any 8010008Snilay@cs.wisc.edu // 8110008Snilay@cs.wisc.edu if (max_insts_any_thread != 0) 8210008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 8310008Snilay@cs.wisc.edu new SimExitEvent(comInstEventQueue[i], max_insts_any_thread, 8410008Snilay@cs.wisc.edu "a thread reached the max instruction count"); 8510008Snilay@cs.wisc.edu 8610008Snilay@cs.wisc.edu if (max_insts_all_threads != 0) { 8710008Snilay@cs.wisc.edu // allocate & initialize shared downcounter: each event will 8810008Snilay@cs.wisc.edu // decrement this when triggered; simulation will terminate 8910008Snilay@cs.wisc.edu // when counter reaches 0 9010008Snilay@cs.wisc.edu int *counter = new int; 9110008Snilay@cs.wisc.edu *counter = number_of_threads; 9210008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 9310008Snilay@cs.wisc.edu new CountedExitEvent(comInstEventQueue[i], 9410008Snilay@cs.wisc.edu "all threads reached the max instruction count", 9510008Snilay@cs.wisc.edu max_insts_all_threads, *counter); 9610008Snilay@cs.wisc.edu } 9710008Snilay@cs.wisc.edu 9810008Snilay@cs.wisc.edu // allocate per-thread load-based event queues 9910008Snilay@cs.wisc.edu comLoadEventQueue = new (EventQueue *)[number_of_threads]; 10010008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 10110008Snilay@cs.wisc.edu comLoadEventQueue[i] = new EventQueue("load-based event queue"); 10210008Snilay@cs.wisc.edu 10310008Snilay@cs.wisc.edu // 10410008Snilay@cs.wisc.edu // set up instruction-count-based termination events, if any 10510300Scastilloe@unican.es // 10610008Snilay@cs.wisc.edu if (max_loads_any_thread != 0) 10710008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 10810008Snilay@cs.wisc.edu new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread, 10910300Scastilloe@unican.es "a thread reached the max load count"); 11010008Snilay@cs.wisc.edu 11110008Snilay@cs.wisc.edu if (max_loads_all_threads != 0) { 11210008Snilay@cs.wisc.edu // allocate & initialize shared downcounter: each event will 11310008Snilay@cs.wisc.edu // decrement this when triggered; simulation will terminate 11410008Snilay@cs.wisc.edu // when counter reaches 0 11510008Snilay@cs.wisc.edu int *counter = new int; 11610008Snilay@cs.wisc.edu *counter = number_of_threads; 11710008Snilay@cs.wisc.edu for (int i = 0; i < number_of_threads; ++i) 11810008Snilay@cs.wisc.edu new CountedExitEvent(comLoadEventQueue[i], 11910008Snilay@cs.wisc.edu "all threads reached the max load count", 12010008Snilay@cs.wisc.edu max_loads_all_threads, *counter); 12110008Snilay@cs.wisc.edu } 12210008Snilay@cs.wisc.edu 12310008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 12410008Snilay@cs.wisc.edu memset(interrupts, 0, sizeof(interrupts)); 12510008Snilay@cs.wisc.edu intstatus = 0; 12610008Snilay@cs.wisc.edu#endif 12710008Snilay@cs.wisc.edu} 12810008Snilay@cs.wisc.edu 12910008Snilay@cs.wisc.edu 13010008Snilay@cs.wisc.eduvoid 13110008Snilay@cs.wisc.eduBaseCPU::regStats() 13210008Snilay@cs.wisc.edu{ 13310008Snilay@cs.wisc.edu using namespace Statistics; 13410008Snilay@cs.wisc.edu 13510008Snilay@cs.wisc.edu numCycles 13610008Snilay@cs.wisc.edu .name(name() + ".numCycles") 13710008Snilay@cs.wisc.edu .desc("number of cpu cycles simulated") 13810008Snilay@cs.wisc.edu ; 13910008Snilay@cs.wisc.edu 14010008Snilay@cs.wisc.edu int size = execContexts.size(); 14110008Snilay@cs.wisc.edu if (size > 1) { 14210008Snilay@cs.wisc.edu for (int i = 0; i < size; ++i) { 14310008Snilay@cs.wisc.edu stringstream namestr; 14410008Snilay@cs.wisc.edu ccprintf(namestr, "%s.ctx%d", name(), i); 14510008Snilay@cs.wisc.edu execContexts[i]->regStats(namestr.str()); 14610008Snilay@cs.wisc.edu } 14710008Snilay@cs.wisc.edu } else if (size == 1) 14810008Snilay@cs.wisc.edu execContexts[0]->regStats(name()); 14910008Snilay@cs.wisc.edu} 15010008Snilay@cs.wisc.edu 15110008Snilay@cs.wisc.edu 15210008Snilay@cs.wisc.eduvoid 15310008Snilay@cs.wisc.eduBaseCPU::registerExecContexts() 15410008Snilay@cs.wisc.edu{ 15510008Snilay@cs.wisc.edu for (int i = 0; i < execContexts.size(); ++i) { 15610008Snilay@cs.wisc.edu ExecContext *xc = execContexts[i]; 15710008Snilay@cs.wisc.edu int cpu_id; 15810008Snilay@cs.wisc.edu 15910008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 16010008Snilay@cs.wisc.edu cpu_id = system->registerExecContext(xc); 16110008Snilay@cs.wisc.edu#else 16210008Snilay@cs.wisc.edu cpu_id = xc->process->registerExecContext(xc); 16310008Snilay@cs.wisc.edu#endif 16410008Snilay@cs.wisc.edu 16510008Snilay@cs.wisc.edu xc->cpu_id = cpu_id; 16610008Snilay@cs.wisc.edu } 16710008Snilay@cs.wisc.edu} 16810008Snilay@cs.wisc.edu 16910008Snilay@cs.wisc.edu 17010008Snilay@cs.wisc.eduvoid 17110008Snilay@cs.wisc.eduBaseCPU::switchOut() 17210008Snilay@cs.wisc.edu{ 17310008Snilay@cs.wisc.edu // default: do nothing 17410008Snilay@cs.wisc.edu} 17510008Snilay@cs.wisc.edu 17610008Snilay@cs.wisc.eduvoid 17710008Snilay@cs.wisc.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU) 17810008Snilay@cs.wisc.edu{ 17910008Snilay@cs.wisc.edu assert(execContexts.size() == oldCPU->execContexts.size()); 18010008Snilay@cs.wisc.edu 18110008Snilay@cs.wisc.edu for (int i = 0; i < execContexts.size(); ++i) { 18210008Snilay@cs.wisc.edu ExecContext *newXC = execContexts[i]; 18310008Snilay@cs.wisc.edu ExecContext *oldXC = oldCPU->execContexts[i]; 18410008Snilay@cs.wisc.edu 18510008Snilay@cs.wisc.edu newXC->takeOverFrom(oldXC); 18610008Snilay@cs.wisc.edu assert(newXC->cpu_id == oldXC->cpu_id); 18710008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 18810008Snilay@cs.wisc.edu system->replaceExecContext(newXC->cpu_id, newXC); 18910008Snilay@cs.wisc.edu#else 19010008Snilay@cs.wisc.edu assert(newXC->process == oldXC->process); 19110008Snilay@cs.wisc.edu newXC->process->replaceExecContext(newXC->cpu_id, newXC); 19210008Snilay@cs.wisc.edu#endif 19310008Snilay@cs.wisc.edu } 19410008Snilay@cs.wisc.edu 19510008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 19610008Snilay@cs.wisc.edu for (int i = 0; i < NumInterruptLevels; ++i) 19710008Snilay@cs.wisc.edu interrupts[i] = oldCPU->interrupts[i]; 19810008Snilay@cs.wisc.edu intstatus = oldCPU->intstatus; 19910008Snilay@cs.wisc.edu#endif 20010008Snilay@cs.wisc.edu} 20110008Snilay@cs.wisc.edu 20210008Snilay@cs.wisc.edu 20310008Snilay@cs.wisc.edu#ifdef FULL_SYSTEM 20410008Snilay@cs.wisc.eduvoid 20510008Snilay@cs.wisc.eduBaseCPU::post_interrupt(int int_num, int index) 20610008Snilay@cs.wisc.edu{ 20710008Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); 20810008Snilay@cs.wisc.edu 20910008Snilay@cs.wisc.edu if (int_num < 0 || int_num >= NumInterruptLevels) 210 panic("int_num out of bounds\n"); 211 212 if (index < 0 || index >= sizeof(uint8_t) * 8) 213 panic("int_num out of bounds\n"); 214 215 AlphaISA::check_interrupts = 1; 216 interrupts[int_num] |= 1 << index; 217 intstatus |= (ULL(1) << int_num); 218} 219 220void 221BaseCPU::clear_interrupt(int int_num, int index) 222{ 223 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); 224 225 if (int_num < 0 || int_num >= NumInterruptLevels) 226 panic("int_num out of bounds\n"); 227 228 if (index < 0 || index >= sizeof(uint8_t) * 8) 229 panic("int_num out of bounds\n"); 230 231 interrupts[int_num] &= ~(1 << index); 232 if (interrupts[int_num] == 0) 233 intstatus &= ~(ULL(1) << int_num); 234} 235 236void 237BaseCPU::clear_interrupts() 238{ 239 DPRINTF(Interrupt, "Interrupts all cleared\n"); 240 241 memset(interrupts, 0, sizeof(interrupts)); 242 intstatus = 0; 243} 244 245#endif // FULL_SYSTEM 246 247DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) 248