#include "arch/mmaped_ipr.hh"
#include "arch/utility.hh"
#include "base/bigint.hh"
+#include "config/the_isa.hh"
#include "cpu/exetrace.hh"
#include "cpu/simple/atomic.hh"
#include "mem/packet.hh"
}
Port *
-AtomicSimpleCPU::getPort(const std::string &if_name, int idx)
+AtomicSimpleCPU::getPort(const string &if_name, int idx)
{
if (if_name == "dcache_port")
return &dcachePort;
AtomicSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
- for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadID size = threadContexts.size();
+ for (ThreadID i = 0; i < size; ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, tc->contextId());
}
#endif
if (hasPhysMemPort) {
physmemPort.getPeerAddressRanges(pmAddrList, snoop);
physMemAddr = *pmAddrList.begin();
}
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ // Atomic doesn't do MT right now, so contextId == threadId
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
bool
}
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
- : BaseSimpleCPU(p), tickEvent(this), width(p->width),
+ : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
simulate_data_stalls(p->simulate_data_stalls),
simulate_inst_stalls(p->simulate_inst_stalls),
icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
AtomicSimpleCPU::~AtomicSimpleCPU()
{
+ if (tickEvent.scheduled()) {
+ deschedule(tickEvent);
+ }
}
void
{
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
+ SERIALIZE_SCALAR(locked);
BaseSimpleCPU::serialize(os);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
{
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
+ UNSERIALIZE_SCALAR(locked);
BaseSimpleCPU::unserialize(cp, section);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
}
// if any of this CPU's ThreadContexts are active, mark the CPU as
// running and schedule its tick event.
- for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadID size = threadContexts.size();
+ for (ThreadID i = 0; i < size; ++i) {
ThreadContext *tc = threadContexts[i];
if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
assert(thread_num == 0);
assert(thread);
+ if (_status == Idle)
+ return;
+
assert(_status == Running);
// tick event may not be scheduled if this gets called from inside
}
//The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
+ unsigned blockSize = dcachePort.peerBlockSize();
//The size of the data we're trying to read.
int dataSize = sizeof(T);
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
// Now do the access.
- if (fault == NoFault) {
+ if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
Packet pkt = Packet(req,
- req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
+ req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
Packet::Broadcast);
pkt.dataStatic(dataPtr);
assert(!pkt.isError());
- if (req->isLocked()) {
+ if (req->isLLSC()) {
TheISA::handleLockedRead(thread, req);
}
}
recordEvent("Uncached Read");
//If there's a fault, return it
- if (fault != NoFault)
- return fault;
+ if (fault != NoFault) {
+ if (req->isPrefetch()) {
+ return NoFault;
+ } else {
+ return fault;
+ }
+ }
+
//If we don't need to access a second cache line, stop now.
if (secondAddr <= addr)
{
if (traceData) {
traceData->setData(data);
}
+ if (req->isLocked() && fault == NoFault) {
+ assert(!locked);
+ locked = true;
+ }
return fault;
}
}
}
-Fault
-AtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated read request and packet objects
- Request *req = &data_read_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize);
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
-
- //If there's a fault, return it
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- //If we don't need to access a second cache line, stop now.
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
}
//The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
+ unsigned blockSize = dcachePort.peerBlockSize();
//The size of the data we're trying to read.
int dataSize = sizeof(T);
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
// Now do the access.
if (fault == NoFault) {
MemCmd cmd = MemCmd::WriteReq; // default
bool do_access = true; // flag to suppress cache access
- if (req->isLocked()) {
+ if (req->isLLSC()) {
cmd = MemCmd::StoreCondReq;
do_access = TheISA::handleLockedWrite(thread, req);
} else if (req->isSwap()) {
}
}
- if (do_access) {
+ if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
Packet pkt = Packet(req, cmd, Packet::Broadcast);
pkt.dataStatic(dataPtr);
// calling changeStatus() and changing it to "bad addr write"
// or something.
if (traceData) {
- traceData->setData(data);
+ traceData->setData(gtoh(data));
+ }
+ if (req->isLocked() && fault == NoFault) {
+ assert(locked);
+ locked = false;
+ }
+ if (fault != NoFault && req->isPrefetch()) {
+ return NoFault;
+ } else {
+ return fault;
}
- return fault;
}
/*
}
}
-Fault
-AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated write request and packet objects
- Request *req = &data_write_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + size - 1, blockSize);
-
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- dcache_latency = 0;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- //If there's a fault or we don't need to access a second cache line,
- //stop now.
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
Tick latency = 0;
- for (int i = 0; i < width; ++i) {
+ for (int i = 0; i < width || locked; ++i) {
numCycles++;
if (!curStaticInst || !curStaticInst->isDelayedCommit())
Fault fault = NoFault;
bool fromRom = isRomMicroPC(thread->readMicroPC());
- if (!fromRom)
- fault = setupFetchRequest(&ifetch_req);
+ if (!fromRom && !curMacroStaticInst) {
+ setupFetchRequest(&ifetch_req);
+ fault = thread->itb->translateAtomic(&ifetch_req, tc,
+ BaseTLB::Execute);
+ }
if (fault == NoFault) {
Tick icache_latency = 0;
bool icache_access = false;
dcache_access = false; // assume no dcache access
- if (!fromRom) {
+ if (!fromRom && !curMacroStaticInst) {
// This is commented out because the predecoder would act like
// a tiny cache otherwise. It wouldn't be flushed when needed
// like the I cache. It should be flushed, and when that works