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:
parent
be36c808f7
commit
d3fba5aa30
19 changed files with 465 additions and 53 deletions
|
@ -50,6 +50,7 @@ isa_switch_hdrs = Split('''
|
|||
arguments.hh
|
||||
faults.hh
|
||||
isa_traits.hh
|
||||
locked_mem.hh
|
||||
process.hh
|
||||
regfile.hh
|
||||
stacktrace.hh
|
||||
|
|
97
src/arch/alpha/locked_mem.hh
Normal file
97
src/arch/alpha/locked_mem.hh
Normal 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
|
62
src/arch/mips/locked_mem.hh
Normal file
62
src/arch/mips/locked_mem.hh
Normal 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
|
62
src/arch/sparc/locked_mem.hh
Normal file
62
src/arch/sparc/locked_mem.hh
Normal 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
|
|
@ -112,6 +112,7 @@ baseFlags = [
|
|||
'IdeDisk',
|
||||
'InstExec',
|
||||
'Interrupt',
|
||||
'LLSC',
|
||||
'LSQ',
|
||||
'LSQUnit',
|
||||
'Loader',
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue