changeset cc8d6e99cf46 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=cc8d6e99cf46
description:
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.
diffstat:
configs/example/se.py | 3 +
src/cpu/simple/atomic.cc | 146 +++++----
src/cpu/simple/atomic.hh | 9 +-
src/cpu/simple/base.cc | 516 +++++++++++++++++++-------------
src/cpu/simple/base.hh | 353 +---------------------
src/cpu/simple/exec_context.hh | 416 ++++++++++++++++++++++++++
src/cpu/simple/timing.cc | 168 ++++++----
src/cpu/simple/timing.hh | 9 +-
tests/quick/se/01.hello-2T-smt/test.py | 1 +
9 files changed, 952 insertions(+), 669 deletions(-)
diffs (truncated from 2429 to 300 lines):
diff -r 0fd6976303bc -r cc8d6e99cf46 configs/example/se.py
--- a/configs/example/se.py Wed Sep 30 11:14:19 2015 -0500
+++ b/configs/example/se.py Wed Sep 30 11:14:19 2015 -0500
@@ -178,6 +178,9 @@
mem_ranges = [AddrRange(options.mem_size)],
cache_line_size = options.cacheline_size)
+if numThreads > 1:
+ system.multi_thread = True
+
# Create a top-level voltage domain
system.voltage_domain = VoltageDomain(voltage = options.sys_voltage)
diff -r 0fd6976303bc -r cc8d6e99cf46 src/cpu/simple/atomic.cc
--- a/src/cpu/simple/atomic.cc Wed Sep 30 11:14:19 2015 -0500
+++ b/src/cpu/simple/atomic.cc Wed Sep 30 11:14:19 2015 -0500
@@ -1,6 +1,6 @@
/*
* Copyright 2014 Google, Inc.
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013,2015 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -84,24 +84,11 @@
void
AtomicSimpleCPU::init()
{
- BaseCPU::init();
+ BaseSimpleCPU::init();
- // Initialise the ThreadContext's memory proxies
- tcBase()->initMemProxies(tcBase());
-
- 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
+ ifetch_req.setThreadContext(_cpuId, 0);
+ data_read_req.setThreadContext(_cpuId, 0);
+ data_write_req.setThreadContext(_cpuId, 0);
}
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
@@ -131,12 +118,13 @@
return DrainState::Drained;
if (!isDrained()) {
- DPRINTF(Drain, "Requesting drain: %s\n", pcState());
+ DPRINTF(Drain, "Requesting drain.\n");
return DrainState::Draining;
} else {
if (tickEvent.scheduled())
deschedule(tickEvent);
+ activeThreads.clear();
DPRINTF(Drain, "Not executing microcode, no need to drain.\n");
return DrainState::Drained;
}
@@ -153,16 +141,22 @@
verifyMemoryMode();
assert(!threadContexts.empty());
- if (threadContexts.size() > 1)
- fatal("The atomic CPU only supports one thread.\n");
- if (thread->status() == ThreadContext::Active) {
- schedule(tickEvent, nextCycle());
- _status = BaseSimpleCPU::Running;
- notIdleFraction = 1;
- } else {
- _status = BaseSimpleCPU::Idle;
- notIdleFraction = 0;
+ _status = BaseSimpleCPU::Idle;
+
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ if (threadInfo[tid]->thread->status() == ThreadContext::Active) {
+ threadInfo[tid]->notIdleFraction = 1;
+ activeThreads.push_back(tid);
+ _status = BaseSimpleCPU::Running;
+
+ // Tick if any threads active
+ if (!tickEvent.scheduled()) {
+ schedule(tickEvent, nextCycle());
+ }
+ } else {
+ threadInfo[tid]->notIdleFraction = 0;
+ }
}
}
@@ -172,7 +166,7 @@
if (drainState() != DrainState::Draining)
return false;
- DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
+ DPRINTF(Drain, "tryCompleteDrain.\n");
if (!isDrained())
return false;
@@ -201,10 +195,6 @@
// The tick event should have been descheduled by drain()
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
@@ -221,20 +211,23 @@
{
DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
- assert(thread_num == 0);
- assert(thread);
+ assert(thread_num < numThreads);
- assert(_status == Idle);
- assert(!tickEvent.scheduled());
-
- notIdleFraction = 1;
- Cycles delta = ticksToCycles(thread->lastActivate - thread->lastSuspend);
+ threadInfo[thread_num]->notIdleFraction = 1;
+ Cycles delta = ticksToCycles(threadInfo[thread_num]->thread->lastActivate -
+ threadInfo[thread_num]->thread->lastSuspend);
numCycles += delta;
ppCycles->notify(delta);
- //Make sure ticks are still on multiples of cycles
- schedule(tickEvent, clockEdge(Cycles(0)));
+ if (!tickEvent.scheduled()) {
+ //Make sure ticks are still on multiples of cycles
+ schedule(tickEvent, clockEdge(Cycles(0)));
+ }
_status = BaseSimpleCPU::Running;
+ if (std::find(activeThreads.begin(), activeThreads.end(), thread_num)
+ == activeThreads.end()) {
+ activeThreads.push_back(thread_num);
+ }
}
@@ -243,21 +236,24 @@
{
DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
- assert(thread_num == 0);
- assert(thread);
+ assert(thread_num < numThreads);
+ activeThreads.remove(thread_num);
if (_status == Idle)
return;
assert(_status == BaseSimpleCPU::Running);
- // tick event may not be scheduled if this gets called from inside
- // an instruction's execution, e.g. "quiesce"
- if (tickEvent.scheduled())
- deschedule(tickEvent);
+ threadInfo[thread_num]->notIdleFraction = 0;
- notIdleFraction = 0;
- _status = Idle;
+ if (activeThreads.empty()) {
+ _status = Idle;
+
+ if (tickEvent.scheduled()) {
+ deschedule(tickEvent);
+ }
+ }
+
}
@@ -269,7 +265,7 @@
// X86 ISA: Snooping an invalidation for monitor/mwait
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
- if(cpu->getAddrMonitor()->doMonitor(pkt)) {
+ if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
cpu->wakeup();
}
@@ -277,7 +273,9 @@
if (pkt->isInvalidate()) {
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
pkt->getAddr());
- TheISA::handleLockedSnoop(cpu->thread, pkt, cacheBlockMask);
+ for (auto &t_info : cpu->threadInfo) {
+ TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask);
+ }
}
return 0;
@@ -291,7 +289,7 @@
// X86 ISA: Snooping an invalidation for monitor/mwait
AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
- if(cpu->getAddrMonitor()->doMonitor(pkt)) {
+ if(cpu->getCpuAddrMonitor()->doMonitor(pkt)) {
cpu->wakeup();
}
@@ -299,7 +297,9 @@
if (pkt->isInvalidate()) {
DPRINTF(SimpleCPU, "received invalidation for addr:%#x\n",
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 @@
AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
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
Request *req = &data_read_req;
@@ -330,7 +333,8 @@
req->setVirt(0, addr, size, flags, dataMasterId(),
thread->pcState().instAddr());
// 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.
if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
@@ -370,6 +374,7 @@
assert(!locked);
locked = true;
}
+
return fault;
}
@@ -391,7 +396,8 @@
AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *res)
{
-
+ SimpleExecContext& t_info = *threadInfo[curThread];
+ SimpleThread* thread = t_info.thread;
static uint8_t zero_array[64] = {};
if (data == NULL) {
@@ -424,7 +430,7 @@
req->setVirt(0, addr, size, flags, dataMasterId(),
thread->pcState().instAddr());
// 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.
if (fault == NoFault) {
@@ -477,6 +483,8 @@
assert(locked);
locked = false;
}
+
+
if (fault != NoFault && req->isPrefetch()) {
return NoFault;
} else {
@@ -503,6 +511,19 @@
{
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;
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev