base.cc revision 1133
16145SN/A/*
28683SN/A * Copyright (c) 2002-2004 The Regents of The University of Michigan
310973Sdavid.hashe@amd.com * All rights reserved.
46145SN/A *
56145SN/A * Redistribution and use in source and binary forms, with or without
66145SN/A * modification, are permitted provided that the following conditions are
76145SN/A * met: redistributions of source code must retain the above copyright
86145SN/A * notice, this list of conditions and the following disclaimer;
96145SN/A * redistributions in binary form must reproduce the above copyright
106145SN/A * notice, this list of conditions and the following disclaimer in the
116145SN/A * documentation and/or other materials provided with the distribution;
126145SN/A * neither the name of the copyright holders nor the names of its
136145SN/A * contributors may be used to endorse or promote products derived from
146145SN/A * this software without specific prior written permission.
156145SN/A *
166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276145SN/A */
286145SN/A
296145SN/A#include <string>
3010441Snilay@cs.wisc.edu#include <sstream>
3110441Snilay@cs.wisc.edu#include <iostream>
326145SN/A
337055SN/A#include "cpu/base_cpu.hh"
346145SN/A#include "base/cprintf.hh"
356145SN/A#include "cpu/exec_context.hh"
367039SN/A#include "base/misc.hh"
379104SN/A#include "sim/param.hh"
3810301Snilay@cs.wisc.edu#include "sim/sim_events.hh"
399105SN/A
408174SN/Ausing namespace std;
417039SN/A
427039SN/Avector<BaseCPU *> BaseCPU::cpuList;
437039SN/A
4410970Sdavid.hashe@amd.com// This variable reflects the max number of threads in any CPU.  Be
4510301Snilay@cs.wisc.edu// careful to only use it once all the CPUs that you care about have
4610301Snilay@cs.wisc.edu// been initialized
477039SN/Aint maxThreadsPerCPU = 1;
487039SN/A
496145SN/A#ifdef FULL_SYSTEM
507039SN/ABaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg,
517039SN/A                 Counter max_insts_any_thread,
527039SN/A                 Counter max_insts_all_threads,
536876SN/A                 Counter max_loads_any_thread,
547039SN/A                 Counter max_loads_all_threads,
557039SN/A                 System *_system, Tick freq)
566145SN/A    : SimObject(_name), frequency(freq), checkInterrupts(true),
577039SN/A      deferRegistration(_def_reg), number_of_threads(_number_of_threads),
586145SN/A      system(_system)
597039SN/A#else
607039SN/ABaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg,
618165SN/A                 Counter max_insts_any_thread,
627039SN/A                 Counter max_insts_all_threads,
636145SN/A                 Counter max_loads_any_thread,
647039SN/A                 Counter max_loads_all_threads)
658165SN/A    : SimObject(_name), deferRegistration(_def_reg),
667039SN/A      number_of_threads(_number_of_threads)
676145SN/A#endif
687039SN/A{
697039SN/A    // add self to global list of CPUs
706145SN/A    cpuList.push_back(this);
717039SN/A
727039SN/A    if (number_of_threads > maxThreadsPerCPU)
737039SN/A        maxThreadsPerCPU = number_of_threads;
747039SN/A
756145SN/A    // allocate per-thread instruction-based event queues
767039SN/A    comInstEventQueue = new (EventQueue *)[number_of_threads];
7710974Sdavid.hashe@amd.com    for (int i = 0; i < number_of_threads; ++i)
7810974Sdavid.hashe@amd.com        comInstEventQueue[i] = new EventQueue("instruction-based event queue");
7910974Sdavid.hashe@amd.com
8010974Sdavid.hashe@amd.com    //
8110974Sdavid.hashe@amd.com    // set up instruction-count-based termination events, if any
8210974Sdavid.hashe@amd.com    //
8310974Sdavid.hashe@amd.com    if (max_insts_any_thread != 0)
848193SN/A        for (int i = 0; i < number_of_threads; ++i)
858193SN/A            new SimExitEvent(comInstEventQueue[i], max_insts_any_thread,
8610974Sdavid.hashe@amd.com                "a thread reached the max instruction count");
878193SN/A
886145SN/A    if (max_insts_all_threads != 0) {
897039SN/A        // allocate & initialize shared downcounter: each event will
907039SN/A        // decrement this when triggered; simulation will terminate
916145SN/A        // when counter reaches 0
927039SN/A        int *counter = new int;
937039SN/A        *counter = number_of_threads;
946145SN/A        for (int i = 0; i < number_of_threads; ++i)
957039SN/A            new CountedExitEvent(comInstEventQueue[i],
967839SN/A                "all threads reached the max instruction count",
977839SN/A                max_insts_all_threads, *counter);
986145SN/A    }
999499SN/A
10010969Sdavid.hashe@amd.com    // allocate per-thread load-based event queues
10110969Sdavid.hashe@amd.com    comLoadEventQueue = new (EventQueue *)[number_of_threads];
10210969Sdavid.hashe@amd.com    for (int i = 0; i < number_of_threads; ++i)
1036285SN/A        comLoadEventQueue[i] = new EventQueue("load-based event queue");
1047039SN/A
1058683SN/A    //
1066145SN/A    // set up instruction-count-based termination events, if any
1077039SN/A    //
1087039SN/A    if (max_loads_any_thread != 0)
1096145SN/A        for (int i = 0; i < number_of_threads; ++i)
1107039SN/A            new SimExitEvent(comLoadEventQueue[i], max_loads_any_thread,
1117039SN/A                "a thread reached the max load count");
1127039SN/A
1139692SN/A    if (max_loads_all_threads != 0) {
1147039SN/A        // allocate & initialize shared downcounter: each event will
1157055SN/A        // decrement this when triggered; simulation will terminate
1167055SN/A        // when counter reaches 0
1176145SN/A        int *counter = new int;
1189692SN/A        *counter = number_of_threads;
1199692SN/A        for (int i = 0; i < number_of_threads; ++i)
1209692SN/A            new CountedExitEvent(comLoadEventQueue[i],
1216374SN/A                "all threads reached the max load count",
1229692SN/A                max_loads_all_threads, *counter);
1239692SN/A    }
1249692SN/A
1259692SN/A#ifdef FULL_SYSTEM
1269692SN/A    memset(interrupts, 0, sizeof(interrupts));
1279692SN/A    intstatus = 0;
1289692SN/A#endif
1299692SN/A}
1309692SN/A
1319692SN/Avoid
1329104SN/ABaseCPU::init()
1339104SN/A{
1349104SN/A    if (!deferRegistration)
1359104SN/A        registerExecContexts();
1369104SN/A}
1379104SN/A
1389105SN/Avoid
1399105SN/ABaseCPU::regStats()
1409692SN/A{
14110973Sdavid.hashe@amd.com    using namespace Stats;
14210973Sdavid.hashe@amd.com
14310973Sdavid.hashe@amd.com    numCycles
14410973Sdavid.hashe@amd.com        .name(name() + ".numCycles")
1457039SN/A        .desc("number of cpu cycles simulated")
1467039SN/A        ;
14710314Snilay@cs.wisc.edu
1486145SN/A    int size = execContexts.size();
1497039SN/A    if (size > 1) {
1507039SN/A        for (int i = 0; i < size; ++i) {
15110314Snilay@cs.wisc.edu            stringstream namestr;
15210314Snilay@cs.wisc.edu            ccprintf(namestr, "%s.ctx%d", name(), i);
1537039SN/A            execContexts[i]->regStats(namestr.str());
1546145SN/A        }
1557039SN/A    } else if (size == 1)
1567039SN/A        execContexts[0]->regStats(name());
1577039SN/A}
1586145SN/A
1597039SN/A
1609499SN/Avoid
1616145SN/ABaseCPU::registerExecContexts()
1627039SN/A{
1637039SN/A    for (int i = 0; i < execContexts.size(); ++i) {
1646285SN/A        ExecContext *xc = execContexts[i];
1657039SN/A        int cpu_id;
1667039SN/A
1677039SN/A#ifdef FULL_SYSTEM
1687454SN/A        cpu_id = system->registerExecContext(xc);
1696145SN/A#else
1707039SN/A        cpu_id = xc->process->registerExecContext(xc);
1716145SN/A#endif
1729105SN/A
1739105SN/A        xc->cpu_id = cpu_id;
1749105SN/A    }
1757039SN/A}
1767039SN/A
1777039SN/A
1787039SN/Avoid
1797564SN/ABaseCPU::switchOut()
1809105SN/A{
1816145SN/A    // default: do nothing
1826145SN/A}
1839554SN/A
1849554SN/Avoid
18510441Snilay@cs.wisc.eduBaseCPU::takeOverFrom(BaseCPU *oldCPU)
186{
187    assert(execContexts.size() == oldCPU->execContexts.size());
188
189    for (int i = 0; i < execContexts.size(); ++i) {
190        ExecContext *newXC = execContexts[i];
191        ExecContext *oldXC = oldCPU->execContexts[i];
192
193        newXC->takeOverFrom(oldXC);
194        assert(newXC->cpu_id == oldXC->cpu_id);
195#ifdef FULL_SYSTEM
196        system->replaceExecContext(newXC, newXC->cpu_id);
197#else
198        assert(newXC->process == oldXC->process);
199        newXC->process->replaceExecContext(newXC, newXC->cpu_id);
200#endif
201    }
202
203#ifdef FULL_SYSTEM
204    for (int i = 0; i < NumInterruptLevels; ++i)
205        interrupts[i] = oldCPU->interrupts[i];
206    intstatus = oldCPU->intstatus;
207#endif
208}
209
210
211#ifdef FULL_SYSTEM
212void
213BaseCPU::post_interrupt(int int_num, int index)
214{
215    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
216
217    if (int_num < 0 || int_num >= NumInterruptLevels)
218        panic("int_num out of bounds\n");
219
220    if (index < 0 || index >= sizeof(uint64_t) * 8)
221        panic("int_num out of bounds\n");
222
223    checkInterrupts = true;
224    interrupts[int_num] |= 1 << index;
225    intstatus |= (ULL(1) << int_num);
226}
227
228void
229BaseCPU::clear_interrupt(int int_num, int index)
230{
231    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
232
233    if (int_num < 0 || int_num >= NumInterruptLevels)
234        panic("int_num out of bounds\n");
235
236    if (index < 0 || index >= sizeof(uint64_t) * 8)
237        panic("int_num out of bounds\n");
238
239    interrupts[int_num] &= ~(1 << index);
240    if (interrupts[int_num] == 0)
241        intstatus &= ~(ULL(1) << int_num);
242}
243
244void
245BaseCPU::clear_interrupts()
246{
247    DPRINTF(Interrupt, "Interrupts all cleared\n");
248
249    memset(interrupts, 0, sizeof(interrupts));
250    intstatus = 0;
251}
252
253
254void
255BaseCPU::serialize(std::ostream &os)
256{
257    SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
258    SERIALIZE_SCALAR(intstatus);
259}
260
261void
262BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
263{
264    UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
265    UNSERIALIZE_SCALAR(intstatus);
266}
267
268#endif // FULL_SYSTEM
269
270DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
271