base.cc revision 1355
17949SAli.Saidi@ARM.com/* 27949SAli.Saidi@ARM.com * Copyright (c) 2002-2004 The Regents of The University of Michigan 37949SAli.Saidi@ARM.com * All rights reserved. 47949SAli.Saidi@ARM.com * 57949SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67949SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77949SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97949SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117949SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127949SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137949SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 147949SAli.Saidi@ARM.com * this software without specific prior written permission. 157949SAli.Saidi@ARM.com * 167949SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177949SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187949SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197949SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207949SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217949SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227949SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237949SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247949SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257949SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267949SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277949SAli.Saidi@ARM.com */ 287949SAli.Saidi@ARM.com 297949SAli.Saidi@ARM.com#include <cmath> 307949SAli.Saidi@ARM.com#include <cstdio> 317949SAli.Saidi@ARM.com#include <cstdlib> 327949SAli.Saidi@ARM.com#include <iostream> 337949SAli.Saidi@ARM.com#include <iomanip> 347949SAli.Saidi@ARM.com#include <list> 357949SAli.Saidi@ARM.com#include <sstream> 367949SAli.Saidi@ARM.com#include <string> 377949SAli.Saidi@ARM.com 387949SAli.Saidi@ARM.com#include "base/cprintf.hh" 397949SAli.Saidi@ARM.com#include "base/inifile.hh" 407949SAli.Saidi@ARM.com#include "base/loader/symtab.hh" 417949SAli.Saidi@ARM.com#include "base/misc.hh" 427949SAli.Saidi@ARM.com#include "base/pollevent.hh" 437949SAli.Saidi@ARM.com#include "base/range.hh" 447949SAli.Saidi@ARM.com#include "base/trace.hh" 457949SAli.Saidi@ARM.com#include "base/stats/events.hh" 467949SAli.Saidi@ARM.com#include "cpu/base_cpu.hh" 477949SAli.Saidi@ARM.com#include "cpu/exec_context.hh" 487949SAli.Saidi@ARM.com#include "cpu/exetrace.hh" 497949SAli.Saidi@ARM.com#include "cpu/full_cpu/smt.hh" 508229Snate@binkert.org#include "cpu/simple_cpu/simple_cpu.hh" 518635Schris.emmons@arm.com#include "cpu/static_inst.hh" 527949SAli.Saidi@ARM.com#include "mem/base_mem.hh" 537949SAli.Saidi@ARM.com#include "mem/mem_interface.hh" 547949SAli.Saidi@ARM.com#include "sim/builder.hh" 557949SAli.Saidi@ARM.com#include "sim/debug.hh" 568229Snate@binkert.org#include "sim/host.hh" 577949SAli.Saidi@ARM.com#include "sim/sim_events.hh" 587949SAli.Saidi@ARM.com#include "sim/sim_object.hh" 598635Schris.emmons@arm.com#include "sim/stats.hh" 607949SAli.Saidi@ARM.com 617949SAli.Saidi@ARM.com#ifdef FULL_SYSTEM 627949SAli.Saidi@ARM.com#include "base/remote_gdb.hh" 637949SAli.Saidi@ARM.com#include "dev/alpha_access.h" 647949SAli.Saidi@ARM.com#include "dev/pciareg.h" 657949SAli.Saidi@ARM.com#include "mem/functional_mem/memory_control.hh" 667949SAli.Saidi@ARM.com#include "mem/functional_mem/physical_memory.hh" 677949SAli.Saidi@ARM.com#include "sim/system.hh" 687949SAli.Saidi@ARM.com#include "targetarch/alpha_memory.hh" 697949SAli.Saidi@ARM.com#include "targetarch/vtophys.hh" 707949SAli.Saidi@ARM.com#else // !FULL_SYSTEM 717949SAli.Saidi@ARM.com#include "eio/eio.hh" 727949SAli.Saidi@ARM.com#include "mem/functional_mem/functional_memory.hh" 737949SAli.Saidi@ARM.com#endif // FULL_SYSTEM 747949SAli.Saidi@ARM.com 757949SAli.Saidi@ARM.comusing namespace std; 767949SAli.Saidi@ARM.com 777949SAli.Saidi@ARM.comtemplate<typename T> 787949SAli.Saidi@ARM.comvoid 797949SAli.Saidi@ARM.comSimpleCPU::trace_data(T data) { 807949SAli.Saidi@ARM.com if (traceData) { 817949SAli.Saidi@ARM.com traceData->setData(data); 827949SAli.Saidi@ARM.com } 837949SAli.Saidi@ARM.com} 847949SAli.Saidi@ARM.com 857949SAli.Saidi@ARM.com 867949SAli.Saidi@ARM.comSimpleCPU::TickEvent::TickEvent(SimpleCPU *c) 877949SAli.Saidi@ARM.com : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), multiplier(1) 887949SAli.Saidi@ARM.com{ 897949SAli.Saidi@ARM.com} 907949SAli.Saidi@ARM.com 917949SAli.Saidi@ARM.comvoid 927949SAli.Saidi@ARM.comSimpleCPU::TickEvent::process() 937949SAli.Saidi@ARM.com{ 947949SAli.Saidi@ARM.com int count = multiplier; 957949SAli.Saidi@ARM.com do { 967949SAli.Saidi@ARM.com cpu->tick(); 977949SAli.Saidi@ARM.com } while (--count > 0 && cpu->status() == Running); 987949SAli.Saidi@ARM.com} 997949SAli.Saidi@ARM.com 1007949SAli.Saidi@ARM.comconst char * 1017949SAli.Saidi@ARM.comSimpleCPU::TickEvent::description() 1027949SAli.Saidi@ARM.com{ 1037949SAli.Saidi@ARM.com return "SimpleCPU tick event"; 1047949SAli.Saidi@ARM.com} 1057949SAli.Saidi@ARM.com 1067949SAli.Saidi@ARM.com 1077949SAli.Saidi@ARM.comSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 1087949SAli.Saidi@ARM.com : Event(&mainEventQueue), 1097949SAli.Saidi@ARM.com cpu(_cpu) 1107949SAli.Saidi@ARM.com{ 1117949SAli.Saidi@ARM.com} 1127949SAli.Saidi@ARM.com 1137949SAli.Saidi@ARM.comvoid SimpleCPU::CacheCompletionEvent::process() 1147949SAli.Saidi@ARM.com{ 1157949SAli.Saidi@ARM.com cpu->processCacheCompletion(); 1167949SAli.Saidi@ARM.com} 1177949SAli.Saidi@ARM.com 1187949SAli.Saidi@ARM.comconst char * 1197949SAli.Saidi@ARM.comSimpleCPU::CacheCompletionEvent::description() 1207949SAli.Saidi@ARM.com{ 1217949SAli.Saidi@ARM.com return "SimpleCPU cache completion event"; 1227949SAli.Saidi@ARM.com} 1237949SAli.Saidi@ARM.com 1247949SAli.Saidi@ARM.com#ifdef FULL_SYSTEM 1257949SAli.Saidi@ARM.comSimpleCPU::SimpleCPU(const string &_name, 1267949SAli.Saidi@ARM.com System *_system, 1277949SAli.Saidi@ARM.com Counter max_insts_any_thread, 1287949SAli.Saidi@ARM.com Counter max_insts_all_threads, 1297949SAli.Saidi@ARM.com Counter max_loads_any_thread, 1307949SAli.Saidi@ARM.com Counter max_loads_all_threads, 1317949SAli.Saidi@ARM.com AlphaITB *itb, AlphaDTB *dtb, 1327949SAli.Saidi@ARM.com FunctionalMemory *mem, 1337949SAli.Saidi@ARM.com MemInterface *icache_interface, 1347949SAli.Saidi@ARM.com MemInterface *dcache_interface, 1357949SAli.Saidi@ARM.com bool _def_reg, Tick freq, 1367949SAli.Saidi@ARM.com bool _function_trace, Tick _function_trace_start) 1377949SAli.Saidi@ARM.com : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, 1387949SAli.Saidi@ARM.com max_insts_any_thread, max_insts_all_threads, 1397949SAli.Saidi@ARM.com max_loads_any_thread, max_loads_all_threads, 1407949SAli.Saidi@ARM.com _system, freq, _function_trace, _function_trace_start), 1417949SAli.Saidi@ARM.com#else 1427949SAli.Saidi@ARM.comSimpleCPU::SimpleCPU(const string &_name, Process *_process, 1437949SAli.Saidi@ARM.com Counter max_insts_any_thread, 1447949SAli.Saidi@ARM.com Counter max_insts_all_threads, 1457949SAli.Saidi@ARM.com Counter max_loads_any_thread, 1467949SAli.Saidi@ARM.com Counter max_loads_all_threads, 1477949SAli.Saidi@ARM.com MemInterface *icache_interface, 1487949SAli.Saidi@ARM.com MemInterface *dcache_interface, 1497949SAli.Saidi@ARM.com bool _def_reg, 1507949SAli.Saidi@ARM.com bool _function_trace, Tick _function_trace_start) 1517949SAli.Saidi@ARM.com : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, 1527949SAli.Saidi@ARM.com max_insts_any_thread, max_insts_all_threads, 1537949SAli.Saidi@ARM.com max_loads_any_thread, max_loads_all_threads, 1547949SAli.Saidi@ARM.com _function_trace, _function_trace_start), 1557949SAli.Saidi@ARM.com#endif 1567949SAli.Saidi@ARM.com tickEvent(this), xc(NULL), cacheCompletionEvent(this) 1577949SAli.Saidi@ARM.com{ 1587949SAli.Saidi@ARM.com _status = Idle; 1597949SAli.Saidi@ARM.com#ifdef FULL_SYSTEM 1607949SAli.Saidi@ARM.com xc = new ExecContext(this, 0, system, itb, dtb, mem); 1617949SAli.Saidi@ARM.com 1627949SAli.Saidi@ARM.com // initialize CPU, including PC 1637949SAli.Saidi@ARM.com TheISA::initCPU(&xc->regs); 1647949SAli.Saidi@ARM.com#else 1657949SAli.Saidi@ARM.com xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); 1667949SAli.Saidi@ARM.com#endif // !FULL_SYSTEM 1677949SAli.Saidi@ARM.com 1687949SAli.Saidi@ARM.com icacheInterface = icache_interface; 1697949SAli.Saidi@ARM.com dcacheInterface = dcache_interface; 1707949SAli.Saidi@ARM.com 1717949SAli.Saidi@ARM.com memReq = new MemReq(); 1727949SAli.Saidi@ARM.com memReq->xc = xc; 1737949SAli.Saidi@ARM.com memReq->asid = 0; 1747949SAli.Saidi@ARM.com memReq->data = new uint8_t[64]; 1757949SAli.Saidi@ARM.com 1767949SAli.Saidi@ARM.com numInst = 0; 1777949SAli.Saidi@ARM.com startNumInst = 0; 1787949SAli.Saidi@ARM.com numLoad = 0; 1797949SAli.Saidi@ARM.com startNumLoad = 0; 1807949SAli.Saidi@ARM.com lastIcacheStall = 0; 1817949SAli.Saidi@ARM.com lastDcacheStall = 0; 1827949SAli.Saidi@ARM.com 1837949SAli.Saidi@ARM.com execContexts.push_back(xc); 1847949SAli.Saidi@ARM.com} 1857949SAli.Saidi@ARM.com 1867949SAli.Saidi@ARM.comSimpleCPU::~SimpleCPU() 1877949SAli.Saidi@ARM.com{ 1887949SAli.Saidi@ARM.com} 1897949SAli.Saidi@ARM.com 1907949SAli.Saidi@ARM.comvoid 1917949SAli.Saidi@ARM.comSimpleCPU::switchOut() 1927949SAli.Saidi@ARM.com{ 1937949SAli.Saidi@ARM.com _status = SwitchedOut; 1947949SAli.Saidi@ARM.com if (tickEvent.scheduled()) 1957949SAli.Saidi@ARM.com tickEvent.squash(); 1967949SAli.Saidi@ARM.com} 1977949SAli.Saidi@ARM.com 1987949SAli.Saidi@ARM.com 1997949SAli.Saidi@ARM.comvoid 2007949SAli.Saidi@ARM.comSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 2017949SAli.Saidi@ARM.com{ 2027949SAli.Saidi@ARM.com BaseCPU::takeOverFrom(oldCPU); 2037949SAli.Saidi@ARM.com 2047949SAli.Saidi@ARM.com assert(!tickEvent.scheduled()); 2057949SAli.Saidi@ARM.com 2067949SAli.Saidi@ARM.com // if any of this CPU's ExecContexts are active, mark the CPU as 2077949SAli.Saidi@ARM.com // running and schedule its tick event. 2087949SAli.Saidi@ARM.com for (int i = 0; i < execContexts.size(); ++i) { 2097949SAli.Saidi@ARM.com ExecContext *xc = execContexts[i]; 2107949SAli.Saidi@ARM.com if (xc->status() == ExecContext::Active && _status != Running) { 2117949SAli.Saidi@ARM.com _status = Running; 2127949SAli.Saidi@ARM.com tickEvent.schedule(curTick); 2137949SAli.Saidi@ARM.com } 2147949SAli.Saidi@ARM.com } 2157949SAli.Saidi@ARM.com 2167949SAli.Saidi@ARM.com oldCPU->switchOut(); 2177949SAli.Saidi@ARM.com} 2187949SAli.Saidi@ARM.com 2197949SAli.Saidi@ARM.com 2207949SAli.Saidi@ARM.comvoid 2217949SAli.Saidi@ARM.comSimpleCPU::activateContext(int thread_num, int delay) 2227949SAli.Saidi@ARM.com{ 2237949SAli.Saidi@ARM.com assert(thread_num == 0); 2247949SAli.Saidi@ARM.com assert(xc); 2257949SAli.Saidi@ARM.com 2267949SAli.Saidi@ARM.com assert(_status == Idle); 2277949SAli.Saidi@ARM.com notIdleFraction++; 2287949SAli.Saidi@ARM.com scheduleTickEvent(delay); 2297949SAli.Saidi@ARM.com _status = Running; 2307949SAli.Saidi@ARM.com} 2317949SAli.Saidi@ARM.com 2327949SAli.Saidi@ARM.com 2337949SAli.Saidi@ARM.comvoid 2347949SAli.Saidi@ARM.comSimpleCPU::suspendContext(int thread_num) 2357949SAli.Saidi@ARM.com{ 2367949SAli.Saidi@ARM.com assert(thread_num == 0); 2377949SAli.Saidi@ARM.com assert(xc); 2387949SAli.Saidi@ARM.com 2397949SAli.Saidi@ARM.com assert(_status == Running); 2407949SAli.Saidi@ARM.com notIdleFraction--; 2417949SAli.Saidi@ARM.com unscheduleTickEvent(); 2427949SAli.Saidi@ARM.com _status = Idle; 2437949SAli.Saidi@ARM.com} 2447949SAli.Saidi@ARM.com 2457949SAli.Saidi@ARM.com 2467949SAli.Saidi@ARM.comvoid 2477949SAli.Saidi@ARM.comSimpleCPU::deallocateContext(int thread_num) 2487949SAli.Saidi@ARM.com{ 2497949SAli.Saidi@ARM.com // for now, these are equivalent 2507949SAli.Saidi@ARM.com suspendContext(thread_num); 2517949SAli.Saidi@ARM.com} 2527949SAli.Saidi@ARM.com 2537949SAli.Saidi@ARM.com 2547949SAli.Saidi@ARM.comvoid 2557949SAli.Saidi@ARM.comSimpleCPU::haltContext(int thread_num) 2567949SAli.Saidi@ARM.com{ 2577949SAli.Saidi@ARM.com // for now, these are equivalent 2587949SAli.Saidi@ARM.com suspendContext(thread_num); 2597949SAli.Saidi@ARM.com} 2607949SAli.Saidi@ARM.com 2617949SAli.Saidi@ARM.com 2627949SAli.Saidi@ARM.comvoid 2637949SAli.Saidi@ARM.comSimpleCPU::regStats() 2647949SAli.Saidi@ARM.com{ 2657949SAli.Saidi@ARM.com using namespace Stats; 2667949SAli.Saidi@ARM.com 2677949SAli.Saidi@ARM.com BaseCPU::regStats(); 2687949SAli.Saidi@ARM.com 2697949SAli.Saidi@ARM.com numInsts 2707949SAli.Saidi@ARM.com .name(name() + ".num_insts") 2717949SAli.Saidi@ARM.com .desc("Number of instructions executed") 2727949SAli.Saidi@ARM.com ; 2737949SAli.Saidi@ARM.com 2747949SAli.Saidi@ARM.com numMemRefs 2757949SAli.Saidi@ARM.com .name(name() + ".num_refs") 2767949SAli.Saidi@ARM.com .desc("Number of memory references") 2777949SAli.Saidi@ARM.com ; 2787949SAli.Saidi@ARM.com 2797949SAli.Saidi@ARM.com notIdleFraction 2807949SAli.Saidi@ARM.com .name(name() + ".not_idle_fraction") 2817949SAli.Saidi@ARM.com .desc("Percentage of non-idle cycles") 2827949SAli.Saidi@ARM.com ; 2837949SAli.Saidi@ARM.com 2847949SAli.Saidi@ARM.com idleFraction 2857949SAli.Saidi@ARM.com .name(name() + ".idle_fraction") 2867949SAli.Saidi@ARM.com .desc("Percentage of idle cycles") 2877949SAli.Saidi@ARM.com ; 2887949SAli.Saidi@ARM.com 2897949SAli.Saidi@ARM.com icacheStallCycles 2907949SAli.Saidi@ARM.com .name(name() + ".icache_stall_cycles") 2917949SAli.Saidi@ARM.com .desc("ICache total stall cycles") 2927949SAli.Saidi@ARM.com .prereq(icacheStallCycles) 2937949SAli.Saidi@ARM.com ; 2947949SAli.Saidi@ARM.com 2957949SAli.Saidi@ARM.com dcacheStallCycles 2967949SAli.Saidi@ARM.com .name(name() + ".dcache_stall_cycles") 2977949SAli.Saidi@ARM.com .desc("DCache total stall cycles") 2987949SAli.Saidi@ARM.com .prereq(dcacheStallCycles) 2997949SAli.Saidi@ARM.com ; 3007949SAli.Saidi@ARM.com 3017949SAli.Saidi@ARM.com idleFraction = constant(1.0) - notIdleFraction; 3027949SAli.Saidi@ARM.com} 3037949SAli.Saidi@ARM.com 3047949SAli.Saidi@ARM.comvoid 3057949SAli.Saidi@ARM.comSimpleCPU::resetStats() 3067949SAli.Saidi@ARM.com{ 3077949SAli.Saidi@ARM.com startNumInst = numInst; 3087949SAli.Saidi@ARM.com notIdleFraction = (_status != Idle); 3097949SAli.Saidi@ARM.com} 3107949SAli.Saidi@ARM.com 3117949SAli.Saidi@ARM.comvoid 3127949SAli.Saidi@ARM.comSimpleCPU::serialize(ostream &os) 3137949SAli.Saidi@ARM.com{ 3147949SAli.Saidi@ARM.com BaseCPU::serialize(os); 3157949SAli.Saidi@ARM.com SERIALIZE_ENUM(_status); 3167949SAli.Saidi@ARM.com SERIALIZE_SCALAR(inst); 3177949SAli.Saidi@ARM.com nameOut(os, csprintf("%s.xc", name())); 3187949SAli.Saidi@ARM.com xc->serialize(os); 3197949SAli.Saidi@ARM.com nameOut(os, csprintf("%s.tickEvent", name())); 3207949SAli.Saidi@ARM.com tickEvent.serialize(os); 3218635Schris.emmons@arm.com nameOut(os, csprintf("%s.cacheCompletionEvent", name())); 3228635Schris.emmons@arm.com cacheCompletionEvent.serialize(os); 3238635Schris.emmons@arm.com} 3248635Schris.emmons@arm.com 3258635Schris.emmons@arm.comvoid 3268635Schris.emmons@arm.comSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 3278635Schris.emmons@arm.com{ 3288635Schris.emmons@arm.com BaseCPU::unserialize(cp, section); 3298635Schris.emmons@arm.com UNSERIALIZE_ENUM(_status); 3308635Schris.emmons@arm.com UNSERIALIZE_SCALAR(inst); 3318635Schris.emmons@arm.com xc->unserialize(cp, csprintf("%s.xc", section)); 3328635Schris.emmons@arm.com tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 3338635Schris.emmons@arm.com cacheCompletionEvent 3348635Schris.emmons@arm.com .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); 3358635Schris.emmons@arm.com} 3367949SAli.Saidi@ARM.com 3378635Schris.emmons@arm.comvoid 3388635Schris.emmons@arm.comchange_thread_state(int thread_number, int activate, int priority) 3398635Schris.emmons@arm.com{ 3407949SAli.Saidi@ARM.com} 3417949SAli.Saidi@ARM.com 3427949SAli.Saidi@ARM.comFault 3437949SAli.Saidi@ARM.comSimpleCPU::copySrcTranslate(Addr src) 3447949SAli.Saidi@ARM.com{ 3457949SAli.Saidi@ARM.com static bool no_warn = true; 3467949SAli.Saidi@ARM.com int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3477949SAli.Saidi@ARM.com // Only support block sizes of 64 atm. 3487949SAli.Saidi@ARM.com assert(blk_size == 64); 3497949SAli.Saidi@ARM.com int offset = src & (blk_size - 1); 3507949SAli.Saidi@ARM.com 3517949SAli.Saidi@ARM.com // Make sure block doesn't span page 3527949SAli.Saidi@ARM.com if (no_warn && 3537949SAli.Saidi@ARM.com (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && 3547949SAli.Saidi@ARM.com (src >> 40) != 0xfffffc) { 3557949SAli.Saidi@ARM.com warn("Copied block source spans pages %x.", src); 3567949SAli.Saidi@ARM.com no_warn = false; 3577949SAli.Saidi@ARM.com } 3587949SAli.Saidi@ARM.com 3597949SAli.Saidi@ARM.com memReq->reset(src & ~(blk_size - 1), blk_size); 3607949SAli.Saidi@ARM.com 3617949SAli.Saidi@ARM.com // translate to physical address 3627949SAli.Saidi@ARM.com Fault fault = xc->translateDataReadReq(memReq); 3637949SAli.Saidi@ARM.com 3647949SAli.Saidi@ARM.com assert(fault != Alignment_Fault); 3657949SAli.Saidi@ARM.com 3667949SAli.Saidi@ARM.com if (fault == No_Fault) { 3677949SAli.Saidi@ARM.com xc->copySrcAddr = src; 3687949SAli.Saidi@ARM.com xc->copySrcPhysAddr = memReq->paddr + offset; 3697949SAli.Saidi@ARM.com } else { 3707949SAli.Saidi@ARM.com xc->copySrcAddr = 0; 3717949SAli.Saidi@ARM.com xc->copySrcPhysAddr = 0; 3727949SAli.Saidi@ARM.com } 3737949SAli.Saidi@ARM.com return fault; 3747949SAli.Saidi@ARM.com} 3757949SAli.Saidi@ARM.com 3767949SAli.Saidi@ARM.comFault 3777949SAli.Saidi@ARM.comSimpleCPU::copy(Addr dest) 3787949SAli.Saidi@ARM.com{ 3797949SAli.Saidi@ARM.com static bool no_warn = true; 3807949SAli.Saidi@ARM.com int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 3817949SAli.Saidi@ARM.com // Only support block sizes of 64 atm. 3827949SAli.Saidi@ARM.com assert(blk_size == 64); 3837949SAli.Saidi@ARM.com uint8_t data[blk_size]; 3847949SAli.Saidi@ARM.com //assert(xc->copySrcAddr); 3857949SAli.Saidi@ARM.com int offset = dest & (blk_size - 1); 3867949SAli.Saidi@ARM.com 3877949SAli.Saidi@ARM.com // Make sure block doesn't span page 3887949SAli.Saidi@ARM.com if (no_warn && 3897949SAli.Saidi@ARM.com (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && 3907949SAli.Saidi@ARM.com (dest >> 40) != 0xfffffc) { 3917949SAli.Saidi@ARM.com no_warn = false; 3927949SAli.Saidi@ARM.com warn("Copied block destination spans pages %x. ", dest); 3937949SAli.Saidi@ARM.com } 3947949SAli.Saidi@ARM.com 3957949SAli.Saidi@ARM.com memReq->reset(dest & ~(blk_size -1), blk_size); 3967949SAli.Saidi@ARM.com // translate to physical address 3977949SAli.Saidi@ARM.com Fault fault = xc->translateDataWriteReq(memReq); 3987949SAli.Saidi@ARM.com 3997949SAli.Saidi@ARM.com assert(fault != Alignment_Fault); 4007949SAli.Saidi@ARM.com 4017949SAli.Saidi@ARM.com if (fault == No_Fault) { 4027949SAli.Saidi@ARM.com Addr dest_addr = memReq->paddr + offset; 4037949SAli.Saidi@ARM.com // Need to read straight from memory since we have more than 8 bytes. 4047949SAli.Saidi@ARM.com memReq->paddr = xc->copySrcPhysAddr; 4057949SAli.Saidi@ARM.com xc->mem->read(memReq, data); 4067949SAli.Saidi@ARM.com memReq->paddr = dest_addr; 4077949SAli.Saidi@ARM.com xc->mem->write(memReq, data); 4087949SAli.Saidi@ARM.com if (dcacheInterface) { 4097949SAli.Saidi@ARM.com memReq->cmd = Copy; 4107949SAli.Saidi@ARM.com memReq->completionEvent = NULL; 4117949SAli.Saidi@ARM.com memReq->paddr = xc->copySrcPhysAddr; 4127949SAli.Saidi@ARM.com memReq->dest = dest_addr; 4137949SAli.Saidi@ARM.com memReq->size = 64; 4147949SAli.Saidi@ARM.com memReq->time = curTick; 4157949SAli.Saidi@ARM.com dcacheInterface->access(memReq); 4167949SAli.Saidi@ARM.com } 4177949SAli.Saidi@ARM.com } 4187949SAli.Saidi@ARM.com return fault; 4197949SAli.Saidi@ARM.com} 4207949SAli.Saidi@ARM.com 4217949SAli.Saidi@ARM.com// precise architected memory state accessor macros 4227949SAli.Saidi@ARM.comtemplate <class T> 4237949SAli.Saidi@ARM.comFault 4247949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, T &data, unsigned flags) 4257949SAli.Saidi@ARM.com{ 4267949SAli.Saidi@ARM.com memReq->reset(addr, sizeof(T), flags); 4277949SAli.Saidi@ARM.com 4287949SAli.Saidi@ARM.com // translate to physical address 4297949SAli.Saidi@ARM.com Fault fault = xc->translateDataReadReq(memReq); 4307949SAli.Saidi@ARM.com 4317949SAli.Saidi@ARM.com // do functional access 4327949SAli.Saidi@ARM.com if (fault == No_Fault) 4337949SAli.Saidi@ARM.com fault = xc->read(memReq, data); 4347949SAli.Saidi@ARM.com 4357949SAli.Saidi@ARM.com if (traceData) { 4367949SAli.Saidi@ARM.com traceData->setAddr(addr); 4377949SAli.Saidi@ARM.com if (fault == No_Fault) 4387949SAli.Saidi@ARM.com traceData->setData(data); 4397949SAli.Saidi@ARM.com } 4407949SAli.Saidi@ARM.com 4417949SAli.Saidi@ARM.com // if we have a cache, do cache access too 4427949SAli.Saidi@ARM.com if (fault == No_Fault && dcacheInterface) { 4437949SAli.Saidi@ARM.com memReq->cmd = Read; 4447949SAli.Saidi@ARM.com memReq->completionEvent = NULL; 4457949SAli.Saidi@ARM.com memReq->time = curTick; 4467949SAli.Saidi@ARM.com MemAccessResult result = dcacheInterface->access(memReq); 4477949SAli.Saidi@ARM.com 4487949SAli.Saidi@ARM.com // Ugly hack to get an event scheduled *only* if the access is 4497949SAli.Saidi@ARM.com // a miss. We really should add first-class support for this 4507949SAli.Saidi@ARM.com // at some point. 4517949SAli.Saidi@ARM.com if (result != MA_HIT && dcacheInterface->doEvents()) { 4527949SAli.Saidi@ARM.com memReq->completionEvent = &cacheCompletionEvent; 4537949SAli.Saidi@ARM.com lastDcacheStall = curTick; 4547949SAli.Saidi@ARM.com unscheduleTickEvent(); 4557949SAli.Saidi@ARM.com _status = DcacheMissStall; 4567949SAli.Saidi@ARM.com } 4577949SAli.Saidi@ARM.com } 4587949SAli.Saidi@ARM.com 4597949SAli.Saidi@ARM.com if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 4607949SAli.Saidi@ARM.com recordEvent("Uncached Read"); 4617949SAli.Saidi@ARM.com 4627949SAli.Saidi@ARM.com return fault; 4637949SAli.Saidi@ARM.com} 4647949SAli.Saidi@ARM.com 4657949SAli.Saidi@ARM.com#ifndef DOXYGEN_SHOULD_SKIP_THIS 4667949SAli.Saidi@ARM.com 4677949SAli.Saidi@ARM.comtemplate 4687949SAli.Saidi@ARM.comFault 4697949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 4707949SAli.Saidi@ARM.com 4717949SAli.Saidi@ARM.comtemplate 4728635Schris.emmons@arm.comFault 4738635Schris.emmons@arm.comSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 4747949SAli.Saidi@ARM.com 4757949SAli.Saidi@ARM.comtemplate 4767949SAli.Saidi@ARM.comFault 4777949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 4787949SAli.Saidi@ARM.com 4797949SAli.Saidi@ARM.comtemplate 4807949SAli.Saidi@ARM.comFault 4817949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 4827949SAli.Saidi@ARM.com 4837949SAli.Saidi@ARM.com#endif //DOXYGEN_SHOULD_SKIP_THIS 4847949SAli.Saidi@ARM.com 4857949SAli.Saidi@ARM.comtemplate<> 4867949SAli.Saidi@ARM.comFault 4877949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, double &data, unsigned flags) 4887949SAli.Saidi@ARM.com{ 4897949SAli.Saidi@ARM.com return read(addr, *(uint64_t*)&data, flags); 4907949SAli.Saidi@ARM.com} 4917949SAli.Saidi@ARM.com 4927949SAli.Saidi@ARM.comtemplate<> 4937949SAli.Saidi@ARM.comFault 4947949SAli.Saidi@ARM.comSimpleCPU::read(Addr addr, float &data, unsigned flags) 4957949SAli.Saidi@ARM.com{ 4967949SAli.Saidi@ARM.com return read(addr, *(uint32_t*)&data, flags); 4977949SAli.Saidi@ARM.com} 498 499 500template<> 501Fault 502SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 503{ 504 return read(addr, (uint32_t&)data, flags); 505} 506 507 508template <class T> 509Fault 510SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 511{ 512 if (traceData) { 513 traceData->setAddr(addr); 514 traceData->setData(data); 515 } 516 517 memReq->reset(addr, sizeof(T), flags); 518 519 // translate to physical address 520 Fault fault = xc->translateDataWriteReq(memReq); 521 522 // do functional access 523 if (fault == No_Fault) 524 fault = xc->write(memReq, data); 525 526 if (fault == No_Fault && dcacheInterface) { 527 memReq->cmd = Write; 528 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 529 memReq->completionEvent = NULL; 530 memReq->time = curTick; 531 MemAccessResult result = dcacheInterface->access(memReq); 532 533 // Ugly hack to get an event scheduled *only* if the access is 534 // a miss. We really should add first-class support for this 535 // at some point. 536 if (result != MA_HIT && dcacheInterface->doEvents()) { 537 memReq->completionEvent = &cacheCompletionEvent; 538 lastDcacheStall = curTick; 539 unscheduleTickEvent(); 540 _status = DcacheMissStall; 541 } 542 } 543 544 if (res && (fault == No_Fault)) 545 *res = memReq->result; 546 547 if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) 548 recordEvent("Uncached Write"); 549 550 return fault; 551} 552 553 554#ifndef DOXYGEN_SHOULD_SKIP_THIS 555template 556Fault 557SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 558 559template 560Fault 561SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 562 563template 564Fault 565SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 566 567template 568Fault 569SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 570 571#endif //DOXYGEN_SHOULD_SKIP_THIS 572 573template<> 574Fault 575SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 576{ 577 return write(*(uint64_t*)&data, addr, flags, res); 578} 579 580template<> 581Fault 582SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 583{ 584 return write(*(uint32_t*)&data, addr, flags, res); 585} 586 587 588template<> 589Fault 590SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 591{ 592 return write((uint32_t)data, addr, flags, res); 593} 594 595 596#ifdef FULL_SYSTEM 597Addr 598SimpleCPU::dbg_vtophys(Addr addr) 599{ 600 return vtophys(xc, addr); 601} 602#endif // FULL_SYSTEM 603 604Tick save_cycle = 0; 605 606 607void 608SimpleCPU::processCacheCompletion() 609{ 610 switch (status()) { 611 case IcacheMissStall: 612 icacheStallCycles += curTick - lastIcacheStall; 613 _status = IcacheMissComplete; 614 scheduleTickEvent(1); 615 break; 616 case DcacheMissStall: 617 dcacheStallCycles += curTick - lastDcacheStall; 618 _status = Running; 619 scheduleTickEvent(1); 620 break; 621 case SwitchedOut: 622 // If this CPU has been switched out due to sampling/warm-up, 623 // ignore any further status changes (e.g., due to cache 624 // misses outstanding at the time of the switch). 625 return; 626 default: 627 panic("SimpleCPU::processCacheCompletion: bad state"); 628 break; 629 } 630} 631 632#ifdef FULL_SYSTEM 633void 634SimpleCPU::post_interrupt(int int_num, int index) 635{ 636 BaseCPU::post_interrupt(int_num, index); 637 638 if (xc->status() == ExecContext::Suspended) { 639 DPRINTF(IPI,"Suspended Processor awoke\n"); 640 xc->activate(); 641 } 642} 643#endif // FULL_SYSTEM 644 645/* start simulation, program loaded, processor precise state initialized */ 646void 647SimpleCPU::tick() 648{ 649 numCycles++; 650 651 traceData = NULL; 652 653 Fault fault = No_Fault; 654 655#ifdef FULL_SYSTEM 656 if (checkInterrupts && check_interrupts() && !xc->inPalMode() && 657 status() != IcacheMissComplete) { 658 int ipl = 0; 659 int summary = 0; 660 checkInterrupts = false; 661 IntReg *ipr = xc->regs.ipr; 662 663 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 664 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 665 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 666 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 667 // See table 4-19 of 21164 hardware reference 668 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 669 summary |= (ULL(1) << i); 670 } 671 } 672 } 673 674 uint64_t interrupts = xc->cpu->intr_status(); 675 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 676 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 677 if (interrupts & (ULL(1) << i)) { 678 // See table 4-19 of 21164 hardware reference 679 ipl = i; 680 summary |= (ULL(1) << i); 681 } 682 } 683 684 if (ipr[TheISA::IPR_ASTRR]) 685 panic("asynchronous traps not implemented\n"); 686 687 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 688 ipr[TheISA::IPR_ISR] = summary; 689 ipr[TheISA::IPR_INTID] = ipl; 690 xc->ev5_trap(Interrupt_Fault); 691 692 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 693 ipr[TheISA::IPR_IPLR], ipl, summary); 694 } 695 } 696#endif 697 698 // maintain $r0 semantics 699 xc->regs.intRegFile[ZeroReg] = 0; 700#ifdef TARGET_ALPHA 701 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 702#endif // TARGET_ALPHA 703 704 if (status() == IcacheMissComplete) { 705 // We've already fetched an instruction and were stalled on an 706 // I-cache miss. No need to fetch it again. 707 708 // Set status to running; tick event will get rescheduled if 709 // necessary at end of tick() function. 710 _status = Running; 711 } 712 else { 713 // Try to fetch an instruction 714 715 // set up memory request for instruction fetch 716#ifdef FULL_SYSTEM 717#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 718#else 719#define IFETCH_FLAGS(pc) 0 720#endif 721 722 memReq->cmd = Read; 723 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 724 IFETCH_FLAGS(xc->regs.pc)); 725 726 fault = xc->translateInstReq(memReq); 727 728 if (fault == No_Fault) 729 fault = xc->mem->read(memReq, inst); 730 731 if (icacheInterface && fault == No_Fault) { 732 memReq->completionEvent = NULL; 733 734 memReq->time = curTick; 735 MemAccessResult result = icacheInterface->access(memReq); 736 737 // Ugly hack to get an event scheduled *only* if the access is 738 // a miss. We really should add first-class support for this 739 // at some point. 740 if (result != MA_HIT && icacheInterface->doEvents()) { 741 memReq->completionEvent = &cacheCompletionEvent; 742 lastIcacheStall = curTick; 743 unscheduleTickEvent(); 744 _status = IcacheMissStall; 745 return; 746 } 747 } 748 } 749 750 // If we've got a valid instruction (i.e., no fault on instruction 751 // fetch), then execute it. 752 if (fault == No_Fault) { 753 754 // keep an instruction count 755 numInst++; 756 numInsts++; 757 758 // check for instruction-count-based events 759 comInstEventQueue[0]->serviceEvents(numInst); 760 761 // decode the instruction 762 inst = htoa(inst); 763 StaticInstPtr<TheISA> si(inst); 764 765 traceData = Trace::getInstRecord(curTick, xc, this, si, 766 xc->regs.pc); 767 768#ifdef FULL_SYSTEM 769 xc->setInst(inst); 770#endif // FULL_SYSTEM 771 772 xc->func_exe_inst++; 773 774 fault = si->execute(this, traceData); 775 776#ifdef FULL_SYSTEM 777 if (xc->fnbin) 778 xc->execute(si.get()); 779#endif 780 781 if (si->isMemRef()) { 782 numMemRefs++; 783 } 784 785 if (si->isLoad()) { 786 ++numLoad; 787 comLoadEventQueue[0]->serviceEvents(numLoad); 788 } 789 790 if (traceData) 791 traceData->finalize(); 792 793 traceFunctions(xc->regs.pc); 794 795 } // if (fault == No_Fault) 796 797 if (fault != No_Fault) { 798#ifdef FULL_SYSTEM 799 xc->ev5_trap(fault); 800#else // !FULL_SYSTEM 801 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 802#endif // FULL_SYSTEM 803 } 804 else { 805 // go to the next instruction 806 xc->regs.pc = xc->regs.npc; 807 xc->regs.npc += sizeof(MachInst); 808 } 809 810#ifdef FULL_SYSTEM 811 Addr oldpc; 812 do { 813 oldpc = xc->regs.pc; 814 system->pcEventQueue.service(xc); 815 } while (oldpc != xc->regs.pc); 816#endif 817 818 assert(status() == Running || 819 status() == Idle || 820 status() == DcacheMissStall); 821 822 if (status() == Running && !tickEvent.scheduled()) 823 tickEvent.schedule(curTick + 1); 824} 825 826 827//////////////////////////////////////////////////////////////////////// 828// 829// SimpleCPU Simulation Object 830// 831BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 832 833 Param<Counter> max_insts_any_thread; 834 Param<Counter> max_insts_all_threads; 835 Param<Counter> max_loads_any_thread; 836 Param<Counter> max_loads_all_threads; 837 838#ifdef FULL_SYSTEM 839 SimObjectParam<AlphaITB *> itb; 840 SimObjectParam<AlphaDTB *> dtb; 841 SimObjectParam<FunctionalMemory *> mem; 842 SimObjectParam<System *> system; 843 Param<int> mult; 844#else 845 SimObjectParam<Process *> workload; 846#endif // FULL_SYSTEM 847 848 SimObjectParam<BaseMem *> icache; 849 SimObjectParam<BaseMem *> dcache; 850 851 Param<bool> defer_registration; 852 Param<int> multiplier; 853 Param<bool> function_trace; 854 Param<Tick> function_trace_start; 855 856END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 857 858BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 859 860 INIT_PARAM_DFLT(max_insts_any_thread, 861 "terminate when any thread reaches this inst count", 862 0), 863 INIT_PARAM_DFLT(max_insts_all_threads, 864 "terminate when all threads have reached this inst count", 865 0), 866 INIT_PARAM_DFLT(max_loads_any_thread, 867 "terminate when any thread reaches this load count", 868 0), 869 INIT_PARAM_DFLT(max_loads_all_threads, 870 "terminate when all threads have reached this load count", 871 0), 872 873#ifdef FULL_SYSTEM 874 INIT_PARAM(itb, "Instruction TLB"), 875 INIT_PARAM(dtb, "Data TLB"), 876 INIT_PARAM(mem, "memory"), 877 INIT_PARAM(system, "system object"), 878 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 879#else 880 INIT_PARAM(workload, "processes to run"), 881#endif // FULL_SYSTEM 882 883 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 884 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), 885 INIT_PARAM_DFLT(defer_registration, "defer registration with system " 886 "(for sampling)", false), 887 888 INIT_PARAM_DFLT(multiplier, "clock multiplier", 1), 889 INIT_PARAM_DFLT(function_trace, "Enable function trace", false), 890 INIT_PARAM_DFLT(function_trace_start, "Cycle to start function trace", 0) 891 892END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 893 894 895CREATE_SIM_OBJECT(SimpleCPU) 896{ 897 SimpleCPU *cpu; 898#ifdef FULL_SYSTEM 899 if (mult != 1) 900 panic("processor clock multiplier must be 1\n"); 901 902 cpu = new SimpleCPU(getInstanceName(), system, 903 max_insts_any_thread, max_insts_all_threads, 904 max_loads_any_thread, max_loads_all_threads, 905 itb, dtb, mem, 906 (icache) ? icache->getInterface() : NULL, 907 (dcache) ? dcache->getInterface() : NULL, 908 defer_registration, 909 ticksPerSecond * mult, 910 function_trace, function_trace_start); 911#else 912 913 cpu = new SimpleCPU(getInstanceName(), workload, 914 max_insts_any_thread, max_insts_all_threads, 915 max_loads_any_thread, max_loads_all_threads, 916 (icache) ? icache->getInterface() : NULL, 917 (dcache) ? dcache->getInterface() : NULL, 918 defer_registration, 919 function_trace, function_trace_start); 920 921#endif // FULL_SYSTEM 922 923 cpu->setTickMultiplier(multiplier); 924 925 return cpu; 926} 927 928REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 929 930