Implement Alpha LL/SC support for SimpleCPU (Atomic & Timing)
authorSteve Reinhardt <stever@eecs.umich.edu>
Sun, 8 Oct 2006 17:53:24 +0000 (10:53 -0700)
committerSteve Reinhardt <stever@eecs.umich.edu>
Sun, 8 Oct 2006 17:53:24 +0000 (10:53 -0700)
and PhysicalMemory.  *No* support for caches or O3CPU.
Note that properly setting cpu_id on all CPUs is now required
for correct operation.

src/arch/SConscript:
src/base/traceflags.py:
src/cpu/base.hh:
src/cpu/simple/atomic.cc:
src/cpu/simple/timing.cc:
src/cpu/simple/timing.hh:
src/mem/physical.cc:
src/mem/physical.hh:
src/mem/request.hh:
src/python/m5/objects/BaseCPU.py:
tests/configs/simple-atomic.py:
tests/configs/simple-timing.py:
tests/configs/tsunami-simple-atomic-dual.py:
tests/configs/tsunami-simple-atomic.py:
tests/configs/tsunami-simple-timing-dual.py:
tests/configs/tsunami-simple-timing.py:
    Implement Alpha LL/SC support for SimpleCPU (Atomic & Timing)
    and PhysicalMemory.  *No* support for caches or O3CPU.

--HG--
extra : convert_revision : 6ce982d44924cc477e049b9adf359818908e72be

19 files changed:
src/arch/SConscript
src/arch/alpha/locked_mem.hh [new file with mode: 0644]
src/arch/mips/locked_mem.hh [new file with mode: 0644]
src/arch/sparc/locked_mem.hh [new file with mode: 0644]
src/base/traceflags.py
src/cpu/base.hh
src/cpu/simple/atomic.cc
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/mem/physical.cc
src/mem/physical.hh
src/mem/request.hh
src/python/m5/objects/BaseCPU.py
tests/configs/simple-atomic.py
tests/configs/simple-timing.py
tests/configs/tsunami-simple-atomic-dual.py
tests/configs/tsunami-simple-atomic.py
tests/configs/tsunami-simple-timing-dual.py
tests/configs/tsunami-simple-timing.py

