cpu.cc revision 10407
12330SN/A/*
22330SN/A * Copyright (c) 2012-2014 ARM Limited
32330SN/A * All rights reserved
42330SN/A *
52330SN/A * The license below extends only to copyright in the software and shall
62330SN/A * not be construed as granting a license to any other intellectual
72330SN/A * property including but not limited to intellectual property relating
82330SN/A * to a hardware implementation of the functionality of the software
92330SN/A * licensed hereunder.  You may use the software subject to the license
102330SN/A * terms below provided that you ensure that this notice is replicated
112330SN/A * unmodified and in its entirety in all distributions of the software,
122330SN/A * modified or unmodified, in source code or in binary form.
132330SN/A *
142330SN/A * Redistribution and use in source and binary forms, with or without
152330SN/A * modification, are permitted provided that the following conditions are
162330SN/A * met: redistributions of source code must retain the above copyright
172330SN/A * notice, this list of conditions and the following disclaimer;
182330SN/A * redistributions in binary form must reproduce the above copyright
192330SN/A * notice, this list of conditions and the following disclaimer in the
202330SN/A * documentation and/or other materials provided with the distribution;
212330SN/A * neither the name of the copyright holders nor the names of its
222330SN/A * contributors may be used to endorse or promote products derived from
232330SN/A * this software without specific prior written permission.
242330SN/A *
252330SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262330SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292330SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342980Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352362SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362680Sktlim@umich.edu *
372292SN/A * Authors: Andrew Bardsley
382678Sktlim@umich.edu */
392683Sktlim@umich.edu
402683Sktlim@umich.edu#include "arch/utility.hh"
412678Sktlim@umich.edu#include "cpu/minor/cpu.hh"
422678Sktlim@umich.edu#include "cpu/minor/dyn_inst.hh"
432292SN/A#include "cpu/minor/fetch1.hh"
442292SN/A#include "cpu/minor/pipeline.hh"
452292SN/A#include "debug/Drain.hh"
462292SN/A#include "debug/MinorCPU.hh"
472330SN/A#include "debug/Quiesce.hh"
482330SN/A
492330SN/AMinorCPU::MinorCPU(MinorCPUParams *params) :
502292SN/A    BaseCPU(params),
512292SN/A    drainManager(NULL)
523402Sktlim@umich.edu{
532862Sktlim@umich.edu    /* This is only written for one thread at the moment */
543402Sktlim@umich.edu    Minor::MinorThread *thread;
552862Sktlim@umich.edu
562330SN/A    if (FullSystem) {
572330SN/A        thread = new Minor::MinorThread(this, 0, params->system, params->itb,
582330SN/A            params->dtb, params->isa[0]);
592330SN/A    } else {
602330SN/A        /* thread_id 0 */
612330SN/A        thread = new Minor::MinorThread(this, 0, params->system,
622292SN/A            params->workload[0], params->itb, params->dtb, params->isa[0]);
632683Sktlim@umich.edu    }
642683Sktlim@umich.edu
652292SN/A    threads.push_back(thread);
663402Sktlim@umich.edu
672292SN/A    thread->setStatus(ThreadContext::Halted);
683402Sktlim@umich.edu
693402Sktlim@umich.edu    ThreadContext *tc = thread->getTC();
702292SN/A
712683Sktlim@umich.edu    if (params->checker) {
722862Sktlim@umich.edu        fatal("The Minor model doesn't support checking (yet)\n");
732862Sktlim@umich.edu    }
742862Sktlim@umich.edu
752862Sktlim@umich.edu    threadContexts.push_back(tc);
762683Sktlim@umich.edu
772683Sktlim@umich.edu    Minor::MinorDynInst::init();
782683Sktlim@umich.edu
792683Sktlim@umich.edu    pipeline = new Minor::Pipeline(*this, *params);
802683Sktlim@umich.edu    activityRecorder = pipeline->getActivityRecorder();
812683Sktlim@umich.edu}
822683Sktlim@umich.edu
832683Sktlim@umich.eduMinorCPU::~MinorCPU()
842683Sktlim@umich.edu{
852683Sktlim@umich.edu    delete pipeline;
862683Sktlim@umich.edu
872683Sktlim@umich.edu    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
882683Sktlim@umich.edu        delete threads[thread_id];
892683Sktlim@umich.edu    }
902683Sktlim@umich.edu}
912683Sktlim@umich.edu
922683Sktlim@umich.eduvoid
932683Sktlim@umich.eduMinorCPU::init()
942683Sktlim@umich.edu{
952683Sktlim@umich.edu    BaseCPU::init();
962683Sktlim@umich.edu
972683Sktlim@umich.edu    if (!params()->switched_out &&
982683Sktlim@umich.edu        system->getMemoryMode() != Enums::timing)
992690Sktlim@umich.edu    {
1002690Sktlim@umich.edu        fatal("The Minor CPU requires the memory system to be in "
1012683Sktlim@umich.edu            "'timing' mode.\n");
1022683Sktlim@umich.edu    }
1032690Sktlim@umich.edu
1042690Sktlim@umich.edu    /* Initialise the ThreadContext's memory proxies */
1052683Sktlim@umich.edu    for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) {
1062683Sktlim@umich.edu        ThreadContext *tc = getContext(thread_id);
1072683Sktlim@umich.edu
1082683Sktlim@umich.edu        tc->initMemProxies(tc);
1093402Sktlim@umich.edu    }
1102683Sktlim@umich.edu
1112683Sktlim@umich.edu    /* Initialise CPUs (== threads in the ISA) */
1122683Sktlim@umich.edu    if (FullSystem && !params()->switched_out) {
1132683Sktlim@umich.edu        for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++)
1142683Sktlim@umich.edu        {
1152678Sktlim@umich.edu            ThreadContext *tc = getContext(thread_id);
1162292SN/A
1172683Sktlim@umich.edu            /* Initialize CPU, including PC */
1182683Sktlim@umich.edu            TheISA::initCPU(tc, cpuId());
1192292SN/A        }
1202683Sktlim@umich.edu    }
1212683Sktlim@umich.edu}
1222683Sktlim@umich.edu
1232683Sktlim@umich.edu/** Stats interface from SimObject (by way of BaseCPU) */
1242683Sktlim@umich.eduvoid
1252683Sktlim@umich.eduMinorCPU::regStats()
1262683Sktlim@umich.edu{
1272683Sktlim@umich.edu    BaseCPU::regStats();
1282683Sktlim@umich.edu    stats.regStats(name(), *this);
1292683Sktlim@umich.edu    pipeline->regStats();
1302683Sktlim@umich.edu}
1312683Sktlim@umich.edu
1322683Sktlim@umich.eduvoid
1332683Sktlim@umich.eduMinorCPU::serializeThread(std::ostream &os, ThreadID thread_id)
1342683Sktlim@umich.edu{
1352683Sktlim@umich.edu    threads[thread_id]->serialize(os);
1362683Sktlim@umich.edu}
1372683Sktlim@umich.edu
1382683Sktlim@umich.eduvoid
1392683Sktlim@umich.eduMinorCPU::unserializeThread(Checkpoint *cp, const std::string &section,
1402683Sktlim@umich.edu    ThreadID thread_id)
1412683Sktlim@umich.edu{
1422683Sktlim@umich.edu    if (thread_id != 0)
1432683Sktlim@umich.edu        fatal("Trying to load more than one thread into a MinorCPU\n");
1442683Sktlim@umich.edu
1452683Sktlim@umich.edu    threads[thread_id]->unserialize(cp, section);
1462683Sktlim@umich.edu}
1472683Sktlim@umich.edu
1482683Sktlim@umich.eduvoid
1492683Sktlim@umich.eduMinorCPU::serialize(std::ostream &os)
1502683Sktlim@umich.edu{
1512683Sktlim@umich.edu    pipeline->serialize(os);
1522683Sktlim@umich.edu    BaseCPU::serialize(os);
1532683Sktlim@umich.edu}
1542683Sktlim@umich.edu
1552683Sktlim@umich.eduvoid
1562683Sktlim@umich.eduMinorCPU::unserialize(Checkpoint *cp, const std::string &section)
1573402Sktlim@umich.edu{
1583402Sktlim@umich.edu    pipeline->unserialize(cp, section);
1593402Sktlim@umich.edu    BaseCPU::unserialize(cp, section);
1602683Sktlim@umich.edu}
1612683Sktlim@umich.edu
1622292SN/AAddr
1632292SN/AMinorCPU::dbg_vtophys(Addr addr)
1642292SN/A{
1652292SN/A    /* Note that this gives you the translation for thread 0 */
1662292SN/A    panic("No implementation for vtophy\n");
1672690Sktlim@umich.edu
1682683Sktlim@umich.edu    return 0;
1692683Sktlim@umich.edu}
1702292SN/A
1712683Sktlim@umich.eduvoid
1722683Sktlim@umich.eduMinorCPU::wakeup()
1732292SN/A{
1742292SN/A    DPRINTF(Drain, "MinorCPU wakeup\n");
1752683Sktlim@umich.edu
1762292SN/A    for (auto i = threads.begin(); i != threads.end(); i ++) {
1772292SN/A        if ((*i)->status() == ThreadContext::Suspended)
1782292SN/A            (*i)->activate();
1792292SN/A    }
1802292SN/A
1812330SN/A    DPRINTF(Drain,"Suspended Processor awoke\n");
1822683Sktlim@umich.edu}
1832683Sktlim@umich.edu
1842683Sktlim@umich.eduvoid
1852683Sktlim@umich.eduMinorCPU::startup()
1862683Sktlim@umich.edu{
1872683Sktlim@umich.edu    DPRINTF(MinorCPU, "MinorCPU startup\n");
1882683Sktlim@umich.edu
1892683Sktlim@umich.edu    BaseCPU::startup();
1902292SN/A
1912678Sktlim@umich.edu    for (auto i = threads.begin(); i != threads.end(); i ++)
1922678Sktlim@umich.edu        (*i)->startup();
1932292SN/A
1942292SN/A    /* CPU state setup, activate initial context */
1952292SN/A    activateContext(0);
1962292SN/A}
1972292SN/A
1982292SN/Aunsigned int
1992330SN/AMinorCPU::drain(DrainManager *drain_manager)
2002330SN/A{
2012330SN/A    DPRINTF(Drain, "MinorCPU drain\n");
2022683Sktlim@umich.edu
2032683Sktlim@umich.edu    drainManager = drain_manager;
2042683Sktlim@umich.edu
2052683Sktlim@umich.edu    /* Need to suspend all threads and wait for Execute to idle.
2062292SN/A     * Tell Fetch1 not to fetch */
2073276Sgblack@eecs.umich.edu    unsigned int ret = pipeline->drain(drain_manager);
2083276Sgblack@eecs.umich.edu
2093276Sgblack@eecs.umich.edu    if (ret == 0)
2103276Sgblack@eecs.umich.edu        DPRINTF(Drain, "MinorCPU drained\n");
2113276Sgblack@eecs.umich.edu    else
2123276Sgblack@eecs.umich.edu        DPRINTF(Drain, "MinorCPU not finished draining\n");
2133276Sgblack@eecs.umich.edu
2143276Sgblack@eecs.umich.edu    return ret;
2153276Sgblack@eecs.umich.edu}
2163276Sgblack@eecs.umich.edu
2172690Sktlim@umich.eduvoid
2182292SN/AMinorCPU::signalDrainDone()
2192292SN/A{
2202292SN/A    DPRINTF(Drain, "MinorCPU drain done\n");
2212292SN/A    setDrainState(Drainable::Drained);
2222292SN/A    drainManager->signalDrainDone();
2232292SN/A    drainManager = NULL;
2242292SN/A}
2252292SN/A
2262292SN/Avoid
2272292SN/AMinorCPU::drainResume()
2282292SN/A{
2292292SN/A    assert(getDrainState() == Drainable::Drained ||
2302292SN/A        getDrainState() == Drainable::Running);
2312292SN/A
2322292SN/A    if (switchedOut()) {
2332292SN/A        DPRINTF(Drain, "drainResume while switched out.  Ignoring\n");
2342292SN/A        return;
2352292SN/A    }
2362292SN/A
2372292SN/A    DPRINTF(Drain, "MinorCPU drainResume\n");
2382292SN/A
2392292SN/A    if (!system->isTimingMode()) {
2402292SN/A        fatal("The Minor CPU requires the memory system to be in "
2412292SN/A            "'timing' mode.\n");
2422292SN/A    }
243
244    wakeup();
245    pipeline->drainResume();
246
247    setDrainState(Drainable::Running);
248}
249
250void
251MinorCPU::memWriteback()
252{
253    DPRINTF(Drain, "MinorCPU memWriteback\n");
254}
255
256void
257MinorCPU::switchOut()
258{
259    DPRINTF(MinorCPU, "MinorCPU switchOut\n");
260
261    assert(!switchedOut());
262    BaseCPU::switchOut();
263
264    /* Check that the CPU is drained? */
265    activityRecorder->reset();
266}
267
268void
269MinorCPU::takeOverFrom(BaseCPU *old_cpu)
270{
271    DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n");
272
273    BaseCPU::takeOverFrom(old_cpu);
274
275    /* Don't think I need to do anything here */
276}
277
278void
279MinorCPU::activateContext(ThreadID thread_id)
280{
281    DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id);
282
283    /* Do some cycle accounting.  lastStopped is reset to stop the
284     *  wakeup call on the pipeline from adding the quiesce period
285     *  to BaseCPU::numCycles */
286    stats.quiesceCycles += pipeline->cyclesSinceLastStopped();
287    pipeline->resetLastStopped();
288
289    /* Wake up the thread, wakeup the pipeline tick */
290    threads[thread_id]->activate();
291    wakeupOnEvent(Minor::Pipeline::CPUStageId);
292    pipeline->wakeupFetch();
293}
294
295void
296MinorCPU::suspendContext(ThreadID thread_id)
297{
298    DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
299
300    threads[thread_id]->suspend();
301}
302
303void
304MinorCPU::wakeupOnEvent(unsigned int stage_id)
305{
306    DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id);
307
308    /* Mark that some activity has taken place and start the pipeline */
309    activityRecorder->activateStage(stage_id);
310    pipeline->start();
311}
312
313MinorCPU *
314MinorCPUParams::create()
315{
316    numThreads = 1;
317    if (!FullSystem && workload.size() != 1)
318        panic("only one workload allowed");
319    return new MinorCPU(this);
320}
321
322MasterPort &MinorCPU::getInstPort()
323{
324    return pipeline->getInstPort();
325}
326
327MasterPort &MinorCPU::getDataPort()
328{
329    return pipeline->getDataPort();
330}
331
332Counter
333MinorCPU::totalInsts() const
334{
335    Counter ret = 0;
336
337    for (auto i = threads.begin(); i != threads.end(); i ++)
338        ret += (*i)->numInst;
339
340    return ret;
341}
342
343Counter
344MinorCPU::totalOps() const
345{
346    Counter ret = 0;
347
348    for (auto i = threads.begin(); i != threads.end(); i ++)
349        ret += (*i)->numOp;
350
351    return ret;
352}
353