Implement Alpha LL/SC support for SimpleCPU (Atomic & Timing)

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
This commit is contained in:
Steve Reinhardt 2006-10-08 10:53:24 -07:00
parent be36c808f7
commit d3fba5aa30
19 changed files with 465 additions and 53 deletions

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -112,6 +112,7 @@ baseFlags = [
'IdeDisk',
'InstExec',
'Interrupt',
'LLSC',
'LSQ',
'LSQUnit',
'Loader',

View 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;

View 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);
if (res && req->getFlags() & LOCKED) {
*res = req->getScResult();
dcache_latency = dcachePort.sendAtomic(pkt);
dcache_access = true;
assert(pkt->result == Packet::Success);
}
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;

View 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;

View 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);

View 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:

View 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;

View 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;
};

View 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")

View 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

View 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

View 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:

View 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)

View 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:

View 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)