index 59cea6211b328f2b1d15bbcc38bf6558b0b6cc0f..dda1dea532568779df1789ca7c15a70de6b025f8 100644 (file)
@@ -50,6 +50,7 @@ isa_switch_hdrs = Split('''
        arguments.hh
        faults.hh
        isa_traits.hh
+        locked_mem.hh
        process.hh
        regfile.hh
        stacktrace.hh
diff --git a/src/arch/alpha/locked_mem.hh b/src/arch/alpha/locked_mem.hh
new file mode 100644 (file)
index 0000000..368ea28
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 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: Steve Reinhardt
+ */
+
+#ifndef __ARCH_ALPHA_LOCKED_MEM_HH__
+#define __ARCH_ALPHA_LOCKED_MEM_HH__
+
+/**
+ * @file
+ *
+ * ISA-specific helper functions for locked memory accesses.
+ */
+
+#include "arch/isa_traits.hh"
+#include "base/misc.hh"
+#include "mem/request.hh"
+
+
+namespace AlphaISA
+{
+template <class XC>
+inline void
+handleLockedRead(XC *xc, Request *req)
+{
+    xc->setMiscReg(Lock_Addr_DepTag, req->getPaddr() & ~0xf);
+    xc->setMiscReg(Lock_Flag_DepTag, true);
+}
+
+
+template <class XC>
+inline bool
+handleLockedWrite(XC *xc, Request *req)
+{
+    if (req->isUncacheable()) {
+        // Funky Turbolaser mailbox access...don't update
+        // result register (see stq_c in decoder.isa)
+        req->setScResult(2);
+    } else {
+        // standard store conditional
+        bool lock_flag = xc->readMiscReg(Lock_Flag_DepTag);
+        Addr lock_addr = xc->readMiscReg(Lock_Addr_DepTag);
+        if (!lock_flag || (req->getPaddr() & ~0xf) != lock_addr) {
+            // Lock flag not set or addr mismatch in CPU;
+            // don't even bother sending to memory system
+            req->setScResult(0);
+            xc->setMiscReg(Lock_Flag_DepTag, false);
+            // the rest of this code is not architectural;
+            // it's just a debugging aid to help detect
+            // livelock by warning on long sequences of failed
+            // store conditionals
+            int stCondFailures = xc->readStCondFailures();
+            stCondFailures++;
+            xc->setStCondFailures(stCondFailures);
+            if (stCondFailures % 100000 == 0) {
+                warn("cpu %d: %d consecutive "
+                     "store conditional failures\n",
+                     xc->readCpuId(), stCondFailures);
+            }
+
+            // store conditional failed already, so don't issue it to mem
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+} // namespace AlphaISA
+
+#endif
diff --git a/src/arch/mips/locked_mem.hh b/src/arch/mips/locked_mem.hh
new file mode 100644 (file)
index 0000000..363cf1e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006 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: Steve Reinhardt
+ */
+
+#ifndef __ARCH_MIPS_LOCKED_MEM_HH__
+#define __ARCH_MIPS_LOCKED_MEM_HH__
+
+/**
+ * @file
+ *
+ * ISA-specific helper functions for locked memory accesses.
+ */
+
+#include "mem/request.hh"
+
+
+namespace MipsISA
+{
+template <class XC>
+inline void
+handleLockedRead(XC *xc, Request *req)
+{
+}
+
+
+template <class XC>
+inline bool
+handleLockedWrite(XC *xc, Request *req)
+{
+    return true;
+}
+
+
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/sparc/locked_mem.hh b/src/arch/sparc/locked_mem.hh
new file mode 100644 (file)
index 0000000..291b2f4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006 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: Steve Reinhardt
+ */
+
+#ifndef __ARCH_SPARC_LOCKED_MEM_HH__
+#define __ARCH_SPARC_LOCKED_MEM_HH__
+
+/**
+ * @file
+ *
+ * ISA-specific helper functions for locked memory accesses.
+ */
+
+#include "mem/request.hh"
+
+
+namespace SparcISA
+{
+template <class XC>
+inline void
+handleLockedRead(XC *xc, Request *req)
+{
+}
+
+
+template <class XC>
+inline bool
+handleLockedWrite(XC *xc, Request *req)
+{
+    return true;
+}
+
+
+} // namespace SparcISA
+
+#endif
index 8e8153b6874f10a30ad8f34c5d3c5dc00927e0a2..274407be5961302089bc176df8da549ff64952f3 100644 (file)
@@ -112,6 +112,7 @@ baseFlags = [
     'IdeDisk',
     'InstExec',
     'Interrupt',
+    'LLSC',
     'LSQ',
     'LSQUnit',
     'Loader',
index e025273710e4086d6db64f8e003d0bbb81dc8e6d..75e0d86af4e910e221eae6a784475ad7016b80e6 100644 (file)
@@ -140,8 +140,8 @@ class BaseCPU : public MemObject
         bool functionTrace;
         Tick functionTraceStart;
         System *system;
-#if FULL_SYSTEM
         int cpu_id;
+#if FULL_SYSTEM
         Tick profile;
 #endif
         Tick progress_interval;
index 1b67af81b0dd08372e5c6f923f88b0034af29bb2..0ca7006340bc7b7da5ebf10f728e1f17769b8914 100644 (file)
@@ -28,6 +28,7 @@
  * Authors: Steve Reinhardt
  */
 
+#include "arch/locked_mem.hh"
 #include "arch/utility.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/simple/atomic.hh"
@@ -133,20 +134,19 @@ AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
 {
     _status = Idle;
 
-    // @todo fix me and get the real cpu id & thread number!!!
     ifetch_req = new Request();
-    ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+    ifetch_req->setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
     ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
     ifetch_pkt->dataStatic(&inst);
 
     data_read_req = new Request();
-    data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+    data_read_req->setThreadContext(p->cpu_id, 0); // Add thread ID here too
     data_read_pkt = new Packet(data_read_req, Packet::ReadReq,
                                Packet::Broadcast);
     data_read_pkt->dataStatic(&dataReg);
 
     data_write_req = new Request();
-    data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+    data_write_req->setThreadContext(p->cpu_id, 0); // Add thread ID here too
     data_write_pkt = new Packet(data_write_req, Packet::WriteReq,
                                 Packet::Broadcast);
 }
@@ -275,6 +275,10 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
 
         assert(pkt->result == Packet::Success);
         data = pkt->get<T>();
+
+        if (req->isLocked()) {
+            TheISA::handleLockedRead(thread, req);
+        }
     }
 
     // This will need a new way to tell if it has a dcache attached.
@@ -346,17 +350,32 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 
     // Now do the access.
     if (fault == NoFault) {
-        data = htog(data);
-        pkt->reinitFromRequest();
-        pkt->dataStatic(&data);
+        bool do_access = true;  // flag to suppress cache access
 
-        dcache_latency = dcachePort.sendAtomic(pkt);
-        dcache_access = true;
+        if (req->isLocked()) {
+            do_access = TheISA::handleLockedWrite(thread, req);
+        }
 
-        assert(pkt->result == Packet::Success);
+        if (do_access) {
+            data = htog(data);
+            pkt->reinitFromRequest();
+            pkt->dataStatic(&data);
+
+            dcache_latency = dcachePort.sendAtomic(pkt);
+            dcache_access = true;
+
+            assert(pkt->result == Packet::Success);
+        }
 
-        if (res && req->getFlags() & LOCKED) {
-            *res = req->getScResult();
+        if (req->isLocked()) {
+            uint64_t scResult = req->getScResult();
+            if (scResult != 0) {
+                // clear failure counter
+                thread->setStCondFailures(0);
+            }
+            if (res) {
+                *res = req->getScResult();
+            }
         }
     }
 
@@ -474,11 +493,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
     Param<Tick> progress_interval;
     SimObjectParam<MemObject *> mem;
     SimObjectParam<System *> system;
+    Param<int> cpu_id;
 
 #if FULL_SYSTEM
     SimObjectParam<AlphaITB *> itb;
     SimObjectParam<AlphaDTB *> dtb;
-    Param<int> cpu_id;
     Param<Tick> profile;
 #else
     SimObjectParam<Process *> workload;
@@ -507,11 +526,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
     INIT_PARAM(progress_interval, "Progress interval"),
     INIT_PARAM(mem, "memory"),
     INIT_PARAM(system, "system object"),
+    INIT_PARAM(cpu_id, "processor ID"),
 
 #if FULL_SYSTEM
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
-    INIT_PARAM(cpu_id, "processor ID"),
     INIT_PARAM(profile, ""),
 #else
     INIT_PARAM(workload, "processes to run"),
@@ -545,11 +564,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU)
     params->simulate_stalls = simulate_stalls;
     params->mem = mem;
     params->system = system;
+    params->cpu_id = cpu_id;
 
 #if FULL_SYSTEM
     params->itb = itb;
     params->dtb = dtb;
-    params->cpu_id = cpu_id;
     params->profile = profile;
 #else
     params->process = workload;
index dfe599bc54648307cf4ec4708d6c1e934f8ca056..cd43bb5fc4be92c7b60bde4ade15207506fae9af 100644 (file)
@@ -28,6 +28,7 @@
  * Authors: Steve Reinhardt
  */
 
+#include "arch/locked_mem.hh"
 #include "arch/utility.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/simple/timing.hh"
@@ -94,7 +95,8 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(Packet *_pkt, Tick t)
 }
 
 TimingSimpleCPU::TimingSimpleCPU(Params *p)
-    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
+    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock),
+      cpu_id(p->cpu_id)
 {
     _status = Idle;
     ifetch_pkt = dcache_pkt = NULL;
@@ -229,7 +231,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
 {
     Request *req =
         new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
-                    /* CPU ID */ 0, /* thread ID */ 0);
+                    cpu_id, /* thread ID */ 0);
 
     if (traceData) {
         traceData->setAddr(req->getVaddr());
@@ -310,7 +312,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 {
     Request *req =
         new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
-                    /* CPU ID */ 0, /* thread ID */ 0);
+                    cpu_id, /* thread ID */ 0);
 
     // translate to physical address
     Fault fault = thread->translateDataWriteReq(req);
@@ -322,12 +324,20 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
         dcache_pkt->allocate();
         dcache_pkt->set(data);
 
-        if (!dcachePort.sendTiming(dcache_pkt)) {
-            _status = DcacheRetry;
-        } else {
-            _status = DcacheWaitResponse;
-            // memory system takes ownership of packet
-            dcache_pkt = NULL;
+        bool do_access = true;  // flag to suppress cache access
+
+        if (req->isLocked()) {
+            do_access = TheISA::handleLockedWrite(thread, req);
+        }
+
+        if (do_access) {
+            if (!dcachePort.sendTiming(dcache_pkt)) {
+                _status = DcacheRetry;
+            } else {
+                _status = DcacheWaitResponse;
+                // memory system takes ownership of packet
+                dcache_pkt = NULL;
+            }
         }
     }
 
@@ -392,9 +402,8 @@ TimingSimpleCPU::fetch()
 {
     checkForInterrupts();
 
-    // need to fill in CPU & thread IDs here
     Request *ifetch_req = new Request();
-    ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+    ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0);
     Fault fault = setupFetchRequest(ifetch_req);
 
     ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
@@ -453,12 +462,20 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
     if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
         // load or store: just send to dcache
         Fault fault = curStaticInst->initiateAcc(this, traceData);
-        if (fault == NoFault) {
-            // successfully initiated access: instruction will
-            // complete in dcache response callback
-            assert(_status == DcacheWaitResponse);
+        if (_status != Running) {
+            // instruction will complete in dcache response callback
+            assert(_status == DcacheWaitResponse || _status == DcacheRetry);
+            assert(fault == NoFault);
         } else {
-            // fault: complete now to invoke fault handler
+            if (fault == NoFault) {
+                // early fail on store conditional: complete now
+                assert(dcache_pkt != NULL);
+                fault = curStaticInst->completeAcc(dcache_pkt, this,
+                                                   traceData);
+                delete dcache_pkt->req;
+                delete dcache_pkt;
+                dcache_pkt = NULL;
+            }
             postExecute();
             advanceInst(fault);
         }
@@ -479,8 +496,7 @@ TimingSimpleCPU::IcachePort::ITickEvent::process()
 bool
 TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
 {
-    // These next few lines could be replaced with something faster
-    // who knows what though
+    // delay processing of returned data until next CPU clock edge
     Tick time = pkt->req->getTime();
     while (time < curTick)
         time += lat;
@@ -527,6 +543,10 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
 
     Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
 
+    if (pkt->isRead() && pkt->req->isLocked()) {
+        TheISA::handleLockedRead(thread, pkt->req);
+    }
+
     delete pkt->req;
     delete pkt;
 
@@ -546,6 +566,7 @@ TimingSimpleCPU::completeDrain()
 bool
 TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
 {
+    // delay processing of returned data until next CPU clock edge
     Tick time = pkt->req->getTime();
     while (time < curTick)
         time += lat;
@@ -574,6 +595,7 @@ TimingSimpleCPU::DcachePort::recvRetry()
     Packet *tmp = cpu->dcache_pkt;
     if (sendTiming(tmp)) {
         cpu->_status = DcacheWaitResponse;
+        // memory system takes ownership of packet
         cpu->dcache_pkt = NULL;
     }
 }
@@ -592,11 +614,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     Param<Tick> progress_interval;
     SimObjectParam<MemObject *> mem;
     SimObjectParam<System *> system;
+    Param<int> cpu_id;
 
 #if FULL_SYSTEM
     SimObjectParam<AlphaITB *> itb;
     SimObjectParam<AlphaDTB *> dtb;
-    Param<int> cpu_id;
     Param<Tick> profile;
 #else
     SimObjectParam<Process *> workload;
@@ -625,11 +647,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     INIT_PARAM(progress_interval, "Progress interval"),
     INIT_PARAM(mem, "memory"),
     INIT_PARAM(system, "system object"),
+    INIT_PARAM(cpu_id, "processor ID"),
 
 #if FULL_SYSTEM
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
-    INIT_PARAM(cpu_id, "processor ID"),
     INIT_PARAM(profile, ""),
 #else
     INIT_PARAM(workload, "processes to run"),
@@ -661,11 +683,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
     params->functionTraceStart = function_trace_start;
     params->mem = mem;
     params->system = system;
+    params->cpu_id = cpu_id;
 
 #if FULL_SYSTEM
     params->itb = itb;
     params->dtb = dtb;
-    params->cpu_id = cpu_id;
     params->profile = profile;
 #else
     params->process = workload;
index d03fa4bc0a7f2fd27698cac1e411e7f58e182f29..b65eebd996dbcf0b8ce98e6bfc298a013c7c34bf 100644 (file)
@@ -166,6 +166,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
     Packet *ifetch_pkt;
     Packet *dcache_pkt;
 
+    int cpu_id;
+
   public:
 
     virtual Port *getPort(const std::string &if_name, int idx = -1);
index 8fea733ec37ef443cdf146aa701baa38478f04e6..23b1d5ffce8c75c51895def3d6feb8ac6463702b 100644 (file)
@@ -110,6 +110,88 @@ PhysicalMemory::calculateLatency(Packet *pkt)
     return lat;
 }
 
+
+
+// Add load-locked to tracking list.  Should only be called if the
+// operation is a load and the LOCKED flag is set.
+void
+PhysicalMemory::trackLoadLocked(Request *req)
+{
+    Addr paddr = LockedAddr::mask(req->getPaddr());
+
+    // first we check if we already have a locked addr for this
+    // xc.  Since each xc only gets one, we just update the
+    // existing record with the new address.
+    list<LockedAddr>::iterator i;
+
+    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
+        if (i->matchesContext(req)) {
+            DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
+                    req->getCpuNum(), req->getThreadNum(), paddr);
+            i->addr = paddr;
+            return;
+        }
+    }
+
+    // no record for this xc: need to allocate a new one
+    DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
+            req->getCpuNum(), req->getThreadNum(), paddr);
+    lockedAddrList.push_front(LockedAddr(req));
+}
+
+
+// Called on *writes* only... both regular stores and
+// store-conditional operations.  Check for conventional stores which
+// conflict with locked addresses, and for success/failure of store
+// conditionals.
+bool
+PhysicalMemory::checkLockedAddrList(Request *req)
+{
+    Addr paddr = LockedAddr::mask(req->getPaddr());
+    bool isLocked = req->isLocked();
+
+    // Initialize return value.  Non-conditional stores always
+    // succeed.  Assume conditional stores will fail until proven
+    // otherwise.
+    bool success = !isLocked;
+
+    // Iterate over list.  Note that there could be multiple matching
+    // records, as more than one context could have done a load locked
+    // to this location.
+    list<LockedAddr>::iterator i = lockedAddrList.begin();
+
+    while (i != lockedAddrList.end()) {
+
+        if (i->addr == paddr) {
+            // we have a matching address
+
+            if (isLocked && i->matchesContext(req)) {
+                // it's a store conditional, and as far as the memory
+                // system can tell, the requesting context's lock is
+                // still valid.
+                DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
+                        req->getCpuNum(), req->getThreadNum(), paddr);
+                success = true;
+            }
+
+            // Get rid of our record of this lock and advance to next
+            DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
+                    i->cpuNum, i->threadNum, paddr);
+            i = lockedAddrList.erase(i);
+        }
+        else {
+            // no match: advance to next record
+            ++i;
+        }
+    }
+
+    if (isLocked) {
+        req->setScResult(success ? 1 : 0);
+    }
+
+    return success;
+}
+
 void
 PhysicalMemory::doFunctionalAccess(Packet *pkt)
 {
@@ -117,18 +199,17 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt)
 
     switch (pkt->cmd) {
       case Packet::ReadReq:
+        if (pkt->req->isLocked()) {
+            trackLoadLocked(pkt->req);
+        }
         memcpy(pkt->getPtr<uint8_t>(),
                pmemAddr + pkt->getAddr() - params()->addrRange.start,
                pkt->getSize());
         break;
       case Packet::WriteReq:
-        memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
-               pkt->getPtr<uint8_t>(),
-               pkt->getSize());
-        // temporary hack: will need to add real LL/SC implementation
-        // for cacheless systems later.
-        if (pkt->req->getFlags() & LOCKED) {
-            pkt->req->setScResult(1);
+        if (writeOK(pkt->req)) {
+            memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
+                   pkt->getPtr<uint8_t>(), pkt->getSize());
         }
         break;
       default:
index 02308b2ef90355ddf9a24676429b94acf52f952b..97bea2ec43a9dfcbf9b87044c5ff4b041ec29445 100644 (file)
@@ -78,6 +78,68 @@ class PhysicalMemory : public MemObject
     const PhysicalMemory &operator=(const PhysicalMemory &specmem);
 
   protected:
+
+    class LockedAddr {
+      public:
+        // on alpha, minimum LL/SC granularity is 16 bytes, so lower
+        // bits need to masked off.
+        static const Addr Addr_Mask = 0xf;
+
+        static Addr mask(Addr paddr) { return (paddr & ~Addr_Mask); }
+
+        Addr addr;     // locked address
+        int cpuNum;    // locking CPU
+        int threadNum; // locking thread ID within CPU
+
+        // check for matching execution context
+        bool matchesContext(Request *req)
+        {
+            return (cpuNum == req->getCpuNum() &&
+                    threadNum == req->getThreadNum());
+        }
+
+        LockedAddr(Request *req)
+            : addr(mask(req->getPaddr())),
+              cpuNum(req->getCpuNum()),
+              threadNum(req->getThreadNum())
+        {
+        }
+    };
+
+    std::list<LockedAddr> lockedAddrList;
+
+    // helper function for checkLockedAddrs(): we really want to
+    // inline a quick check for an empty locked addr list (hopefully
+    // the common case), and do the full list search (if necessary) in
+    // this out-of-line function
+    bool checkLockedAddrList(Request *req);
+
+    // Record the address of a load-locked operation so that we can
+    // clear the execution context's lock flag if a matching store is
+    // performed
+    void trackLoadLocked(Request *req);
+
+    // Compare a store address with any locked addresses so we can
+    // clear the lock flag appropriately.  Return value set to 'false'
+    // if store operation should be suppressed (because it was a
+    // conditional store and the address was no longer locked by the
+    // requesting execution context), 'true' otherwise.  Note that
+    // this method must be called on *all* stores since even
+    // non-conditional stores must clear any matching lock addresses.
+    bool writeOK(Request *req) {
+        if (lockedAddrList.empty()) {
+            // no locked addrs: nothing to check, store_conditional fails
+            bool isLocked = req->isLocked();
+            if (isLocked) {
+                req->setScResult(0);
+            }
+            return !isLocked; // only do write if not an sc
+        } else {
+            // iterate over list...
+            return checkLockedAddrList(req);
+        }
+    }
+
     uint8_t *pmemAddr;
     MemoryPort *port;
     int pagePtr;
index 6acd7526c3180fcf0403ed9e4d7d29d221fd9788..e54984fcde1f6d372399a68821eef07efbf5b472 100644 (file)
@@ -232,9 +232,11 @@ class Request
     Addr getPC() { assert(validPC); return pc; }
 
     /** Accessor Function to Check Cacheability. */
-    bool isUncacheable() { return getFlags() & UNCACHEABLE; }
+    bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; }
 
-    bool isInstRead() { return getFlags() & INST_READ; }
+    bool isInstRead() { return (getFlags() & INST_READ) != 0; }
+
+    bool isLocked() { return (getFlags() & LOCKED) != 0; }
 
     friend class Packet;
 };
index 0b887cceb313b77e1a9059212e0afb8356296417..b6dc08e465d2acc3844e0d26d3614e6b8ba63714 100644 (file)
@@ -11,10 +11,11 @@ class BaseCPU(SimObject):
     mem = Param.MemObject("memory")
 
     system = Param.System(Parent.any, "system object")
+    cpu_id = Param.Int("CPU identifier")
+
     if build_env['FULL_SYSTEM']:
         dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB")
         itb = Param.AlphaITB(AlphaITB(), "Instruction TLB")
-        cpu_id = Param.Int(-1, "CPU identifier")
     else:
         workload = VectorParam.Process("processes to run")
 
index 2bf67f3b11647a535da32e21f6cba153e4bcbf5e..d35ac4ae0e9ec1e16ea90585bd2d7752e04a147d 100644 (file)
@@ -29,7 +29,7 @@
 import m5
 from m5.objects import *
 
-system = System(cpu = AtomicSimpleCPU(),
+system = System(cpu = AtomicSimpleCPU(cpu_id=0),
                 physmem = PhysicalMemory(),
                 membus = Bus())
 system.physmem.port = system.membus.port
index 7bb76db0e498b8b337451d16ea10b4974d261e14..60190b47c8bc28e38535e72ac103b3798555df79 100644 (file)
@@ -36,7 +36,7 @@ class MyCache(BaseCache):
     mshrs = 10
     tgts_per_mshr = 5
 
-cpu = TimingSimpleCPU()
+cpu = TimingSimpleCPU(cpu_id=0)
 cpu.addTwoLevelCacheHierarchy(MyCache(size = '128kB'), MyCache(size = '256kB'),
                               MyCache(size = '2MB'))
 cpu.mem = cpu.dcache
index e3945f7dcd00d7e5297c9cacc5b22b1dc7678fe7..f798213dbfa217c669d7c5806334c5194af6376b 100644 (file)
@@ -34,7 +34,7 @@ import FSConfig
 AlphaConsole.cpu = Parent.cpu[0]
 IntrControl.cpu = Parent.cpu[0]
 
-cpus = [ AtomicSimpleCPU() for i in xrange(2) ]
+cpus = [ AtomicSimpleCPU(cpu_id=i) for i in xrange(2) ]
 system = FSConfig.makeLinuxAlphaSystem('atomic')
 system.cpu = cpus
 for c in cpus:
index ca1dd5c77c1ee9d4dd87ae95571ece32900bc22a..623d285e4278f9c912852acae66acb76e562e815 100644 (file)
@@ -31,7 +31,7 @@ from m5.objects import *
 m5.AddToPath('../configs/common')
 import FSConfig
 
-cpu = AtomicSimpleCPU()
+cpu = AtomicSimpleCPU(cpu_id=0)
 system = FSConfig.makeLinuxAlphaSystem('atomic')
 system.cpu = cpu
 cpu.connectMemPorts(system.membus)
index 967d6a2d29654570a67111ede948d85386c9961a..bf94214fd8aa1d5359c77f0750f8e5fa604d8fbf 100644 (file)
@@ -34,7 +34,7 @@ import FSConfig
 AlphaConsole.cpu = Parent.cpu[0]
 IntrControl.cpu = Parent.cpu[0]
 
-cpus = [ TimingSimpleCPU() for i in xrange(2) ]
+cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(2) ]
 system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpus
 for c in cpus:
index b3fc9d105d7ed46185285e0d2ea9b10435435aac..2edf5ac3203b62c8fd11aa96c3384d638946cb98 100644 (file)
@@ -31,7 +31,7 @@ from m5.objects import *
 m5.AddToPath('../configs/common')
 import FSConfig
 
-cpu = TimingSimpleCPU()
+cpu = TimingSimpleCPU(cpu_id=0)
 system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpu
 cpu.connectMemPorts(system.membus)