config,cpu: Add SMT support to Atomic and Timing CPUs
Adds SMT support to the "simple" CPU models so that they can be used with other SMT-supported CPUs. Example usage: this enables the TimingSimpleCPU to be used to warmup caches before swapping to detailed mode with the in-order or out-of-order based CPU models.
This commit is contained in:
parent
52d521e433
commit
582a0148b4
9 changed files with 952 additions and 669 deletions
|
@ -178,6 +178,9 @@ system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)],
|
||||||
mem_ranges = [AddrRange(options.mem_size)],
|
mem_ranges = [AddrRange(options.mem_size)],
|
||||||
cache_line_size = options.cacheline_size)
|
cache_line_size = options.cacheline_size)
|
||||||
|
|
||||||
|
if numThreads > 1:
|
||||||
|
system.multi_thread = True
|
||||||
|
|
||||||
# Create a top-level voltage domain
|
# Create a top-level voltage domain
|
||||||
system.voltage_domain = VoltageDomain(voltage = options.sys_voltage)
|
system.voltage_domain = VoltageDomain(voltage = options.sys_voltage)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Google, Inc.
|
* Copyright 2014 Google, Inc.
|
||||||
* Copyright (c) 2012-2013 ARM Limited
|
* Copyright (c) 2012-2013,2015 ARM Limited
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -84,24 +84,11 @@ AtomicSimpleCPU::TickEvent::description() const
|
||||||
void
|
void
|
||||||
AtomicSimpleCPU::init()
|
AtomicSimpleCPU::init()
|
||||||
{
|
{
|
||||||
BaseCPU::init();
|
BaseSimpleCPU::init();
|
||||||
|
|
||||||
// Initialise the ThreadContext's memory proxies
|
ifetch_req.setThreadContext(_cpuId, 0);
|
||||||
tcBase()->initMemProxies(tcBase());
|
data_read_req.setThreadContext(_cpuId, 0);
|
||||||
|
data_write_req.setThreadContext(_cpuId, 0);
|
||||||
if (FullSystem && !params()->switched_out) {
|
|
||||||
ThreadID size = threadContexts.size();
|
|
||||||
for (ThreadID i = 0; i < size; ++i) {
|
|
||||||
ThreadContext *tc = threadContexts[i];
|
|
||||||
// initialize CPU, including PC
|
|
||||||
TheISA::initCPU(tc, tc->contextId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atomic doesn't do MT right now, so contextId == threadId
|
|
||||||
ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
|
|
||||||
data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
|
||||||
data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
||||||
|
@ -131,12 +118,13 @@ AtomicSimpleCPU::drain()
|
||||||
return DrainState::Drained;
|
return DrainState::Drained;
|
||||||
|
|
||||||
if (!isDrained()) {
|
if (!isDrained()) {
|
||||||
DPRINTF(Drain, "Requesting drain: %s\n", pcState());
|
DPRINTF(Drain, "Requesting drain.\n");
|
||||||
return DrainState::Draining;
|
return DrainState::Draining;
|
||||||
} else {
|
} else {
|
||||||
if (tickEvent.scheduled())
|
if (tickEvent.scheduled())
|
||||||
deschedule(tickEvent);
|
deschedule(tickEvent);
|
||||||
|
|
||||||
|
activeThreads.clear();
|
||||||
DPRINTF(Drain, "Not executing microcode, no need to drain.\n");
|
DPRINTF(Drain, "Not executing microcode, no need to drain.\n");
|
||||||
return DrainState::Drained;
|
return DrainState::Drained;
|
||||||
}
|
}
|
||||||
|
@ -153,16 +141,22 @@ AtomicSimpleCPU::drainResume()
|
||||||
verifyMemoryMode();
|
verifyMemoryMode();
|
||||||
|
|
||||||
assert(!threadContexts.empty());
|
assert(!threadContexts.empty());
|
||||||
if (threadContexts.size() > 1)
|
|
||||||
fatal("The atomic CPU only supports one thread.\n");
|
|
||||||
|
|
||||||
if (thread->status() == ThreadContext::Active) {
|
_status = BaseSimpleCPU::Idle;
|
||||||
schedule(tickEvent, nextCycle());
|
|
||||||
_status = BaseSimpleCPU::Running;
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
notIdleFraction = 1;
|
if (threadInfo[tid]->thread->status() == ThreadContext::Active) {
|
||||||
} else {
|
threadInfo[tid]->notIdleFraction = 1;
|
||||||
_status = BaseSimpleCPU::Idle;
|
activeThreads.push_back(tid);
|
||||||
notIdleFraction = 0;
|
_status = BaseSimpleCPU::Running;
|
||||||
|
|
||||||
|
// Tick if any threads active
|
||||||
|
if (!tickEvent.scheduled()) {
|
||||||
|
schedule(tickEvent, nextCycle());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
threadInfo[tid]->notIdleFraction = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +166,7 @@ AtomicSimpleCPU::tryCompleteDrain()
|
||||||
if (drainState() != DrainState::Draining)
|
if (drainState() != DrainState::Draining)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
|
DPRINTF(Drain, "tryCompleteDrain.\n");
|
||||||
if (!isDrained())
|
if (!isDrained())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -201,10 +195,6 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
|
||||||
|
|
||||||
// The tick event should have been descheduled by drain()
|
// The tick event should have been descheduled by drain()
|
||||||
assert(!tickEvent.scheduled());
|
assert(!tickEvent.scheduled());
|
||||||
|
|
||||||
ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
|
|
||||||
data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
|
||||||
data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -221,20 +211,23 @@ AtomicSimpleCPU::activateContext(ThreadID thread_num)
|
||||||
{
|
{
|
||||||
DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
|
DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
|
||||||
|
|
||||||
assert(thread_num == 0);
|
assert(thread_num < numThreads);
|
||||||
assert(thread);
|
|
||||||
|
|
||||||
assert(_status == Idle);
|
threadInfo[thread_num]->notIdleFraction = 1;
|
||||||
assert(!tickEvent.scheduled());
|
Cycles delta = ticksToCycles(threadInfo[thread_num]->thread->lastActivate -
|
||||||
|
threadInfo[thread_num]->thread->lastSuspend);
|
||||||
notIdleFraction = 1;
|
|
||||||
Cycles delta = ticksToCycles(thread->lastActivate - thread->lastSuspend);
|
|
||||||
numCycles += delta;
|
numCycles += delta;
|
||||||
ppCycles->notify(delta);
|
ppCycles->notify(delta);
|
||||||
|
|
||||||
//Make sure ticks are still on multiples of cycles
|
if (!tickEvent.scheduled()) {
|
||||||
schedule(tickEvent, clockEdge(Cycles(0)));
|
//Make sure ticks are still on multiples of cycles
|
||||||
|
schedule(tickEvent, clockEdge(Cycles(0)));
|
||||||
|
}
|
||||||
_status = BaseSimpleCPU::Running;
|
_status = BaseSimpleCPU::Running;
|
||||||
|
if (std::find(activeThreads.begin(), activeThreads.end(), thread_num)
|
||||||
|
== activeThreads.end()) {
|
||||||
|
activeThreads.push_back(thread_num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,21 +236,24 @@ AtomicSimpleCPU::suspendContext(ThreadID thread_num)
|
||||||
{
|
{
|
||||||
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
||||||
|
|
||||||
assert(thread_num == 0);
|
assert(thread_num < numThreads);
|
||||||
assert(thread);
|
activeThreads.remove(thread_num);
|
||||||
|
|
||||||
if (_status == Idle)
|
if (_status == Idle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(_status == BaseSimpleCPU::Running);
|
assert(_status == BaseSimpleCPU::Running);
|
||||||
|
|
||||||
// tick event may not be scheduled if this gets called from inside
|
threadInfo[thread_num]->notIdleFraction = 0;
|
||||||
// an instruction's execution, e.g. "quiesce"
|
|
||||||
if (tickEvent.scheduled())
|
if (activeThreads.empty()) {
|
||||||
deschedule(tickEvent);
|
_status = Idle;
|
||||||
|
|
||||||
|
if (tickEvent.scheduled()) {
|
||||||
|
deschedule(tickEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notIdleFraction = 0;
|
|
||||||
_status = Idle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,7 +265,7 @@ AtomicSimpleCPU::AtomicCPUDPort::recvAtomicSnoop(PacketPtr pkt)
|
||||||
|
|
||||||
// X86 ISA: Snooping an invalidation for monitor/mwait
|
// X86 ISA: Snooping an invalidation for monitor/mwait
|
||||||
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
|
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
|
||||||
if(cpu->getAddrMonitor()->doMonitor(pkt)) {
|
if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
|
||||||
cpu->wakeup();
|
cpu->wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +273,9 @@ AtomicSimpleCPU::AtomicCPUDPort::recvAtomicSnoop(PacketPtr pkt)
|
||||||
if (pkt->isInvalidate()) {
|
if (pkt->isInvalidate()) {
|
||||||
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
|
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
|
||||||
pkt->getAddr());
|
pkt->getAddr());
|
||||||
TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
|
for (auto &t_info : cpu->threadInfo) {
|
||||||
|
TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -291,7 +289,7 @@ AtomicSimpleCPU::AtomicCPUDPort::recvFunctionalSnoop(PacketPtr pkt)
|
||||||
|
|
||||||
// X86 ISA: Snooping an invalidation for monitor/mwait
|
// X86 ISA: Snooping an invalidation for monitor/mwait
|
||||||
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
|
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
|
||||||
if(cpu->getAddrMonitor()->doMonitor(pkt)) {
|
if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
|
||||||
cpu->wakeup();
|
cpu->wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +297,9 @@ AtomicSimpleCPU::AtomicCPUDPort::recvFunctionalSnoop(PacketPtr pkt)
|
||||||
if (pkt->isInvalidate()) {
|
if (pkt->isInvalidate()) {
|
||||||
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
|
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
|
||||||
pkt->getAddr());
|
pkt->getAddr());
|
||||||
TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
|
for (auto &t_info : cpu->threadInfo) {
|
||||||
|
TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +307,9 @@ Fault
|
||||||
AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
|
AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
|
||||||
unsigned size, unsigned flags)
|
unsigned size, unsigned flags)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
// use the CPU's statically allocated read request and packet objects
|
// use the CPU's statically allocated read request and packet objects
|
||||||
Request *req = &data_read_req;
|
Request *req = &data_read_req;
|
||||||
|
|
||||||
|
@ -330,7 +333,8 @@ AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
|
||||||
req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
|
req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
|
||||||
|
|
||||||
// translate to physical address
|
// translate to physical address
|
||||||
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
|
Fault fault = thread->dtb->translateAtomic(req, thread->getTC(),
|
||||||
|
BaseTLB::Read);
|
||||||
|
|
||||||
// Now do the access.
|
// Now do the access.
|
||||||
if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
|
if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||||
|
@ -370,6 +374,7 @@ AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
|
||||||
assert(!locked);
|
assert(!locked);
|
||||||
locked = true;
|
locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fault;
|
return fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +396,8 @@ Fault
|
||||||
AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
Addr addr, unsigned flags, uint64_t *res)
|
Addr addr, unsigned flags, uint64_t *res)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
static uint8_t zero_array[64] = {};
|
static uint8_t zero_array[64] = {};
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
|
@ -424,7 +430,7 @@ AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
|
req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
|
||||||
|
|
||||||
// translate to physical address
|
// translate to physical address
|
||||||
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
|
Fault fault = thread->dtb->translateAtomic(req, thread->getTC(), BaseTLB::Write);
|
||||||
|
|
||||||
// Now do the access.
|
// Now do the access.
|
||||||
if (fault == NoFault) {
|
if (fault == NoFault) {
|
||||||
|
@ -477,6 +483,8 @@ AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
assert(locked);
|
assert(locked);
|
||||||
locked = false;
|
locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (fault != NoFault && req->isPrefetch()) {
|
if (fault != NoFault && req->isPrefetch()) {
|
||||||
return NoFault;
|
return NoFault;
|
||||||
} else {
|
} else {
|
||||||
|
@ -503,6 +511,19 @@ AtomicSimpleCPU::tick()
|
||||||
{
|
{
|
||||||
DPRINTF(SimpleCPU, "Tick\n");
|
DPRINTF(SimpleCPU, "Tick\n");
|
||||||
|
|
||||||
|
// Change thread if multi-threaded
|
||||||
|
swapActiveThread();
|
||||||
|
|
||||||
|
// Set memroy request ids to current thread
|
||||||
|
if (numThreads > 1) {
|
||||||
|
ifetch_req.setThreadContext(_cpuId, curThread);
|
||||||
|
data_read_req.setThreadContext(_cpuId, curThread);
|
||||||
|
data_write_req.setThreadContext(_cpuId, curThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
Tick latency = 0;
|
Tick latency = 0;
|
||||||
|
|
||||||
for (int i = 0; i < width || locked; ++i) {
|
for (int i = 0; i < width || locked; ++i) {
|
||||||
|
@ -529,7 +550,7 @@ AtomicSimpleCPU::tick()
|
||||||
if (needToFetch) {
|
if (needToFetch) {
|
||||||
ifetch_req.taskId(taskId());
|
ifetch_req.taskId(taskId());
|
||||||
setupFetchRequest(&ifetch_req);
|
setupFetchRequest(&ifetch_req);
|
||||||
fault = thread->itb->translateAtomic(&ifetch_req, tc,
|
fault = thread->itb->translateAtomic(&ifetch_req, thread->getTC(),
|
||||||
BaseTLB::Execute);
|
BaseTLB::Execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +586,7 @@ AtomicSimpleCPU::tick()
|
||||||
preExecute();
|
preExecute();
|
||||||
|
|
||||||
if (curStaticInst) {
|
if (curStaticInst) {
|
||||||
fault = curStaticInst->execute(this, traceData);
|
fault = curStaticInst->execute(&t_info, traceData);
|
||||||
|
|
||||||
// keep an instruction count
|
// keep an instruction count
|
||||||
if (fault == NoFault) {
|
if (fault == NoFault) {
|
||||||
|
@ -601,7 +622,7 @@ AtomicSimpleCPU::tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if(fault != NoFault || !stayAtPC)
|
if(fault != NoFault || !t_info.stayAtPC)
|
||||||
advancePC(fault);
|
advancePC(fault);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +634,7 @@ AtomicSimpleCPU::tick()
|
||||||
latency = clockPeriod();
|
latency = clockPeriod();
|
||||||
|
|
||||||
if (_status != Idle)
|
if (_status != Idle)
|
||||||
schedule(tickEvent, curTick() + latency);
|
reschedule(tickEvent, curTick() + latency, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -638,8 +659,5 @@ AtomicSimpleCPU::printAddr(Addr a)
|
||||||
AtomicSimpleCPU *
|
AtomicSimpleCPU *
|
||||||
AtomicSimpleCPUParams::create()
|
AtomicSimpleCPUParams::create()
|
||||||
{
|
{
|
||||||
numThreads = 1;
|
|
||||||
if (!FullSystem && workload.size() != 1)
|
|
||||||
panic("only one workload allowed");
|
|
||||||
return new AtomicSimpleCPU(this);
|
return new AtomicSimpleCPU(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2013 ARM Limited
|
* Copyright (c) 2012-2013,2015 ARM Limited
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
#define __CPU_SIMPLE_ATOMIC_HH__
|
#define __CPU_SIMPLE_ATOMIC_HH__
|
||||||
|
|
||||||
#include "cpu/simple/base.hh"
|
#include "cpu/simple/base.hh"
|
||||||
|
#include "cpu/simple/exec_context.hh"
|
||||||
#include "params/AtomicSimpleCPU.hh"
|
#include "params/AtomicSimpleCPU.hh"
|
||||||
#include "sim/probe/probe.hh"
|
#include "sim/probe/probe.hh"
|
||||||
|
|
||||||
|
@ -96,9 +97,11 @@ class AtomicSimpleCPU : public BaseSimpleCPU
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
bool isDrained() {
|
bool isDrained() {
|
||||||
return microPC() == 0 &&
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
|
||||||
|
return t_info.thread->microPC() == 0 &&
|
||||||
!locked &&
|
!locked &&
|
||||||
!stayAtPC;
|
!t_info.stayAtPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2012 ARM Limited
|
* Copyright (c) 2010-2012,2015 ARM Limited
|
||||||
* Copyright (c) 2013 Advanced Micro Devices, Inc.
|
* Copyright (c) 2013 Advanced Micro Devices, Inc.
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
|
@ -62,6 +62,7 @@
|
||||||
#include "cpu/exetrace.hh"
|
#include "cpu/exetrace.hh"
|
||||||
#include "cpu/pred/bpred_unit.hh"
|
#include "cpu/pred/bpred_unit.hh"
|
||||||
#include "cpu/profile.hh"
|
#include "cpu/profile.hh"
|
||||||
|
#include "cpu/simple/exec_context.hh"
|
||||||
#include "cpu/simple_thread.hh"
|
#include "cpu/simple_thread.hh"
|
||||||
#include "cpu/smt.hh"
|
#include "cpu/smt.hh"
|
||||||
#include "cpu/static_inst.hh"
|
#include "cpu/static_inst.hh"
|
||||||
|
@ -87,46 +88,121 @@ using namespace TheISA;
|
||||||
|
|
||||||
BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
|
BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
|
||||||
: BaseCPU(p),
|
: BaseCPU(p),
|
||||||
|
curThread(0),
|
||||||
branchPred(p->branchPred),
|
branchPred(p->branchPred),
|
||||||
traceData(NULL), thread(NULL), _status(Idle), interval_stats(false),
|
traceData(NULL),
|
||||||
inst()
|
inst(),
|
||||||
|
_status(Idle)
|
||||||
{
|
{
|
||||||
if (FullSystem)
|
SimpleThread *thread;
|
||||||
thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb,
|
|
||||||
p->isa[0]);
|
|
||||||
else
|
|
||||||
thread = new SimpleThread(this, /* thread_num */ 0, p->system,
|
|
||||||
p->workload[0], p->itb, p->dtb, p->isa[0]);
|
|
||||||
|
|
||||||
thread->setStatus(ThreadContext::Halted);
|
for (unsigned i = 0; i < numThreads; i++) {
|
||||||
|
if (FullSystem) {
|
||||||
tc = thread->getTC();
|
thread = new SimpleThread(this, i, p->system,
|
||||||
|
p->itb, p->dtb, p->isa[i]);
|
||||||
|
} else {
|
||||||
|
thread = new SimpleThread(this, i, p->system, p->workload[i],
|
||||||
|
p->itb, p->dtb, p->isa[i]);
|
||||||
|
}
|
||||||
|
threadInfo.push_back(new SimpleExecContext(this, thread));
|
||||||
|
ThreadContext *tc = thread->getTC();
|
||||||
|
threadContexts.push_back(tc);
|
||||||
|
}
|
||||||
|
|
||||||
if (p->checker) {
|
if (p->checker) {
|
||||||
|
if (numThreads != 1)
|
||||||
|
fatal("Checker currently does not support SMT");
|
||||||
|
|
||||||
BaseCPU *temp_checker = p->checker;
|
BaseCPU *temp_checker = p->checker;
|
||||||
checker = dynamic_cast<CheckerCPU *>(temp_checker);
|
checker = dynamic_cast<CheckerCPU *>(temp_checker);
|
||||||
checker->setSystem(p->system);
|
checker->setSystem(p->system);
|
||||||
// Manipulate thread context
|
// Manipulate thread context
|
||||||
ThreadContext *cpu_tc = tc;
|
ThreadContext *cpu_tc = threadContexts[0];
|
||||||
tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
|
threadContexts[0] = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
|
||||||
} else {
|
} else {
|
||||||
checker = NULL;
|
checker = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
numInst = 0;
|
void
|
||||||
startNumInst = 0;
|
BaseSimpleCPU::init()
|
||||||
numOp = 0;
|
{
|
||||||
startNumOp = 0;
|
BaseCPU::init();
|
||||||
numLoad = 0;
|
|
||||||
startNumLoad = 0;
|
|
||||||
lastIcacheStall = 0;
|
|
||||||
lastDcacheStall = 0;
|
|
||||||
|
|
||||||
threadContexts.push_back(tc);
|
for (auto tc : threadContexts) {
|
||||||
|
// Initialise the ThreadContext's memory proxies
|
||||||
|
tc->initMemProxies(tc);
|
||||||
|
|
||||||
|
if (FullSystem && !params()->switched_out) {
|
||||||
|
// initialize CPU, including PC
|
||||||
|
TheISA::initCPU(tc, tc->contextId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetchOffset = 0;
|
void
|
||||||
stayAtPC = false;
|
BaseSimpleCPU::checkPcEventQueue()
|
||||||
|
{
|
||||||
|
Addr oldpc, pc = threadInfo[curThread]->thread->instAddr();
|
||||||
|
do {
|
||||||
|
oldpc = pc;
|
||||||
|
system->pcEventQueue.service(threadContexts[curThread]);
|
||||||
|
pc = threadInfo[curThread]->thread->instAddr();
|
||||||
|
} while (oldpc != pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseSimpleCPU::swapActiveThread()
|
||||||
|
{
|
||||||
|
if (numThreads > 1) {
|
||||||
|
if ((!curStaticInst || !curStaticInst->isDelayedCommit()) &&
|
||||||
|
!threadInfo[curThread]->stayAtPC) {
|
||||||
|
// Swap active threads
|
||||||
|
if (!activeThreads.empty()) {
|
||||||
|
curThread = activeThreads.front();
|
||||||
|
activeThreads.pop_front();
|
||||||
|
activeThreads.push_back(curThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BaseSimpleCPU::countInst()
|
||||||
|
{
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
|
||||||
|
if (!curStaticInst->isMicroop() || curStaticInst->isLastMicroop()) {
|
||||||
|
t_info.numInst++;
|
||||||
|
t_info.numInsts++;
|
||||||
|
}
|
||||||
|
t_info.numOp++;
|
||||||
|
t_info.numOps++;
|
||||||
|
|
||||||
|
system->totalNumInsts++;
|
||||||
|
t_info.thread->funcExeInst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Counter
|
||||||
|
BaseSimpleCPU::totalInsts() const
|
||||||
|
{
|
||||||
|
Counter total_inst = 0;
|
||||||
|
for (auto& t_info : threadInfo) {
|
||||||
|
total_inst += t_info->numInst;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
Counter
|
||||||
|
BaseSimpleCPU::totalOps() const
|
||||||
|
{
|
||||||
|
Counter total_op = 0;
|
||||||
|
for (auto& t_info : threadInfo) {
|
||||||
|
total_op += t_info->numOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_op;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseSimpleCPU::~BaseSimpleCPU()
|
BaseSimpleCPU::~BaseSimpleCPU()
|
||||||
|
@ -148,177 +224,184 @@ BaseSimpleCPU::regStats()
|
||||||
|
|
||||||
BaseCPU::regStats();
|
BaseCPU::regStats();
|
||||||
|
|
||||||
numInsts
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
.name(name() + ".committedInsts")
|
SimpleExecContext& t_info = *threadInfo[tid];
|
||||||
.desc("Number of instructions committed")
|
|
||||||
;
|
|
||||||
|
|
||||||
numOps
|
std::string thread_str = name();
|
||||||
.name(name() + ".committedOps")
|
if (numThreads > 1)
|
||||||
.desc("Number of ops (including micro ops) committed")
|
thread_str += ".thread" + std::to_string(tid);
|
||||||
;
|
|
||||||
|
|
||||||
numIntAluAccesses
|
t_info.numInsts
|
||||||
.name(name() + ".num_int_alu_accesses")
|
.name(thread_str + ".committedInsts")
|
||||||
.desc("Number of integer alu accesses")
|
.desc("Number of instructions committed")
|
||||||
;
|
;
|
||||||
|
|
||||||
numFpAluAccesses
|
t_info.numOps
|
||||||
.name(name() + ".num_fp_alu_accesses")
|
.name(thread_str + ".committedOps")
|
||||||
.desc("Number of float alu accesses")
|
.desc("Number of ops (including micro ops) committed")
|
||||||
;
|
;
|
||||||
|
|
||||||
numCallsReturns
|
t_info.numIntAluAccesses
|
||||||
.name(name() + ".num_func_calls")
|
.name(thread_str + ".num_int_alu_accesses")
|
||||||
.desc("number of times a function call or return occured")
|
.desc("Number of integer alu accesses")
|
||||||
;
|
;
|
||||||
|
|
||||||
numCondCtrlInsts
|
t_info.numFpAluAccesses
|
||||||
.name(name() + ".num_conditional_control_insts")
|
.name(thread_str + ".num_fp_alu_accesses")
|
||||||
.desc("number of instructions that are conditional controls")
|
.desc("Number of float alu accesses")
|
||||||
;
|
;
|
||||||
|
|
||||||
numIntInsts
|
t_info.numCallsReturns
|
||||||
.name(name() + ".num_int_insts")
|
.name(thread_str + ".num_func_calls")
|
||||||
.desc("number of integer instructions")
|
.desc("number of times a function call or return occured")
|
||||||
;
|
;
|
||||||
|
|
||||||
numFpInsts
|
t_info.numCondCtrlInsts
|
||||||
.name(name() + ".num_fp_insts")
|
.name(thread_str + ".num_conditional_control_insts")
|
||||||
.desc("number of float instructions")
|
.desc("number of instructions that are conditional controls")
|
||||||
;
|
;
|
||||||
|
|
||||||
numIntRegReads
|
t_info.numIntInsts
|
||||||
.name(name() + ".num_int_register_reads")
|
.name(thread_str + ".num_int_insts")
|
||||||
.desc("number of times the integer registers were read")
|
.desc("number of integer instructions")
|
||||||
;
|
;
|
||||||
|
|
||||||
numIntRegWrites
|
t_info.numFpInsts
|
||||||
.name(name() + ".num_int_register_writes")
|
.name(thread_str + ".num_fp_insts")
|
||||||
.desc("number of times the integer registers were written")
|
.desc("number of float instructions")
|
||||||
;
|
;
|
||||||
|
|
||||||
numFpRegReads
|
t_info.numIntRegReads
|
||||||
.name(name() + ".num_fp_register_reads")
|
.name(thread_str + ".num_int_register_reads")
|
||||||
.desc("number of times the floating registers were read")
|
.desc("number of times the integer registers were read")
|
||||||
;
|
;
|
||||||
|
|
||||||
numFpRegWrites
|
t_info.numIntRegWrites
|
||||||
.name(name() + ".num_fp_register_writes")
|
.name(thread_str + ".num_int_register_writes")
|
||||||
.desc("number of times the floating registers were written")
|
.desc("number of times the integer registers were written")
|
||||||
;
|
;
|
||||||
|
|
||||||
numCCRegReads
|
t_info.numFpRegReads
|
||||||
.name(name() + ".num_cc_register_reads")
|
.name(thread_str + ".num_fp_register_reads")
|
||||||
.desc("number of times the CC registers were read")
|
.desc("number of times the floating registers were read")
|
||||||
.flags(nozero)
|
;
|
||||||
;
|
|
||||||
|
|
||||||
numCCRegWrites
|
t_info.numFpRegWrites
|
||||||
.name(name() + ".num_cc_register_writes")
|
.name(thread_str + ".num_fp_register_writes")
|
||||||
.desc("number of times the CC registers were written")
|
.desc("number of times the floating registers were written")
|
||||||
.flags(nozero)
|
;
|
||||||
;
|
|
||||||
|
|
||||||
numMemRefs
|
t_info.numCCRegReads
|
||||||
.name(name()+".num_mem_refs")
|
.name(thread_str + ".num_cc_register_reads")
|
||||||
.desc("number of memory refs")
|
.desc("number of times the CC registers were read")
|
||||||
;
|
.flags(nozero)
|
||||||
|
;
|
||||||
|
|
||||||
numStoreInsts
|
t_info.numCCRegWrites
|
||||||
.name(name() + ".num_store_insts")
|
.name(thread_str + ".num_cc_register_writes")
|
||||||
.desc("Number of store instructions")
|
.desc("number of times the CC registers were written")
|
||||||
;
|
.flags(nozero)
|
||||||
|
;
|
||||||
|
|
||||||
numLoadInsts
|
t_info.numMemRefs
|
||||||
.name(name() + ".num_load_insts")
|
.name(thread_str + ".num_mem_refs")
|
||||||
.desc("Number of load instructions")
|
.desc("number of memory refs")
|
||||||
;
|
;
|
||||||
|
|
||||||
notIdleFraction
|
t_info.numStoreInsts
|
||||||
.name(name() + ".not_idle_fraction")
|
.name(thread_str + ".num_store_insts")
|
||||||
.desc("Percentage of non-idle cycles")
|
.desc("Number of store instructions")
|
||||||
;
|
;
|
||||||
|
|
||||||
idleFraction
|
t_info.numLoadInsts
|
||||||
.name(name() + ".idle_fraction")
|
.name(thread_str + ".num_load_insts")
|
||||||
.desc("Percentage of idle cycles")
|
.desc("Number of load instructions")
|
||||||
;
|
;
|
||||||
|
|
||||||
numBusyCycles
|
t_info.notIdleFraction
|
||||||
.name(name() + ".num_busy_cycles")
|
.name(thread_str + ".not_idle_fraction")
|
||||||
.desc("Number of busy cycles")
|
.desc("Percentage of non-idle cycles")
|
||||||
;
|
;
|
||||||
|
|
||||||
numIdleCycles
|
t_info.idleFraction
|
||||||
.name(name()+".num_idle_cycles")
|
.name(thread_str + ".idle_fraction")
|
||||||
.desc("Number of idle cycles")
|
.desc("Percentage of idle cycles")
|
||||||
;
|
;
|
||||||
|
|
||||||
icacheStallCycles
|
t_info.numBusyCycles
|
||||||
.name(name() + ".icache_stall_cycles")
|
.name(thread_str + ".num_busy_cycles")
|
||||||
.desc("ICache total stall cycles")
|
.desc("Number of busy cycles")
|
||||||
.prereq(icacheStallCycles)
|
;
|
||||||
;
|
|
||||||
|
|
||||||
dcacheStallCycles
|
t_info.numIdleCycles
|
||||||
.name(name() + ".dcache_stall_cycles")
|
.name(thread_str + ".num_idle_cycles")
|
||||||
.desc("DCache total stall cycles")
|
.desc("Number of idle cycles")
|
||||||
.prereq(dcacheStallCycles)
|
;
|
||||||
;
|
|
||||||
|
|
||||||
statExecutedInstType
|
t_info.icacheStallCycles
|
||||||
.init(Enums::Num_OpClass)
|
.name(thread_str + ".icache_stall_cycles")
|
||||||
.name(name() + ".op_class")
|
.desc("ICache total stall cycles")
|
||||||
.desc("Class of executed instruction")
|
.prereq(t_info.icacheStallCycles)
|
||||||
.flags(total | pdf | dist)
|
;
|
||||||
;
|
|
||||||
for (unsigned i = 0; i < Num_OpClasses; ++i) {
|
t_info.dcacheStallCycles
|
||||||
statExecutedInstType.subname(i, Enums::OpClassStrings[i]);
|
.name(thread_str + ".dcache_stall_cycles")
|
||||||
|
.desc("DCache total stall cycles")
|
||||||
|
.prereq(t_info.dcacheStallCycles)
|
||||||
|
;
|
||||||
|
|
||||||
|
t_info.statExecutedInstType
|
||||||
|
.init(Enums::Num_OpClass)
|
||||||
|
.name(thread_str + ".op_class")
|
||||||
|
.desc("Class of executed instruction")
|
||||||
|
.flags(total | pdf | dist)
|
||||||
|
;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < Num_OpClasses; ++i) {
|
||||||
|
t_info.statExecutedInstType.subname(i, Enums::OpClassStrings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_info.idleFraction = constant(1.0) - t_info.notIdleFraction;
|
||||||
|
t_info.numIdleCycles = t_info.idleFraction * numCycles;
|
||||||
|
t_info.numBusyCycles = t_info.notIdleFraction * numCycles;
|
||||||
|
|
||||||
|
t_info.numBranches
|
||||||
|
.name(thread_str + ".Branches")
|
||||||
|
.desc("Number of branches fetched")
|
||||||
|
.prereq(t_info.numBranches);
|
||||||
|
|
||||||
|
t_info.numPredictedBranches
|
||||||
|
.name(thread_str + ".predictedBranches")
|
||||||
|
.desc("Number of branches predicted as taken")
|
||||||
|
.prereq(t_info.numPredictedBranches);
|
||||||
|
|
||||||
|
t_info.numBranchMispred
|
||||||
|
.name(thread_str + ".BranchMispred")
|
||||||
|
.desc("Number of branch mispredictions")
|
||||||
|
.prereq(t_info.numBranchMispred);
|
||||||
}
|
}
|
||||||
|
|
||||||
idleFraction = constant(1.0) - notIdleFraction;
|
|
||||||
numIdleCycles = idleFraction * numCycles;
|
|
||||||
numBusyCycles = (notIdleFraction)*numCycles;
|
|
||||||
|
|
||||||
numBranches
|
|
||||||
.name(name() + ".Branches")
|
|
||||||
.desc("Number of branches fetched")
|
|
||||||
.prereq(numBranches);
|
|
||||||
|
|
||||||
numPredictedBranches
|
|
||||||
.name(name() + ".predictedBranches")
|
|
||||||
.desc("Number of branches predicted as taken")
|
|
||||||
.prereq(numPredictedBranches);
|
|
||||||
|
|
||||||
numBranchMispred
|
|
||||||
.name(name() + ".BranchMispred")
|
|
||||||
.desc("Number of branch mispredictions")
|
|
||||||
.prereq(numBranchMispred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::resetStats()
|
BaseSimpleCPU::resetStats()
|
||||||
{
|
{
|
||||||
// startNumInst = numInst;
|
for (auto &thread_info : threadInfo) {
|
||||||
notIdleFraction = (_status != Idle);
|
thread_info->notIdleFraction = (_status != Idle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::serializeThread(CheckpointOut &cp, ThreadID tid) const
|
BaseSimpleCPU::serializeThread(CheckpointOut &cp, ThreadID tid) const
|
||||||
{
|
{
|
||||||
assert(_status == Idle || _status == Running);
|
assert(_status == Idle || _status == Running);
|
||||||
assert(tid == 0);
|
|
||||||
|
|
||||||
thread->serialize(cp);
|
threadInfo[tid]->thread->serialize(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::unserializeThread(CheckpointIn &cp, ThreadID tid)
|
BaseSimpleCPU::unserializeThread(CheckpointIn &cp, ThreadID tid)
|
||||||
{
|
{
|
||||||
if (tid != 0)
|
threadInfo[tid]->thread->unserialize(cp);
|
||||||
fatal("Trying to load more than one thread into a SimpleCPU\n");
|
|
||||||
thread->unserialize(cp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -329,29 +412,34 @@ change_thread_state(ThreadID tid, int activate, int priority)
|
||||||
Addr
|
Addr
|
||||||
BaseSimpleCPU::dbg_vtophys(Addr addr)
|
BaseSimpleCPU::dbg_vtophys(Addr addr)
|
||||||
{
|
{
|
||||||
return vtophys(tc, addr);
|
return vtophys(threadContexts[curThread], addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::wakeup()
|
BaseSimpleCPU::wakeup()
|
||||||
{
|
{
|
||||||
getAddrMonitor()->gotWakeup = true;
|
getCpuAddrMonitor()->gotWakeup = true;
|
||||||
|
|
||||||
if (thread->status() != ThreadContext::Suspended)
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
return;
|
if (threadInfo[tid]->thread->status() == ThreadContext::Suspended) {
|
||||||
|
DPRINTF(Quiesce,"Suspended Processor awoke\n");
|
||||||
DPRINTF(Quiesce,"Suspended Processor awoke\n");
|
threadInfo[tid]->thread->activate();
|
||||||
thread->activate();
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::checkForInterrupts()
|
BaseSimpleCPU::checkForInterrupts()
|
||||||
{
|
{
|
||||||
|
SimpleExecContext&t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
ThreadContext* tc = thread->getTC();
|
||||||
|
|
||||||
if (checkInterrupts(tc)) {
|
if (checkInterrupts(tc)) {
|
||||||
Fault interrupt = interrupts->getInterrupt(tc);
|
Fault interrupt = interrupts->getInterrupt(tc);
|
||||||
|
|
||||||
if (interrupt != NoFault) {
|
if (interrupt != NoFault) {
|
||||||
fetchOffset = 0;
|
t_info.fetchOffset = 0;
|
||||||
interrupts->updateIntrInfo(tc);
|
interrupts->updateIntrInfo(tc);
|
||||||
interrupt->invoke(tc);
|
interrupt->invoke(tc);
|
||||||
thread->decoder.reset();
|
thread->decoder.reset();
|
||||||
|
@ -363,12 +451,15 @@ BaseSimpleCPU::checkForInterrupts()
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::setupFetchRequest(Request *req)
|
BaseSimpleCPU::setupFetchRequest(Request *req)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
Addr instAddr = thread->instAddr();
|
Addr instAddr = thread->instAddr();
|
||||||
|
|
||||||
// set up memory request for instruction fetch
|
// set up memory request for instruction fetch
|
||||||
DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
|
DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
|
||||||
|
|
||||||
Addr fetchPC = (instAddr & PCMask) + fetchOffset;
|
Addr fetchPC = (instAddr & PCMask) + t_info.fetchOffset;
|
||||||
req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instMasterId(),
|
req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instMasterId(),
|
||||||
instAddr);
|
instAddr);
|
||||||
}
|
}
|
||||||
|
@ -377,6 +468,9 @@ BaseSimpleCPU::setupFetchRequest(Request *req)
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::preExecute()
|
BaseSimpleCPU::preExecute()
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
// maintain $r0 semantics
|
// maintain $r0 semantics
|
||||||
thread->setIntReg(ZeroReg, 0);
|
thread->setIntReg(ZeroReg, 0);
|
||||||
#if THE_ISA == ALPHA_ISA
|
#if THE_ISA == ALPHA_ISA
|
||||||
|
@ -384,7 +478,7 @@ BaseSimpleCPU::preExecute()
|
||||||
#endif // ALPHA_ISA
|
#endif // ALPHA_ISA
|
||||||
|
|
||||||
// check for instruction-count-based events
|
// check for instruction-count-based events
|
||||||
comInstEventQueue[0]->serviceEvents(numInst);
|
comInstEventQueue[curThread]->serviceEvents(t_info.numInst);
|
||||||
system->instEventQueue.serviceEvents(system->totalNumInsts);
|
system->instEventQueue.serviceEvents(system->totalNumInsts);
|
||||||
|
|
||||||
// decode the instruction
|
// decode the instruction
|
||||||
|
@ -393,7 +487,7 @@ BaseSimpleCPU::preExecute()
|
||||||
TheISA::PCState pcState = thread->pcState();
|
TheISA::PCState pcState = thread->pcState();
|
||||||
|
|
||||||
if (isRomMicroPC(pcState.microPC())) {
|
if (isRomMicroPC(pcState.microPC())) {
|
||||||
stayAtPC = false;
|
t_info.stayAtPC = false;
|
||||||
curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
|
curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
|
||||||
curMacroStaticInst);
|
curMacroStaticInst);
|
||||||
} else if (!curMacroStaticInst) {
|
} else if (!curMacroStaticInst) {
|
||||||
|
@ -404,7 +498,7 @@ BaseSimpleCPU::preExecute()
|
||||||
|
|
||||||
//Predecode, ie bundle up an ExtMachInst
|
//Predecode, ie bundle up an ExtMachInst
|
||||||
//If more fetch data is needed, pass it in.
|
//If more fetch data is needed, pass it in.
|
||||||
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
|
Addr fetchPC = (pcState.instAddr() & PCMask) + t_info.fetchOffset;
|
||||||
//if(decoder->needMoreBytes())
|
//if(decoder->needMoreBytes())
|
||||||
decoder->moreBytes(pcState, fetchPC, inst);
|
decoder->moreBytes(pcState, fetchPC, inst);
|
||||||
//else
|
//else
|
||||||
|
@ -414,18 +508,19 @@ BaseSimpleCPU::preExecute()
|
||||||
//fetch beyond the MachInst at the current pc.
|
//fetch beyond the MachInst at the current pc.
|
||||||
instPtr = decoder->decode(pcState);
|
instPtr = decoder->decode(pcState);
|
||||||
if (instPtr) {
|
if (instPtr) {
|
||||||
stayAtPC = false;
|
t_info.stayAtPC = false;
|
||||||
thread->pcState(pcState);
|
thread->pcState(pcState);
|
||||||
} else {
|
} else {
|
||||||
stayAtPC = true;
|
t_info.stayAtPC = true;
|
||||||
fetchOffset += sizeof(MachInst);
|
t_info.fetchOffset += sizeof(MachInst);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we decoded an instruction and it's microcoded, start pulling
|
//If we decoded an instruction and it's microcoded, start pulling
|
||||||
//out micro ops
|
//out micro ops
|
||||||
if (instPtr && instPtr->isMacroop()) {
|
if (instPtr && instPtr->isMacroop()) {
|
||||||
curMacroStaticInst = instPtr;
|
curMacroStaticInst = instPtr;
|
||||||
curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
|
curStaticInst =
|
||||||
|
curMacroStaticInst->fetchMicroop(pcState.microPC());
|
||||||
} else {
|
} else {
|
||||||
curStaticInst = instPtr;
|
curStaticInst = instPtr;
|
||||||
}
|
}
|
||||||
|
@ -437,7 +532,7 @@ BaseSimpleCPU::preExecute()
|
||||||
//If we decoded an instruction this "tick", record information about it.
|
//If we decoded an instruction this "tick", record information about it.
|
||||||
if (curStaticInst) {
|
if (curStaticInst) {
|
||||||
#if TRACING_ON
|
#if TRACING_ON
|
||||||
traceData = tracer->getInstRecord(curTick(), tc,
|
traceData = tracer->getInstRecord(curTick(), thread->getTC(),
|
||||||
curStaticInst, thread->pcState(), curMacroStaticInst);
|
curStaticInst, thread->pcState(), curMacroStaticInst);
|
||||||
|
|
||||||
DPRINTF(Decode,"Decode: Decoded %s instruction: %#x\n",
|
DPRINTF(Decode,"Decode: Decoded %s instruction: %#x\n",
|
||||||
|
@ -445,86 +540,91 @@ BaseSimpleCPU::preExecute()
|
||||||
#endif // TRACING_ON
|
#endif // TRACING_ON
|
||||||
}
|
}
|
||||||
|
|
||||||
if (branchPred && curStaticInst && curStaticInst->isControl()) {
|
if (branchPred && curStaticInst &&
|
||||||
|
curStaticInst->isControl()) {
|
||||||
// Use a fake sequence number since we only have one
|
// Use a fake sequence number since we only have one
|
||||||
// instruction in flight at the same time.
|
// instruction in flight at the same time.
|
||||||
const InstSeqNum cur_sn(0);
|
const InstSeqNum cur_sn(0);
|
||||||
const ThreadID tid(0);
|
t_info.predPC = thread->pcState();
|
||||||
pred_pc = thread->pcState();
|
|
||||||
const bool predict_taken(
|
const bool predict_taken(
|
||||||
branchPred->predict(curStaticInst, cur_sn, pred_pc, tid));
|
branchPred->predict(curStaticInst, cur_sn, t_info.predPC,
|
||||||
|
curThread));
|
||||||
|
|
||||||
if (predict_taken)
|
if (predict_taken)
|
||||||
++numPredictedBranches;
|
++t_info.numPredictedBranches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::postExecute()
|
BaseSimpleCPU::postExecute()
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
assert(curStaticInst);
|
assert(curStaticInst);
|
||||||
|
|
||||||
TheISA::PCState pc = tc->pcState();
|
TheISA::PCState pc = threadContexts[curThread]->pcState();
|
||||||
Addr instAddr = pc.instAddr();
|
Addr instAddr = pc.instAddr();
|
||||||
if (FullSystem && thread->profile) {
|
if (FullSystem && thread->profile) {
|
||||||
bool usermode = TheISA::inUserMode(tc);
|
bool usermode = TheISA::inUserMode(threadContexts[curThread]);
|
||||||
thread->profilePC = usermode ? 1 : instAddr;
|
thread->profilePC = usermode ? 1 : instAddr;
|
||||||
ProfileNode *node = thread->profile->consume(tc, curStaticInst);
|
ProfileNode *node = thread->profile->consume(threadContexts[curThread],
|
||||||
|
curStaticInst);
|
||||||
if (node)
|
if (node)
|
||||||
thread->profileNode = node;
|
thread->profileNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curStaticInst->isMemRef()) {
|
if (curStaticInst->isMemRef()) {
|
||||||
numMemRefs++;
|
t_info.numMemRefs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curStaticInst->isLoad()) {
|
if (curStaticInst->isLoad()) {
|
||||||
++numLoad;
|
++t_info.numLoad;
|
||||||
comLoadEventQueue[0]->serviceEvents(numLoad);
|
comLoadEventQueue[curThread]->serviceEvents(t_info.numLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CPA::available()) {
|
if (CPA::available()) {
|
||||||
CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
|
CPA::cpa()->swAutoBegin(threadContexts[curThread], pc.nextInstAddr());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curStaticInst->isControl()) {
|
if (curStaticInst->isControl()) {
|
||||||
++numBranches;
|
++t_info.numBranches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Power model statistics */
|
/* Power model statistics */
|
||||||
//integer alu accesses
|
//integer alu accesses
|
||||||
if (curStaticInst->isInteger()){
|
if (curStaticInst->isInteger()){
|
||||||
numIntAluAccesses++;
|
t_info.numIntAluAccesses++;
|
||||||
numIntInsts++;
|
t_info.numIntInsts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//float alu accesses
|
//float alu accesses
|
||||||
if (curStaticInst->isFloating()){
|
if (curStaticInst->isFloating()){
|
||||||
numFpAluAccesses++;
|
t_info.numFpAluAccesses++;
|
||||||
numFpInsts++;
|
t_info.numFpInsts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//number of function calls/returns to get window accesses
|
//number of function calls/returns to get window accesses
|
||||||
if (curStaticInst->isCall() || curStaticInst->isReturn()){
|
if (curStaticInst->isCall() || curStaticInst->isReturn()){
|
||||||
numCallsReturns++;
|
t_info.numCallsReturns++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//the number of branch predictions that will be made
|
//the number of branch predictions that will be made
|
||||||
if (curStaticInst->isCondCtrl()){
|
if (curStaticInst->isCondCtrl()){
|
||||||
numCondCtrlInsts++;
|
t_info.numCondCtrlInsts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//result bus acceses
|
//result bus acceses
|
||||||
if (curStaticInst->isLoad()){
|
if (curStaticInst->isLoad()){
|
||||||
numLoadInsts++;
|
t_info.numLoadInsts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curStaticInst->isStore()){
|
if (curStaticInst->isStore()){
|
||||||
numStoreInsts++;
|
t_info.numStoreInsts++;
|
||||||
}
|
}
|
||||||
/* End power model statistics */
|
/* End power model statistics */
|
||||||
|
|
||||||
statExecutedInstType[curStaticInst->opClass()]++;
|
t_info.statExecutedInstType[curStaticInst->opClass()]++;
|
||||||
|
|
||||||
if (FullSystem)
|
if (FullSystem)
|
||||||
traceFunctions(instAddr);
|
traceFunctions(instAddr);
|
||||||
|
@ -542,13 +642,16 @@ BaseSimpleCPU::postExecute()
|
||||||
void
|
void
|
||||||
BaseSimpleCPU::advancePC(const Fault &fault)
|
BaseSimpleCPU::advancePC(const Fault &fault)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
const bool branching(thread->pcState().branching());
|
const bool branching(thread->pcState().branching());
|
||||||
|
|
||||||
//Since we're moving to a new pc, zero out the offset
|
//Since we're moving to a new pc, zero out the offset
|
||||||
fetchOffset = 0;
|
t_info.fetchOffset = 0;
|
||||||
if (fault != NoFault) {
|
if (fault != NoFault) {
|
||||||
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
curMacroStaticInst = StaticInst::nullStaticInstPtr;
|
||||||
fault->invoke(tc, curStaticInst);
|
fault->invoke(threadContexts[curThread], curStaticInst);
|
||||||
thread->decoder.reset();
|
thread->decoder.reset();
|
||||||
} else {
|
} else {
|
||||||
if (curStaticInst) {
|
if (curStaticInst) {
|
||||||
|
@ -564,16 +667,14 @@ BaseSimpleCPU::advancePC(const Fault &fault)
|
||||||
// Use a fake sequence number since we only have one
|
// Use a fake sequence number since we only have one
|
||||||
// instruction in flight at the same time.
|
// instruction in flight at the same time.
|
||||||
const InstSeqNum cur_sn(0);
|
const InstSeqNum cur_sn(0);
|
||||||
const ThreadID tid(0);
|
|
||||||
|
|
||||||
if (pred_pc == thread->pcState()) {
|
if (t_info.predPC == thread->pcState()) {
|
||||||
// Correctly predicted branch
|
// Correctly predicted branch
|
||||||
branchPred->update(cur_sn, tid);
|
branchPred->update(cur_sn, curThread);
|
||||||
} else {
|
} else {
|
||||||
// Mis-predicted branch
|
// Mis-predicted branch
|
||||||
branchPred->squash(cur_sn, pcState(),
|
branchPred->squash(cur_sn, thread->pcState(), branching, curThread);
|
||||||
branching, tid);
|
++t_info.numBranchMispred;
|
||||||
++numBranchMispred;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -582,5 +683,6 @@ void
|
||||||
BaseSimpleCPU::startup()
|
BaseSimpleCPU::startup()
|
||||||
{
|
{
|
||||||
BaseCPU::startup();
|
BaseCPU::startup();
|
||||||
thread->startup();
|
for (auto& t_info : threadInfo)
|
||||||
|
t_info->thread->startup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2012 ARM Limited
|
* Copyright (c) 2011-2012,2015 ARM Limited
|
||||||
* Copyright (c) 2013 Advanced Micro Devices, Inc.
|
* Copyright (c) 2013 Advanced Micro Devices, Inc.
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
|
@ -79,57 +79,35 @@ namespace Trace {
|
||||||
|
|
||||||
struct BaseSimpleCPUParams;
|
struct BaseSimpleCPUParams;
|
||||||
class BPredUnit;
|
class BPredUnit;
|
||||||
|
class SimpleExecContext;
|
||||||
|
|
||||||
class BaseSimpleCPU : public BaseCPU, public ExecContext
|
class BaseSimpleCPU : public BaseCPU
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef TheISA::MiscReg MiscReg;
|
ThreadID curThread;
|
||||||
typedef TheISA::FloatReg FloatReg;
|
|
||||||
typedef TheISA::FloatRegBits FloatRegBits;
|
|
||||||
typedef TheISA::CCReg CCReg;
|
|
||||||
|
|
||||||
BPredUnit *branchPred;
|
BPredUnit *branchPred;
|
||||||
|
|
||||||
protected:
|
void checkPcEventQueue();
|
||||||
Trace::InstRecord *traceData;
|
void swapActiveThread();
|
||||||
|
|
||||||
inline void checkPcEventQueue() {
|
|
||||||
Addr oldpc, pc = thread->instAddr();
|
|
||||||
do {
|
|
||||||
oldpc = pc;
|
|
||||||
system->pcEventQueue.service(tc);
|
|
||||||
pc = thread->instAddr();
|
|
||||||
} while (oldpc != pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void wakeup();
|
|
||||||
|
|
||||||
void zero_fill_64(Addr addr) {
|
|
||||||
static int warned = 0;
|
|
||||||
if (!warned) {
|
|
||||||
warn ("WH64 is not implemented");
|
|
||||||
warned = 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseSimpleCPU(BaseSimpleCPUParams *params);
|
BaseSimpleCPU(BaseSimpleCPUParams *params);
|
||||||
virtual ~BaseSimpleCPU();
|
virtual ~BaseSimpleCPU();
|
||||||
|
void wakeup();
|
||||||
|
virtual void init();
|
||||||
public:
|
public:
|
||||||
/** SimpleThread object, provides all the architectural state. */
|
Trace::InstRecord *traceData;
|
||||||
SimpleThread *thread;
|
|
||||||
|
|
||||||
/** ThreadContext object, provides an interface for external
|
|
||||||
* objects to modify this thread's state.
|
|
||||||
*/
|
|
||||||
ThreadContext *tc;
|
|
||||||
|
|
||||||
CheckerCPU *checker;
|
CheckerCPU *checker;
|
||||||
|
|
||||||
protected:
|
std::vector<SimpleExecContext*> threadInfo;
|
||||||
|
std::list<ThreadID> activeThreads;
|
||||||
|
|
||||||
|
/** Current instruction */
|
||||||
|
TheISA::MachInst inst;
|
||||||
|
StaticInstPtr curStaticInst;
|
||||||
|
StaticInstPtr curMacroStaticInst;
|
||||||
|
|
||||||
|
protected:
|
||||||
enum Status {
|
enum Status {
|
||||||
Idle,
|
Idle,
|
||||||
Running,
|
Running,
|
||||||
|
@ -147,22 +125,8 @@ class BaseSimpleCPU : public BaseCPU, public ExecContext
|
||||||
Status _status;
|
Status _status;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Addr dbg_vtophys(Addr addr);
|
Addr dbg_vtophys(Addr addr);
|
||||||
|
|
||||||
bool interval_stats;
|
|
||||||
|
|
||||||
// current instruction
|
|
||||||
TheISA::MachInst inst;
|
|
||||||
|
|
||||||
StaticInstPtr curStaticInst;
|
|
||||||
StaticInstPtr curMacroStaticInst;
|
|
||||||
|
|
||||||
//This is the offset from the current pc that fetch should be performed at
|
|
||||||
Addr fetchOffset;
|
|
||||||
//This flag says to stay at the current pc. This is useful for
|
|
||||||
//instructions which go beyond MachInst boundaries.
|
|
||||||
bool stayAtPC;
|
|
||||||
|
|
||||||
void checkForInterrupts();
|
void checkForInterrupts();
|
||||||
void setupFetchRequest(Request *req);
|
void setupFetchRequest(Request *req);
|
||||||
|
@ -178,289 +142,20 @@ class BaseSimpleCPU : public BaseCPU, public ExecContext
|
||||||
|
|
||||||
virtual void startup();
|
virtual void startup();
|
||||||
|
|
||||||
// number of simulated instructions
|
virtual Fault readMem(Addr addr, uint8_t* data, unsigned size,
|
||||||
Counter numInst;
|
unsigned flags) = 0;
|
||||||
Counter startNumInst;
|
|
||||||
Stats::Scalar numInsts;
|
|
||||||
Counter numOp;
|
|
||||||
Counter startNumOp;
|
|
||||||
Stats::Scalar numOps;
|
|
||||||
|
|
||||||
void countInst()
|
virtual Fault writeMem(uint8_t* data, unsigned size, Addr addr,
|
||||||
{
|
unsigned flags, uint64_t* res) = 0;
|
||||||
if (!curStaticInst->isMicroop() || curStaticInst->isLastMicroop()) {
|
|
||||||
numInst++;
|
|
||||||
numInsts++;
|
|
||||||
}
|
|
||||||
numOp++;
|
|
||||||
numOps++;
|
|
||||||
|
|
||||||
system->totalNumInsts++;
|
void countInst();
|
||||||
thread->funcExeInst++;
|
virtual Counter totalInsts() const;
|
||||||
}
|
virtual Counter totalOps() const;
|
||||||
|
|
||||||
virtual Counter totalInsts() const
|
|
||||||
{
|
|
||||||
return numInst - startNumInst;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Counter totalOps() const
|
|
||||||
{
|
|
||||||
return numOp - startNumOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//number of integer alu accesses
|
|
||||||
Stats::Scalar numIntAluAccesses;
|
|
||||||
|
|
||||||
//number of float alu accesses
|
|
||||||
Stats::Scalar numFpAluAccesses;
|
|
||||||
|
|
||||||
//number of function calls/returns
|
|
||||||
Stats::Scalar numCallsReturns;
|
|
||||||
|
|
||||||
//conditional control instructions;
|
|
||||||
Stats::Scalar numCondCtrlInsts;
|
|
||||||
|
|
||||||
//number of int instructions
|
|
||||||
Stats::Scalar numIntInsts;
|
|
||||||
|
|
||||||
//number of float instructions
|
|
||||||
Stats::Scalar numFpInsts;
|
|
||||||
|
|
||||||
//number of integer register file accesses
|
|
||||||
Stats::Scalar numIntRegReads;
|
|
||||||
Stats::Scalar numIntRegWrites;
|
|
||||||
|
|
||||||
//number of float register file accesses
|
|
||||||
Stats::Scalar numFpRegReads;
|
|
||||||
Stats::Scalar numFpRegWrites;
|
|
||||||
|
|
||||||
//number of condition code register file accesses
|
|
||||||
Stats::Scalar numCCRegReads;
|
|
||||||
Stats::Scalar numCCRegWrites;
|
|
||||||
|
|
||||||
// number of simulated memory references
|
|
||||||
Stats::Scalar numMemRefs;
|
|
||||||
Stats::Scalar numLoadInsts;
|
|
||||||
Stats::Scalar numStoreInsts;
|
|
||||||
|
|
||||||
// number of idle cycles
|
|
||||||
Stats::Formula numIdleCycles;
|
|
||||||
|
|
||||||
// number of busy cycles
|
|
||||||
Stats::Formula numBusyCycles;
|
|
||||||
|
|
||||||
// number of simulated loads
|
|
||||||
Counter numLoad;
|
|
||||||
Counter startNumLoad;
|
|
||||||
|
|
||||||
// number of idle cycles
|
|
||||||
Stats::Average notIdleFraction;
|
|
||||||
Stats::Formula idleFraction;
|
|
||||||
|
|
||||||
// number of cycles stalled for I-cache responses
|
|
||||||
Stats::Scalar icacheStallCycles;
|
|
||||||
Counter lastIcacheStall;
|
|
||||||
|
|
||||||
// number of cycles stalled for D-cache responses
|
|
||||||
Stats::Scalar dcacheStallCycles;
|
|
||||||
Counter lastDcacheStall;
|
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// Total number of branches fetched
|
|
||||||
Stats::Scalar numBranches;
|
|
||||||
/// Number of branches predicted as taken
|
|
||||||
Stats::Scalar numPredictedBranches;
|
|
||||||
/// Number of misprediced branches
|
|
||||||
Stats::Scalar numBranchMispred;
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
// instruction mix histogram by OpClass
|
|
||||||
Stats::Vector statExecutedInstType;
|
|
||||||
|
|
||||||
void serializeThread(CheckpointOut &cp,
|
void serializeThread(CheckpointOut &cp,
|
||||||
ThreadID tid) const M5_ATTR_OVERRIDE;
|
ThreadID tid) const M5_ATTR_OVERRIDE;
|
||||||
void unserializeThread(CheckpointIn &cp, ThreadID tid) M5_ATTR_OVERRIDE;
|
void unserializeThread(CheckpointIn &cp, ThreadID tid) M5_ATTR_OVERRIDE;
|
||||||
|
|
||||||
// These functions are only used in CPU models that split
|
|
||||||
// effective address computation from the actual memory access.
|
|
||||||
void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); }
|
|
||||||
Addr getEA() const { panic("BaseSimpleCPU::getEA() not implemented\n"); }
|
|
||||||
|
|
||||||
// The register accessor methods provide the index of the
|
|
||||||
// instruction's operand (e.g., 0 or 1), not the architectural
|
|
||||||
// register index, to simplify the implementation of register
|
|
||||||
// renaming. We find the architectural register index by indexing
|
|
||||||
// into the instruction's own operand index table. Note that a
|
|
||||||
// raw pointer to the StaticInst is provided instead of a
|
|
||||||
// ref-counted StaticInstPtr to redice overhead. This is fine as
|
|
||||||
// long as these methods don't copy the pointer into any long-term
|
|
||||||
// storage (which is pretty hard to imagine they would have reason
|
|
||||||
// to do).
|
|
||||||
|
|
||||||
IntReg readIntRegOperand(const StaticInst *si, int idx)
|
|
||||||
{
|
|
||||||
numIntRegReads++;
|
|
||||||
return thread->readIntReg(si->srcRegIdx(idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
|
||||||
{
|
|
||||||
numFpRegReads++;
|
|
||||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Reg_Base;
|
|
||||||
return thread->readFloatReg(reg_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
|
||||||
{
|
|
||||||
numFpRegReads++;
|
|
||||||
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Reg_Base;
|
|
||||||
return thread->readFloatRegBits(reg_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCReg readCCRegOperand(const StaticInst *si, int idx)
|
|
||||||
{
|
|
||||||
numCCRegReads++;
|
|
||||||
int reg_idx = si->srcRegIdx(idx) - TheISA::CC_Reg_Base;
|
|
||||||
return thread->readCCReg(reg_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
|
|
||||||
{
|
|
||||||
numIntRegWrites++;
|
|
||||||
thread->setIntReg(si->destRegIdx(idx), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
|
||||||
{
|
|
||||||
numFpRegWrites++;
|
|
||||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Reg_Base;
|
|
||||||
thread->setFloatReg(reg_idx, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
|
||||||
FloatRegBits val)
|
|
||||||
{
|
|
||||||
numFpRegWrites++;
|
|
||||||
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Reg_Base;
|
|
||||||
thread->setFloatRegBits(reg_idx, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCCRegOperand(const StaticInst *si, int idx, CCReg val)
|
|
||||||
{
|
|
||||||
numCCRegWrites++;
|
|
||||||
int reg_idx = si->destRegIdx(idx) - TheISA::CC_Reg_Base;
|
|
||||||
thread->setCCReg(reg_idx, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool readPredicate() { return thread->readPredicate(); }
|
|
||||||
void setPredicate(bool val)
|
|
||||||
{
|
|
||||||
thread->setPredicate(val);
|
|
||||||
if (traceData) {
|
|
||||||
traceData->setPredicate(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TheISA::PCState pcState() const { return thread->pcState(); }
|
|
||||||
void pcState(const TheISA::PCState &val) { thread->pcState(val); }
|
|
||||||
Addr instAddr() { return thread->instAddr(); }
|
|
||||||
Addr nextInstAddr() { return thread->nextInstAddr(); }
|
|
||||||
MicroPC microPC() { return thread->microPC(); }
|
|
||||||
|
|
||||||
MiscReg readMiscRegNoEffect(int misc_reg) const
|
|
||||||
{
|
|
||||||
return thread->readMiscRegNoEffect(misc_reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
MiscReg readMiscReg(int misc_reg)
|
|
||||||
{
|
|
||||||
numIntRegReads++;
|
|
||||||
return thread->readMiscReg(misc_reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMiscReg(int misc_reg, const MiscReg &val)
|
|
||||||
{
|
|
||||||
numIntRegWrites++;
|
|
||||||
return thread->setMiscReg(misc_reg, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
MiscReg readMiscRegOperand(const StaticInst *si, int idx)
|
|
||||||
{
|
|
||||||
numIntRegReads++;
|
|
||||||
int reg_idx = si->srcRegIdx(idx) - TheISA::Misc_Reg_Base;
|
|
||||||
return thread->readMiscReg(reg_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMiscRegOperand(
|
|
||||||
const StaticInst *si, int idx, const MiscReg &val)
|
|
||||||
{
|
|
||||||
numIntRegWrites++;
|
|
||||||
int reg_idx = si->destRegIdx(idx) - TheISA::Misc_Reg_Base;
|
|
||||||
return thread->setMiscReg(reg_idx, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void demapPage(Addr vaddr, uint64_t asn)
|
|
||||||
{
|
|
||||||
thread->demapPage(vaddr, asn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void demapInstPage(Addr vaddr, uint64_t asn)
|
|
||||||
{
|
|
||||||
thread->demapInstPage(vaddr, asn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void demapDataPage(Addr vaddr, uint64_t asn)
|
|
||||||
{
|
|
||||||
thread->demapDataPage(vaddr, asn);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int readStCondFailures() const {
|
|
||||||
return thread->readStCondFailures();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setStCondFailures(unsigned int sc_failures) {
|
|
||||||
thread->setStCondFailures(sc_failures);
|
|
||||||
}
|
|
||||||
|
|
||||||
MiscReg readRegOtherThread(int regIdx, ThreadID tid = InvalidThreadID)
|
|
||||||
{
|
|
||||||
panic("Simple CPU models do not support multithreaded "
|
|
||||||
"register access.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRegOtherThread(int regIdx, MiscReg val,
|
|
||||||
ThreadID tid = InvalidThreadID)
|
|
||||||
{
|
|
||||||
panic("Simple CPU models do not support multithreaded "
|
|
||||||
"register access.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fault CacheOp(uint8_t Op, Addr EA);
|
|
||||||
|
|
||||||
Fault hwrei() { return thread->hwrei(); }
|
|
||||||
bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
|
|
||||||
|
|
||||||
void
|
|
||||||
syscall(int64_t callnum)
|
|
||||||
{
|
|
||||||
if (FullSystem)
|
|
||||||
panic("Syscall emulation isn't available in FS mode.\n");
|
|
||||||
|
|
||||||
thread->syscall(callnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadContext *tcBase() { return tc; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
TheISA::PCState pred_pc;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// monitor/mwait funtions
|
|
||||||
void armMonitor(Addr address) { BaseCPU::armMonitor(address); }
|
|
||||||
bool mwait(PacketPtr pkt) { return BaseCPU::mwait(pkt); }
|
|
||||||
void mwaitAtomic(ThreadContext *tc)
|
|
||||||
{ return BaseCPU::mwaitAtomic(tc, thread->dtb); }
|
|
||||||
AddressMonitor *getAddrMonitor() { return BaseCPU::getCpuAddrMonitor(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __CPU_SIMPLE_BASE_HH__
|
#endif // __CPU_SIMPLE_BASE_HH__
|
||||||
|
|
416
src/cpu/simple/exec_context.hh
Normal file
416
src/cpu/simple/exec_context.hh
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014-2015 ARM Limited
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* The license below extends only to copyright in the software and shall
|
||||||
|
* not be construed as granting a license to any other intellectual
|
||||||
|
* property including but not limited to intellectual property relating
|
||||||
|
* to a hardware implementation of the functionality of the software
|
||||||
|
* licensed hereunder. You may use the software subject to the license
|
||||||
|
* terms below provided that you ensure that this notice is replicated
|
||||||
|
* unmodified and in its entirety in all distributions of the software,
|
||||||
|
* modified or unmodified, in source code or in binary form.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Authors: Kevin Lim
|
||||||
|
* Andreas Sandberg
|
||||||
|
* Mitch Hayenga
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CPU_SIMPLE_EXEC_CONTEXT_HH__
|
||||||
|
#define __CPU_SIMPLE_EXEC_CONTEXT_HH__
|
||||||
|
|
||||||
|
#include "arch/registers.hh"
|
||||||
|
#include "base/types.hh"
|
||||||
|
#include "config/the_isa.hh"
|
||||||
|
#include "cpu/base.hh"
|
||||||
|
#include "cpu/exec_context.hh"
|
||||||
|
#include "cpu/simple/base.hh"
|
||||||
|
#include "cpu/static_inst_fwd.hh"
|
||||||
|
#include "cpu/translation.hh"
|
||||||
|
|
||||||
|
class BaseSimpleCPU;
|
||||||
|
|
||||||
|
class SimpleExecContext : public ExecContext {
|
||||||
|
protected:
|
||||||
|
typedef TheISA::MiscReg MiscReg;
|
||||||
|
typedef TheISA::FloatReg FloatReg;
|
||||||
|
typedef TheISA::FloatRegBits FloatRegBits;
|
||||||
|
typedef TheISA::CCReg CCReg;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BaseSimpleCPU *cpu;
|
||||||
|
SimpleThread* thread;
|
||||||
|
|
||||||
|
// This is the offset from the current pc that fetch should be performed
|
||||||
|
Addr fetchOffset;
|
||||||
|
// This flag says to stay at the current pc. This is useful for
|
||||||
|
// instructions which go beyond MachInst boundaries.
|
||||||
|
bool stayAtPC;
|
||||||
|
|
||||||
|
// Branch prediction
|
||||||
|
TheISA::PCState predPC;
|
||||||
|
|
||||||
|
/** PER-THREAD STATS */
|
||||||
|
|
||||||
|
// Number of simulated instructions
|
||||||
|
Counter numInst;
|
||||||
|
Stats::Scalar numInsts;
|
||||||
|
Counter numOp;
|
||||||
|
Stats::Scalar numOps;
|
||||||
|
|
||||||
|
// Number of integer alu accesses
|
||||||
|
Stats::Scalar numIntAluAccesses;
|
||||||
|
|
||||||
|
// Number of float alu accesses
|
||||||
|
Stats::Scalar numFpAluAccesses;
|
||||||
|
|
||||||
|
// Number of function calls/returns
|
||||||
|
Stats::Scalar numCallsReturns;
|
||||||
|
|
||||||
|
// Conditional control instructions;
|
||||||
|
Stats::Scalar numCondCtrlInsts;
|
||||||
|
|
||||||
|
// Number of int instructions
|
||||||
|
Stats::Scalar numIntInsts;
|
||||||
|
|
||||||
|
// Number of float instructions
|
||||||
|
Stats::Scalar numFpInsts;
|
||||||
|
|
||||||
|
// Number of integer register file accesses
|
||||||
|
Stats::Scalar numIntRegReads;
|
||||||
|
Stats::Scalar numIntRegWrites;
|
||||||
|
|
||||||
|
// Number of float register file accesses
|
||||||
|
Stats::Scalar numFpRegReads;
|
||||||
|
Stats::Scalar numFpRegWrites;
|
||||||
|
|
||||||
|
// Number of condition code register file accesses
|
||||||
|
Stats::Scalar numCCRegReads;
|
||||||
|
Stats::Scalar numCCRegWrites;
|
||||||
|
|
||||||
|
// Number of simulated memory references
|
||||||
|
Stats::Scalar numMemRefs;
|
||||||
|
Stats::Scalar numLoadInsts;
|
||||||
|
Stats::Scalar numStoreInsts;
|
||||||
|
|
||||||
|
// Number of idle cycles
|
||||||
|
Stats::Formula numIdleCycles;
|
||||||
|
|
||||||
|
// Number of busy cycles
|
||||||
|
Stats::Formula numBusyCycles;
|
||||||
|
|
||||||
|
// Number of simulated loads
|
||||||
|
Counter numLoad;
|
||||||
|
|
||||||
|
// Number of idle cycles
|
||||||
|
Stats::Average notIdleFraction;
|
||||||
|
Stats::Formula idleFraction;
|
||||||
|
|
||||||
|
// Number of cycles stalled for I-cache responses
|
||||||
|
Stats::Scalar icacheStallCycles;
|
||||||
|
Counter lastIcacheStall;
|
||||||
|
|
||||||
|
// Number of cycles stalled for D-cache responses
|
||||||
|
Stats::Scalar dcacheStallCycles;
|
||||||
|
Counter lastDcacheStall;
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// Total number of branches fetched
|
||||||
|
Stats::Scalar numBranches;
|
||||||
|
/// Number of branches predicted as taken
|
||||||
|
Stats::Scalar numPredictedBranches;
|
||||||
|
/// Number of misprediced branches
|
||||||
|
Stats::Scalar numBranchMispred;
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Instruction mix histogram by OpClass
|
||||||
|
Stats::Vector statExecutedInstType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor */
|
||||||
|
SimpleExecContext(BaseSimpleCPU* _cpu, SimpleThread* _thread)
|
||||||
|
: cpu(_cpu), thread(_thread), fetchOffset(0), stayAtPC(false),
|
||||||
|
numInst(0), numOp(0), numLoad(0), lastIcacheStall(0), lastDcacheStall(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/** Reads an integer register. */
|
||||||
|
IntReg readIntRegOperand(const StaticInst *si, int idx) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegReads++;
|
||||||
|
return thread->readIntReg(si->srcRegIdx(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets an integer register to a value. */
|
||||||
|
void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegWrites++;
|
||||||
|
thread->setIntReg(si->destRegIdx(idx), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reads a floating point register of single register width. */
|
||||||
|
FloatReg readFloatRegOperand(const StaticInst *si, int idx)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numFpRegReads++;
|
||||||
|
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Reg_Base;
|
||||||
|
return thread->readFloatReg(reg_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reads a floating point register in its binary format, instead
|
||||||
|
* of by value. */
|
||||||
|
FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numFpRegReads++;
|
||||||
|
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Reg_Base;
|
||||||
|
return thread->readFloatRegBits(reg_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets a floating point register of single width to a value. */
|
||||||
|
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numFpRegWrites++;
|
||||||
|
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Reg_Base;
|
||||||
|
thread->setFloatReg(reg_idx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the bits of a floating point register of single width
|
||||||
|
* to a binary value. */
|
||||||
|
void setFloatRegOperandBits(const StaticInst *si, int idx,
|
||||||
|
FloatRegBits val) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numFpRegWrites++;
|
||||||
|
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Reg_Base;
|
||||||
|
thread->setFloatRegBits(reg_idx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCReg readCCRegOperand(const StaticInst *si, int idx) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numCCRegReads++;
|
||||||
|
int reg_idx = si->srcRegIdx(idx) - TheISA::CC_Reg_Base;
|
||||||
|
return thread->readCCReg(reg_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCCRegOperand(const StaticInst *si, int idx, CCReg val)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numCCRegWrites++;
|
||||||
|
int reg_idx = si->destRegIdx(idx) - TheISA::CC_Reg_Base;
|
||||||
|
thread->setCCReg(reg_idx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
MiscReg readMiscRegOperand(const StaticInst *si, int idx) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegReads++;
|
||||||
|
int reg_idx = si->srcRegIdx(idx) - TheISA::Misc_Reg_Base;
|
||||||
|
return thread->readMiscReg(reg_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegWrites++;
|
||||||
|
int reg_idx = si->destRegIdx(idx) - TheISA::Misc_Reg_Base;
|
||||||
|
thread->setMiscReg(reg_idx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a miscellaneous register, handling any architectural
|
||||||
|
* side effects due to reading that register.
|
||||||
|
*/
|
||||||
|
MiscReg readMiscReg(int misc_reg) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegReads++;
|
||||||
|
return thread->readMiscReg(misc_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a miscellaneous register, handling any architectural
|
||||||
|
* side effects due to writing that register.
|
||||||
|
*/
|
||||||
|
void setMiscReg(int misc_reg, const MiscReg &val) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
numIntRegWrites++;
|
||||||
|
thread->setMiscReg(misc_reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
PCState pcState() const M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->pcState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcState(const PCState &val) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
thread->pcState(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record the effective address of the instruction.
|
||||||
|
*
|
||||||
|
* @note Only valid for memory ops.
|
||||||
|
*/
|
||||||
|
void setEA(Addr EA) M5_ATTR_OVERRIDE
|
||||||
|
{ panic("BaseSimpleCPU::setEA() not implemented\n"); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the effective address of the instruction.
|
||||||
|
*
|
||||||
|
* @note Only valid for memory ops.
|
||||||
|
*/
|
||||||
|
Addr getEA() const M5_ATTR_OVERRIDE
|
||||||
|
{ panic("BaseSimpleCPU::getEA() not implemented\n"); }
|
||||||
|
|
||||||
|
Fault readMem(Addr addr, uint8_t *data, unsigned int size,
|
||||||
|
unsigned int flags) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return cpu->readMem(addr, data, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fault writeMem(uint8_t *data, unsigned int size, Addr addr,
|
||||||
|
unsigned int flags, uint64_t *res) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return cpu->writeMem(data, size, addr, flags, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of consecutive store conditional failures.
|
||||||
|
*/
|
||||||
|
void setStCondFailures(unsigned int sc_failures) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
thread->setStCondFailures(sc_failures);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of consecutive store conditional failures.
|
||||||
|
*/
|
||||||
|
unsigned int readStCondFailures() const M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->readStCondFailures();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a syscall specified by the callnum.
|
||||||
|
*/
|
||||||
|
void syscall(int64_t callnum) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
if (FullSystem)
|
||||||
|
panic("Syscall emulation isn't available in FS mode.");
|
||||||
|
|
||||||
|
thread->syscall(callnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the ThreadContext. */
|
||||||
|
ThreadContext *tcBase() M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->getTC();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Somewhat Alpha-specific function that handles returning from an
|
||||||
|
* error or interrupt.
|
||||||
|
*/
|
||||||
|
Fault hwrei() M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->hwrei();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for special simulator handling of specific PAL calls. If
|
||||||
|
* return value is false, actual PAL call will be suppressed.
|
||||||
|
*/
|
||||||
|
bool simPalCheck(int palFunc) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->simPalCheck(palFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readPredicate() M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return thread->readPredicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPredicate(bool val) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
thread->setPredicate(val);
|
||||||
|
|
||||||
|
if (cpu->traceData) {
|
||||||
|
cpu->traceData->setPredicate(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate a page in the DTLB <i>and</i> ITLB.
|
||||||
|
*/
|
||||||
|
void demapPage(Addr vaddr, uint64_t asn) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
thread->demapPage(vaddr, asn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void armMonitor(Addr address) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
cpu->armMonitor(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mwait(PacketPtr pkt) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return cpu->mwait(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mwaitAtomic(ThreadContext *tc) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
cpu->mwaitAtomic(tc, thread->dtb);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressMonitor *getAddrMonitor() M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
return cpu->getCpuAddrMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if THE_ISA == MIPS_ISA
|
||||||
|
MiscReg readRegOtherThread(int regIdx, ThreadID tid = InvalidThreadID)
|
||||||
|
M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
panic("Simple CPU models do not support multithreaded "
|
||||||
|
"register access.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRegOtherThread(int regIdx, MiscReg val,
|
||||||
|
ThreadID tid = InvalidThreadID) M5_ATTR_OVERRIDE
|
||||||
|
{
|
||||||
|
panic("Simple CPU models do not support multithreaded "
|
||||||
|
"register access.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CPU_EXEC_CONTEXT_HH__
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Google, Inc.
|
* Copyright 2014 Google, Inc.
|
||||||
* Copyright (c) 2010-2013 ARM Limited
|
* Copyright (c) 2010-2013,2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -67,18 +67,7 @@ using namespace TheISA;
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::init()
|
TimingSimpleCPU::init()
|
||||||
{
|
{
|
||||||
BaseCPU::init();
|
BaseSimpleCPU::init();
|
||||||
|
|
||||||
// Initialise the ThreadContext's memory proxies
|
|
||||||
tcBase()->initMemProxies(tcBase());
|
|
||||||
|
|
||||||
if (FullSystem && !params()->switched_out) {
|
|
||||||
for (int i = 0; i < threadContexts.size(); ++i) {
|
|
||||||
ThreadContext *tc = threadContexts[i];
|
|
||||||
// initialize CPU, including PC
|
|
||||||
TheISA::initCPU(tc, _cpuId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -111,9 +100,10 @@ TimingSimpleCPU::drain()
|
||||||
if (_status == Idle ||
|
if (_status == Idle ||
|
||||||
(_status == BaseSimpleCPU::Running && isDrained())) {
|
(_status == BaseSimpleCPU::Running && isDrained())) {
|
||||||
DPRINTF(Drain, "No need to drain.\n");
|
DPRINTF(Drain, "No need to drain.\n");
|
||||||
|
activeThreads.clear();
|
||||||
return DrainState::Drained;
|
return DrainState::Drained;
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(Drain, "Requesting drain: %s\n", pcState());
|
DPRINTF(Drain, "Requesting drain.\n");
|
||||||
|
|
||||||
// The fetch event can become descheduled if a drain didn't
|
// The fetch event can become descheduled if a drain didn't
|
||||||
// succeed on the first attempt. We need to reschedule it if
|
// succeed on the first attempt. We need to reschedule it if
|
||||||
|
@ -136,17 +126,27 @@ TimingSimpleCPU::drainResume()
|
||||||
verifyMemoryMode();
|
verifyMemoryMode();
|
||||||
|
|
||||||
assert(!threadContexts.empty());
|
assert(!threadContexts.empty());
|
||||||
if (threadContexts.size() > 1)
|
|
||||||
fatal("The timing CPU only supports one thread.\n");
|
|
||||||
|
|
||||||
if (thread->status() == ThreadContext::Active) {
|
_status = BaseSimpleCPU::Idle;
|
||||||
schedule(fetchEvent, nextCycle());
|
|
||||||
_status = BaseSimpleCPU::Running;
|
for (ThreadID tid = 0; tid < numThreads; tid++) {
|
||||||
notIdleFraction = 1;
|
if (threadInfo[tid]->thread->status() == ThreadContext::Active) {
|
||||||
} else {
|
threadInfo[tid]->notIdleFraction = 1;
|
||||||
_status = BaseSimpleCPU::Idle;
|
|
||||||
notIdleFraction = 0;
|
activeThreads.push_back(tid);
|
||||||
|
|
||||||
|
_status = BaseSimpleCPU::Running;
|
||||||
|
|
||||||
|
// Fetch if any threads active
|
||||||
|
if (!fetchEvent.scheduled()) {
|
||||||
|
schedule(fetchEvent, nextCycle());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
threadInfo[tid]->notIdleFraction = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
system->totalNumInsts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -155,7 +155,7 @@ TimingSimpleCPU::tryCompleteDrain()
|
||||||
if (drainState() != DrainState::Draining)
|
if (drainState() != DrainState::Draining)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
|
DPRINTF(Drain, "tryCompleteDrain.\n");
|
||||||
if (!isDrained())
|
if (!isDrained())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -168,12 +168,15 @@ TimingSimpleCPU::tryCompleteDrain()
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::switchOut()
|
TimingSimpleCPU::switchOut()
|
||||||
{
|
{
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
M5_VAR_USED SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
BaseSimpleCPU::switchOut();
|
BaseSimpleCPU::switchOut();
|
||||||
|
|
||||||
assert(!fetchEvent.scheduled());
|
assert(!fetchEvent.scheduled());
|
||||||
assert(_status == BaseSimpleCPU::Running || _status == Idle);
|
assert(_status == BaseSimpleCPU::Running || _status == Idle);
|
||||||
assert(!stayAtPC);
|
assert(!t_info.stayAtPC);
|
||||||
assert(microPC() == 0);
|
assert(thread->microPC() == 0);
|
||||||
|
|
||||||
updateCycleCounts();
|
updateCycleCounts();
|
||||||
}
|
}
|
||||||
|
@ -201,16 +204,20 @@ TimingSimpleCPU::activateContext(ThreadID thread_num)
|
||||||
{
|
{
|
||||||
DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
|
DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
|
||||||
|
|
||||||
assert(thread_num == 0);
|
assert(thread_num < numThreads);
|
||||||
assert(thread);
|
|
||||||
|
|
||||||
assert(_status == Idle);
|
threadInfo[thread_num]->notIdleFraction = 1;
|
||||||
|
if (_status == BaseSimpleCPU::Idle)
|
||||||
notIdleFraction = 1;
|
_status = BaseSimpleCPU::Running;
|
||||||
_status = BaseSimpleCPU::Running;
|
|
||||||
|
|
||||||
// kick things off by initiating the fetch of the next instruction
|
// kick things off by initiating the fetch of the next instruction
|
||||||
schedule(fetchEvent, clockEdge(Cycles(0)));
|
if (!fetchEvent.scheduled())
|
||||||
|
schedule(fetchEvent, clockEdge(Cycles(0)));
|
||||||
|
|
||||||
|
if (std::find(activeThreads.begin(), activeThreads.end(), thread_num)
|
||||||
|
== activeThreads.end()) {
|
||||||
|
activeThreads.push_back(thread_num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -219,24 +226,31 @@ TimingSimpleCPU::suspendContext(ThreadID thread_num)
|
||||||
{
|
{
|
||||||
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
|
||||||
|
|
||||||
assert(thread_num == 0);
|
assert(thread_num < numThreads);
|
||||||
assert(thread);
|
activeThreads.remove(thread_num);
|
||||||
|
|
||||||
if (_status == Idle)
|
if (_status == Idle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(_status == BaseSimpleCPU::Running);
|
assert(_status == BaseSimpleCPU::Running);
|
||||||
|
|
||||||
// just change status to Idle... if status != Running,
|
threadInfo[thread_num]->notIdleFraction = 0;
|
||||||
// completeInst() will not initiate fetch of next instruction.
|
|
||||||
|
|
||||||
notIdleFraction = 0;
|
if (activeThreads.empty()) {
|
||||||
_status = Idle;
|
_status = Idle;
|
||||||
|
|
||||||
|
if (fetchEvent.scheduled()) {
|
||||||
|
deschedule(fetchEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
|
TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
RequestPtr req = pkt->req;
|
RequestPtr req = pkt->req;
|
||||||
|
|
||||||
// We're about the issues a locked load, so tell the monitor
|
// We're about the issues a locked load, so tell the monitor
|
||||||
|
@ -264,6 +278,9 @@ void
|
||||||
TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
|
TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
|
||||||
bool read)
|
bool read)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
PacketPtr pkt = buildPacket(req, read);
|
PacketPtr pkt = buildPacket(req, read);
|
||||||
pkt->dataDynamic<uint8_t>(data);
|
pkt->dataDynamic<uint8_t>(data);
|
||||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||||
|
@ -389,9 +406,12 @@ Fault
|
||||||
TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
|
TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
|
||||||
unsigned size, unsigned flags)
|
unsigned size, unsigned flags)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
Fault fault;
|
Fault fault;
|
||||||
const int asid = 0;
|
const int asid = 0;
|
||||||
const ThreadID tid = 0;
|
const ThreadID tid = curThread;
|
||||||
const Addr pc = thread->instAddr();
|
const Addr pc = thread->instAddr();
|
||||||
unsigned block_size = cacheLineSize();
|
unsigned block_size = cacheLineSize();
|
||||||
BaseTLB::Mode mode = BaseTLB::Read;
|
BaseTLB::Mode mode = BaseTLB::Read;
|
||||||
|
@ -400,7 +420,8 @@ TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
|
||||||
traceData->setMem(addr, size, flags);
|
traceData->setMem(addr, size, flags);
|
||||||
|
|
||||||
RequestPtr req = new Request(asid, addr, size,
|
RequestPtr req = new Request(asid, addr, size,
|
||||||
flags, dataMasterId(), pc, _cpuId, tid);
|
flags, dataMasterId(), pc,
|
||||||
|
thread->contextId(), tid);
|
||||||
|
|
||||||
req->taskId(taskId());
|
req->taskId(taskId());
|
||||||
|
|
||||||
|
@ -421,14 +442,14 @@ TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
|
||||||
DataTranslation<TimingSimpleCPU *> *trans2 =
|
DataTranslation<TimingSimpleCPU *> *trans2 =
|
||||||
new DataTranslation<TimingSimpleCPU *>(this, state, 1);
|
new DataTranslation<TimingSimpleCPU *>(this, state, 1);
|
||||||
|
|
||||||
thread->dtb->translateTiming(req1, tc, trans1, mode);
|
thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode);
|
||||||
thread->dtb->translateTiming(req2, tc, trans2, mode);
|
thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode);
|
||||||
} else {
|
} else {
|
||||||
WholeTranslationState *state =
|
WholeTranslationState *state =
|
||||||
new WholeTranslationState(req, new uint8_t[size], NULL, mode);
|
new WholeTranslationState(req, new uint8_t[size], NULL, mode);
|
||||||
DataTranslation<TimingSimpleCPU *> *translation
|
DataTranslation<TimingSimpleCPU *> *translation
|
||||||
= new DataTranslation<TimingSimpleCPU *>(this, state);
|
= new DataTranslation<TimingSimpleCPU *>(this, state);
|
||||||
thread->dtb->translateTiming(req, tc, translation, mode);
|
thread->dtb->translateTiming(req, thread->getTC(), translation, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NoFault;
|
return NoFault;
|
||||||
|
@ -437,6 +458,9 @@ TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
|
||||||
bool
|
bool
|
||||||
TimingSimpleCPU::handleWritePacket()
|
TimingSimpleCPU::handleWritePacket()
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
RequestPtr req = dcache_pkt->req;
|
RequestPtr req = dcache_pkt->req;
|
||||||
if (req->isMmappedIpr()) {
|
if (req->isMmappedIpr()) {
|
||||||
Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
|
Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
|
||||||
|
@ -457,9 +481,12 @@ Fault
|
||||||
TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
Addr addr, unsigned flags, uint64_t *res)
|
Addr addr, unsigned flags, uint64_t *res)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
uint8_t *newData = new uint8_t[size];
|
uint8_t *newData = new uint8_t[size];
|
||||||
const int asid = 0;
|
const int asid = 0;
|
||||||
const ThreadID tid = 0;
|
const ThreadID tid = curThread;
|
||||||
const Addr pc = thread->instAddr();
|
const Addr pc = thread->instAddr();
|
||||||
unsigned block_size = cacheLineSize();
|
unsigned block_size = cacheLineSize();
|
||||||
BaseTLB::Mode mode = BaseTLB::Write;
|
BaseTLB::Mode mode = BaseTLB::Write;
|
||||||
|
@ -476,7 +503,8 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
traceData->setMem(addr, size, flags);
|
traceData->setMem(addr, size, flags);
|
||||||
|
|
||||||
RequestPtr req = new Request(asid, addr, size,
|
RequestPtr req = new Request(asid, addr, size,
|
||||||
flags, dataMasterId(), pc, _cpuId, tid);
|
flags, dataMasterId(), pc,
|
||||||
|
thread->contextId(), tid);
|
||||||
|
|
||||||
req->taskId(taskId());
|
req->taskId(taskId());
|
||||||
|
|
||||||
|
@ -496,14 +524,14 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
DataTranslation<TimingSimpleCPU *> *trans2 =
|
DataTranslation<TimingSimpleCPU *> *trans2 =
|
||||||
new DataTranslation<TimingSimpleCPU *>(this, state, 1);
|
new DataTranslation<TimingSimpleCPU *>(this, state, 1);
|
||||||
|
|
||||||
thread->dtb->translateTiming(req1, tc, trans1, mode);
|
thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode);
|
||||||
thread->dtb->translateTiming(req2, tc, trans2, mode);
|
thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode);
|
||||||
} else {
|
} else {
|
||||||
WholeTranslationState *state =
|
WholeTranslationState *state =
|
||||||
new WholeTranslationState(req, newData, res, mode);
|
new WholeTranslationState(req, newData, res, mode);
|
||||||
DataTranslation<TimingSimpleCPU *> *translation =
|
DataTranslation<TimingSimpleCPU *> *translation =
|
||||||
new DataTranslation<TimingSimpleCPU *>(this, state);
|
new DataTranslation<TimingSimpleCPU *>(this, state);
|
||||||
thread->dtb->translateTiming(req, tc, translation, mode);
|
thread->dtb->translateTiming(req, thread->getTC(), translation, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translation faults will be returned via finishTranslation()
|
// Translation faults will be returned via finishTranslation()
|
||||||
|
@ -540,6 +568,12 @@ TimingSimpleCPU::finishTranslation(WholeTranslationState *state)
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::fetch()
|
TimingSimpleCPU::fetch()
|
||||||
{
|
{
|
||||||
|
// Change thread if multi-threaded
|
||||||
|
swapActiveThread();
|
||||||
|
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
DPRINTF(SimpleCPU, "Fetch\n");
|
DPRINTF(SimpleCPU, "Fetch\n");
|
||||||
|
|
||||||
if (!curStaticInst || !curStaticInst->isDelayedCommit()) {
|
if (!curStaticInst || !curStaticInst->isDelayedCommit()) {
|
||||||
|
@ -552,17 +586,18 @@ TimingSimpleCPU::fetch()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TheISA::PCState pcState = thread->pcState();
|
TheISA::PCState pcState = thread->pcState();
|
||||||
bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
|
bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
|
||||||
|
!curMacroStaticInst;
|
||||||
|
|
||||||
if (needToFetch) {
|
if (needToFetch) {
|
||||||
_status = BaseSimpleCPU::Running;
|
_status = BaseSimpleCPU::Running;
|
||||||
Request *ifetch_req = new Request();
|
Request *ifetch_req = new Request();
|
||||||
ifetch_req->taskId(taskId());
|
ifetch_req->taskId(taskId());
|
||||||
ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
|
ifetch_req->setThreadContext(thread->contextId(), curThread);
|
||||||
setupFetchRequest(ifetch_req);
|
setupFetchRequest(ifetch_req);
|
||||||
DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
|
DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
|
||||||
thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
|
thread->itb->translateTiming(ifetch_req, thread->getTC(),
|
||||||
BaseTLB::Execute);
|
&fetchTranslation, BaseTLB::Execute);
|
||||||
} else {
|
} else {
|
||||||
_status = IcacheWaitResponse;
|
_status = IcacheWaitResponse;
|
||||||
completeIfetch(NULL);
|
completeIfetch(NULL);
|
||||||
|
@ -607,6 +642,8 @@ TimingSimpleCPU::sendFetch(const Fault &fault, RequestPtr req,
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::advanceInst(const Fault &fault)
|
TimingSimpleCPU::advanceInst(const Fault &fault)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext &t_info = *threadInfo[curThread];
|
||||||
|
|
||||||
if (_status == Faulting)
|
if (_status == Faulting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -619,7 +656,7 @@ TimingSimpleCPU::advanceInst(const Fault &fault)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!stayAtPC)
|
if (!t_info.stayAtPC)
|
||||||
advancePC(fault);
|
advancePC(fault);
|
||||||
|
|
||||||
if (tryCompleteDrain())
|
if (tryCompleteDrain())
|
||||||
|
@ -637,6 +674,8 @@ TimingSimpleCPU::advanceInst(const Fault &fault)
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
|
||||||
DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ?
|
DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ?
|
||||||
pkt->getAddr() : 0);
|
pkt->getAddr() : 0);
|
||||||
|
|
||||||
|
@ -656,7 +695,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
||||||
preExecute();
|
preExecute();
|
||||||
if (curStaticInst && curStaticInst->isMemRef()) {
|
if (curStaticInst && curStaticInst->isMemRef()) {
|
||||||
// load or store: just send to dcache
|
// load or store: just send to dcache
|
||||||
Fault fault = curStaticInst->initiateAcc(this, traceData);
|
Fault fault = curStaticInst->initiateAcc(&t_info, traceData);
|
||||||
|
|
||||||
// If we're not running now the instruction will complete in a dcache
|
// If we're not running now the instruction will complete in a dcache
|
||||||
// response callback or the instruction faulted and has started an
|
// response callback or the instruction faulted and has started an
|
||||||
|
@ -677,7 +716,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
} else if (curStaticInst) {
|
} else if (curStaticInst) {
|
||||||
// non-memory instruction: execute completely now
|
// non-memory instruction: execute completely now
|
||||||
Fault fault = curStaticInst->execute(this, traceData);
|
Fault fault = curStaticInst->execute(&t_info, traceData);
|
||||||
|
|
||||||
// keep an instruction count
|
// keep an instruction count
|
||||||
if (fault == NoFault)
|
if (fault == NoFault)
|
||||||
|
@ -690,7 +729,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
||||||
postExecute();
|
postExecute();
|
||||||
// @todo remove me after debugging with legion done
|
// @todo remove me after debugging with legion done
|
||||||
if (curStaticInst && (!curStaticInst->isMicroop() ||
|
if (curStaticInst && (!curStaticInst->isMicroop() ||
|
||||||
curStaticInst->isFirstMicroop()))
|
curStaticInst->isFirstMicroop()))
|
||||||
instCnt++;
|
instCnt++;
|
||||||
advanceInst(fault);
|
advanceInst(fault);
|
||||||
} else {
|
} else {
|
||||||
|
@ -776,7 +815,8 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
|
||||||
|
|
||||||
_status = BaseSimpleCPU::Running;
|
_status = BaseSimpleCPU::Running;
|
||||||
|
|
||||||
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
|
Fault fault = curStaticInst->completeAcc(pkt, threadInfo[curThread],
|
||||||
|
traceData);
|
||||||
|
|
||||||
// keep an instruction count
|
// keep an instruction count
|
||||||
if (fault == NoFault)
|
if (fault == NoFault)
|
||||||
|
@ -810,17 +850,20 @@ void
|
||||||
TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
|
TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
// X86 ISA: Snooping an invalidation for monitor/mwait
|
// X86 ISA: Snooping an invalidation for monitor/mwait
|
||||||
if(cpu->getAddrMonitor()->doMonitor(pkt)) {
|
if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
|
||||||
cpu->wakeup();
|
cpu->wakeup();
|
||||||
}
|
}
|
||||||
TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
|
|
||||||
|
for (auto &t_info : cpu->threadInfo) {
|
||||||
|
TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt)
|
TimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
// X86 ISA: Snooping an invalidation for monitor/mwait
|
// X86 ISA: Snooping an invalidation for monitor/mwait
|
||||||
if(cpu->getAddrMonitor()->doMonitor(pkt)) {
|
if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
|
||||||
cpu->wakeup();
|
cpu->wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -930,8 +973,5 @@ TimingSimpleCPU::printAddr(Addr a)
|
||||||
TimingSimpleCPU *
|
TimingSimpleCPU *
|
||||||
TimingSimpleCPUParams::create()
|
TimingSimpleCPUParams::create()
|
||||||
{
|
{
|
||||||
numThreads = 1;
|
|
||||||
if (!FullSystem && workload.size() != 1)
|
|
||||||
panic("only one workload allowed");
|
|
||||||
return new TimingSimpleCPU(this);
|
return new TimingSimpleCPU(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2013 ARM Limited
|
* Copyright (c) 2012-2013,2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
#define __CPU_SIMPLE_TIMING_HH__
|
#define __CPU_SIMPLE_TIMING_HH__
|
||||||
|
|
||||||
#include "cpu/simple/base.hh"
|
#include "cpu/simple/base.hh"
|
||||||
|
#include "cpu/simple/exec_context.hh"
|
||||||
#include "cpu/translation.hh"
|
#include "cpu/translation.hh"
|
||||||
#include "params/TimingSimpleCPU.hh"
|
#include "params/TimingSimpleCPU.hh"
|
||||||
|
|
||||||
|
@ -342,7 +343,11 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
bool isDrained() {
|
bool isDrained() {
|
||||||
return microPC() == 0 && !stayAtPC && !fetchEvent.scheduled();
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
SimpleThread* thread = t_info.thread;
|
||||||
|
|
||||||
|
return thread->microPC() == 0 && !t_info.stayAtPC &&
|
||||||
|
!fetchEvent.scheduled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,5 +29,6 @@
|
||||||
process1 = LiveProcess(cmd = 'hello', executable = binpath('hello'))
|
process1 = LiveProcess(cmd = 'hello', executable = binpath('hello'))
|
||||||
process2 = LiveProcess(cmd = 'hello', executable = binpath('hello'))
|
process2 = LiveProcess(cmd = 'hello', executable = binpath('hello'))
|
||||||
|
|
||||||
|
root.system.multi_thread = True
|
||||||
root.system.cpu[0].workload = [process1, process2]
|
root.system.cpu[0].workload = [process1, process2]
|
||||||
root.system.cpu[0].numThreads = 2
|
root.system.cpu[0].numThreads = 2
|
||||||
|
|
Loading…
Reference in a new issue