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