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

Reply via email to