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 arguments.hh
faults.hh faults.hh
isa_traits.hh isa_traits.hh
locked_mem.hh
process.hh process.hh
regfile.hh regfile.hh
stacktrace.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', 'IdeDisk',
'InstExec', 'InstExec',
'Interrupt', 'Interrupt',
'LLSC',
'LSQ', 'LSQ',
'LSQUnit', 'LSQUnit',
'Loader', 'Loader',

View file

@ -140,8 +140,8 @@ class BaseCPU : public MemObject
bool functionTrace; bool functionTrace;
Tick functionTraceStart; Tick functionTraceStart;
System *system; System *system;
#if FULL_SYSTEM
int cpu_id; int cpu_id;
#if FULL_SYSTEM
Tick profile; Tick profile;
#endif #endif
Tick progress_interval; Tick progress_interval;

View file

@ -28,6 +28,7 @@
* Authors: Steve Reinhardt * Authors: Steve Reinhardt
*/ */
#include "arch/locked_mem.hh"
#include "arch/utility.hh" #include "arch/utility.hh"
#include "cpu/exetrace.hh" #include "cpu/exetrace.hh"
#include "cpu/simple/atomic.hh" #include "cpu/simple/atomic.hh"
@ -133,20 +134,19 @@ AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
{ {
_status = Idle; _status = Idle;
// @todo fix me and get the real cpu id & thread number!!!
ifetch_req = new Request(); 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 = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
ifetch_pkt->dataStatic(&inst); ifetch_pkt->dataStatic(&inst);
data_read_req = new Request(); 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, data_read_pkt = new Packet(data_read_req, Packet::ReadReq,
Packet::Broadcast); Packet::Broadcast);
data_read_pkt->dataStatic(&dataReg); data_read_pkt->dataStatic(&dataReg);
data_write_req = new Request(); 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, data_write_pkt = new Packet(data_write_req, Packet::WriteReq,
Packet::Broadcast); Packet::Broadcast);
} }
@ -275,6 +275,10 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
assert(pkt->result == Packet::Success); assert(pkt->result == Packet::Success);
data = pkt->get<T>(); 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. // 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. // Now do the access.
if (fault == NoFault) { if (fault == NoFault) {
data = htog(data); bool do_access = true; // flag to suppress cache access
pkt->reinitFromRequest();
pkt->dataStatic(&data);
dcache_latency = dcachePort.sendAtomic(pkt); if (req->isLocked()) {
dcache_access = true; 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) { dcache_latency = dcachePort.sendAtomic(pkt);
*res = req->getScResult(); 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; Param<Tick> progress_interval;
SimObjectParam<MemObject *> mem; SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system; SimObjectParam<System *> system;
Param<int> cpu_id;
#if FULL_SYSTEM #if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb; SimObjectParam<AlphaDTB *> dtb;
Param<int> cpu_id;
Param<Tick> profile; Param<Tick> profile;
#else #else
SimObjectParam<Process *> workload; SimObjectParam<Process *> workload;
@ -507,11 +526,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
INIT_PARAM(progress_interval, "Progress interval"), INIT_PARAM(progress_interval, "Progress interval"),
INIT_PARAM(mem, "memory"), INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"), INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"),
#if FULL_SYSTEM #if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""), INIT_PARAM(profile, ""),
#else #else
INIT_PARAM(workload, "processes to run"), INIT_PARAM(workload, "processes to run"),
@ -545,11 +564,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU)
params->simulate_stalls = simulate_stalls; params->simulate_stalls = simulate_stalls;
params->mem = mem; params->mem = mem;
params->system = system; params->system = system;
params->cpu_id = cpu_id;
#if FULL_SYSTEM #if FULL_SYSTEM
params->itb = itb; params->itb = itb;
params->dtb = dtb; params->dtb = dtb;
params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
#else #else
params->process = workload; params->process = workload;

View file

@ -28,6 +28,7 @@
* Authors: Steve Reinhardt * Authors: Steve Reinhardt
*/ */
#include "arch/locked_mem.hh"
#include "arch/utility.hh" #include "arch/utility.hh"
#include "cpu/exetrace.hh" #include "cpu/exetrace.hh"
#include "cpu/simple/timing.hh" #include "cpu/simple/timing.hh"
@ -94,7 +95,8 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(Packet *_pkt, Tick t)
} }
TimingSimpleCPU::TimingSimpleCPU(Params *p) 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; _status = Idle;
ifetch_pkt = dcache_pkt = NULL; ifetch_pkt = dcache_pkt = NULL;
@ -229,7 +231,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
{ {
Request *req = Request *req =
new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
/* CPU ID */ 0, /* thread ID */ 0); cpu_id, /* thread ID */ 0);
if (traceData) { if (traceData) {
traceData->setAddr(req->getVaddr()); traceData->setAddr(req->getVaddr());
@ -310,7 +312,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{ {
Request *req = Request *req =
new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 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 // translate to physical address
Fault fault = thread->translateDataWriteReq(req); 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->allocate();
dcache_pkt->set(data); dcache_pkt->set(data);
if (!dcachePort.sendTiming(dcache_pkt)) { bool do_access = true; // flag to suppress cache access
_status = DcacheRetry;
} else { if (req->isLocked()) {
_status = DcacheWaitResponse; do_access = TheISA::handleLockedWrite(thread, req);
// memory system takes ownership of packet }
dcache_pkt = NULL;
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(); checkForInterrupts();
// need to fill in CPU & thread IDs here
Request *ifetch_req = new Request(); 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); Fault fault = setupFetchRequest(ifetch_req);
ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
@ -453,12 +462,20 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
// load or store: just send to dcache // load or store: just send to dcache
Fault fault = curStaticInst->initiateAcc(this, traceData); Fault fault = curStaticInst->initiateAcc(this, traceData);
if (fault == NoFault) { if (_status != Running) {
// successfully initiated access: instruction will // instruction will complete in dcache response callback
// complete in dcache response callback assert(_status == DcacheWaitResponse || _status == DcacheRetry);
assert(_status == DcacheWaitResponse); assert(fault == NoFault);
} else { } 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(); postExecute();
advanceInst(fault); advanceInst(fault);
} }
@ -479,8 +496,7 @@ TimingSimpleCPU::IcachePort::ITickEvent::process()
bool bool
TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
{ {
// These next few lines could be replaced with something faster // delay processing of returned data until next CPU clock edge
// who knows what though
Tick time = pkt->req->getTime(); Tick time = pkt->req->getTime();
while (time < curTick) while (time < curTick)
time += lat; time += lat;
@ -527,6 +543,10 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
Fault fault = curStaticInst->completeAcc(pkt, this, traceData); Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
if (pkt->isRead() && pkt->req->isLocked()) {
TheISA::handleLockedRead(thread, pkt->req);
}
delete pkt->req; delete pkt->req;
delete pkt; delete pkt;
@ -546,6 +566,7 @@ TimingSimpleCPU::completeDrain()
bool bool
TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
{ {
// delay processing of returned data until next CPU clock edge
Tick time = pkt->req->getTime(); Tick time = pkt->req->getTime();
while (time < curTick) while (time < curTick)
time += lat; time += lat;
@ -574,6 +595,7 @@ TimingSimpleCPU::DcachePort::recvRetry()
Packet *tmp = cpu->dcache_pkt; Packet *tmp = cpu->dcache_pkt;
if (sendTiming(tmp)) { if (sendTiming(tmp)) {
cpu->_status = DcacheWaitResponse; cpu->_status = DcacheWaitResponse;
// memory system takes ownership of packet
cpu->dcache_pkt = NULL; cpu->dcache_pkt = NULL;
} }
} }
@ -592,11 +614,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
Param<Tick> progress_interval; Param<Tick> progress_interval;
SimObjectParam<MemObject *> mem; SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system; SimObjectParam<System *> system;
Param<int> cpu_id;
#if FULL_SYSTEM #if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb; SimObjectParam<AlphaDTB *> dtb;
Param<int> cpu_id;
Param<Tick> profile; Param<Tick> profile;
#else #else
SimObjectParam<Process *> workload; SimObjectParam<Process *> workload;
@ -625,11 +647,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
INIT_PARAM(progress_interval, "Progress interval"), INIT_PARAM(progress_interval, "Progress interval"),
INIT_PARAM(mem, "memory"), INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"), INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"),
#if FULL_SYSTEM #if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""), INIT_PARAM(profile, ""),
#else #else
INIT_PARAM(workload, "processes to run"), INIT_PARAM(workload, "processes to run"),
@ -661,11 +683,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
params->functionTraceStart = function_trace_start; params->functionTraceStart = function_trace_start;
params->mem = mem; params->mem = mem;
params->system = system; params->system = system;
params->cpu_id = cpu_id;
#if FULL_SYSTEM #if FULL_SYSTEM
params->itb = itb; params->itb = itb;
params->dtb = dtb; params->dtb = dtb;
params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
#else #else
params->process = workload; params->process = workload;

View file

@ -166,6 +166,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
Packet *ifetch_pkt; Packet *ifetch_pkt;
Packet *dcache_pkt; Packet *dcache_pkt;
int cpu_id;
public: public:
virtual Port *getPort(const std::string &if_name, int idx = -1); virtual Port *getPort(const std::string &if_name, int idx = -1);

View file

@ -110,6 +110,88 @@ PhysicalMemory::calculateLatency(Packet *pkt)
return lat; 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 void
PhysicalMemory::doFunctionalAccess(Packet *pkt) PhysicalMemory::doFunctionalAccess(Packet *pkt)
{ {
@ -117,18 +199,17 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt)
switch (pkt->cmd) { switch (pkt->cmd) {
case Packet::ReadReq: case Packet::ReadReq:
if (pkt->req->isLocked()) {
trackLoadLocked(pkt->req);
}
memcpy(pkt->getPtr<uint8_t>(), memcpy(pkt->getPtr<uint8_t>(),
pmemAddr + pkt->getAddr() - params()->addrRange.start, pmemAddr + pkt->getAddr() - params()->addrRange.start,
pkt->getSize()); pkt->getSize());
break; break;
case Packet::WriteReq: case Packet::WriteReq:
memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start, if (writeOK(pkt->req)) {
pkt->getPtr<uint8_t>(), memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
pkt->getSize()); 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);
} }
break; break;
default: default:

View file

@ -78,6 +78,68 @@ class PhysicalMemory : public MemObject
const PhysicalMemory &operator=(const PhysicalMemory &specmem); const PhysicalMemory &operator=(const PhysicalMemory &specmem);
protected: 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; uint8_t *pmemAddr;
MemoryPort *port; MemoryPort *port;
int pagePtr; int pagePtr;

View file

@ -232,9 +232,11 @@ class Request
Addr getPC() { assert(validPC); return pc; } Addr getPC() { assert(validPC); return pc; }
/** Accessor Function to Check Cacheability. */ /** 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; friend class Packet;
}; };

View file

@ -11,10 +11,11 @@ class BaseCPU(SimObject):
mem = Param.MemObject("memory") mem = Param.MemObject("memory")
system = Param.System(Parent.any, "system object") system = Param.System(Parent.any, "system object")
cpu_id = Param.Int("CPU identifier")
if build_env['FULL_SYSTEM']: if build_env['FULL_SYSTEM']:
dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB") dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB")
itb = Param.AlphaITB(AlphaITB(), "Instruction TLB") itb = Param.AlphaITB(AlphaITB(), "Instruction TLB")
cpu_id = Param.Int(-1, "CPU identifier")
else: else:
workload = VectorParam.Process("processes to run") workload = VectorParam.Process("processes to run")

View file

@ -29,7 +29,7 @@
import m5 import m5
from m5.objects import * from m5.objects import *
system = System(cpu = AtomicSimpleCPU(), system = System(cpu = AtomicSimpleCPU(cpu_id=0),
physmem = PhysicalMemory(), physmem = PhysicalMemory(),
membus = Bus()) membus = Bus())
system.physmem.port = system.membus.port system.physmem.port = system.membus.port

View file

@ -36,7 +36,7 @@ class MyCache(BaseCache):
mshrs = 10 mshrs = 10
tgts_per_mshr = 5 tgts_per_mshr = 5
cpu = TimingSimpleCPU() cpu = TimingSimpleCPU(cpu_id=0)
cpu.addTwoLevelCacheHierarchy(MyCache(size = '128kB'), MyCache(size = '256kB'), cpu.addTwoLevelCacheHierarchy(MyCache(size = '128kB'), MyCache(size = '256kB'),
MyCache(size = '2MB')) MyCache(size = '2MB'))
cpu.mem = cpu.dcache cpu.mem = cpu.dcache

View file

@ -34,7 +34,7 @@ import FSConfig
AlphaConsole.cpu = Parent.cpu[0] AlphaConsole.cpu = Parent.cpu[0]
IntrControl.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 = FSConfig.makeLinuxAlphaSystem('atomic')
system.cpu = cpus system.cpu = cpus
for c in cpus: for c in cpus:

View file

@ -31,7 +31,7 @@ from m5.objects import *
m5.AddToPath('../configs/common') m5.AddToPath('../configs/common')
import FSConfig import FSConfig
cpu = AtomicSimpleCPU() cpu = AtomicSimpleCPU(cpu_id=0)
system = FSConfig.makeLinuxAlphaSystem('atomic') system = FSConfig.makeLinuxAlphaSystem('atomic')
system.cpu = cpu system.cpu = cpu
cpu.connectMemPorts(system.membus) cpu.connectMemPorts(system.membus)

View file

@ -34,7 +34,7 @@ import FSConfig
AlphaConsole.cpu = Parent.cpu[0] AlphaConsole.cpu = Parent.cpu[0]
IntrControl.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 = FSConfig.makeLinuxAlphaSystem('timing')
system.cpu = cpus system.cpu = cpus
for c in cpus: for c in cpus:

View file

@ -31,7 +31,7 @@ from m5.objects import *
m5.AddToPath('../configs/common') m5.AddToPath('../configs/common')
import FSConfig import FSConfig
cpu = TimingSimpleCPU() cpu = TimingSimpleCPU(cpu_id=0)
system = FSConfig.makeLinuxAlphaSystem('timing') system = FSConfig.makeLinuxAlphaSystem('timing')
system.cpu = cpu system.cpu = cpu
cpu.connectMemPorts(system.membus) cpu.connectMemPorts(system.membus)