summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2006-03-02 10:31:48 -0500
committerSteve Reinhardt <stever@eecs.umich.edu>2006-03-02 10:31:48 -0500
commite7f442d5273bec95f3412cdc5a82742fe32f8cf3 (patch)
tree754efd78eb14fbc59700f4f275efb9a7b29930d2 /cpu
parent0c2c7171a83f772b297016aa7382157f070b3466 (diff)
downloadgem5-e7f442d5273bec95f3412cdc5a82742fe32f8cf3.tar.xz
Simple program runs with sendAtomic!
Ignoring returned latency for now. Refactored loadSections in ObjectFile hierarchy. base/loader/aout_object.cc: base/loader/aout_object.hh: base/loader/ecoff_object.cc: base/loader/ecoff_object.hh: base/loader/elf_object.cc: base/loader/elf_object.hh: base/loader/object_file.hh: Have each section record a pointer to image data. This allows us to move common loadSections code into ObjectFile. base/loader/object_file.cc: Have each section record a pointer to image data. This allows us to move common loadSections code into ObjectFile. Also explicitly load BSS now since we need to allocate the translations for it in syscall emulation. cpu/base.hh: Don't need memPort (just pass port in to ExecContext constructor). cpu/exec_context.cc: cpu/exec_context.hh: mem/port.cc: mem/translating_port.cc: mem/translating_port.hh: Pass syscall emulation Port into constructor instead of getting it from BaseCPU. cpu/simple/cpu.cc: Explicitly choose one of three timing models. Statically allocate request and packet objects when possible. Several more minor bug fixes. Works for simple program with SIMPLE_CPU_MEM_IMMEDIATE model now. Probably have memory leaks with SIMPLE_CPU_MEM_TIMING (if it works at all). Pass syscall emulation Port into constructor instead of getting it from BaseCPU. cpu/simple/cpu.hh: Explicitly choose one of three timing models. Statically allocate request and packet objects when possible. Pass syscall emulation Port into constructor instead of getting it from BaseCPU. mem/physical.cc: Set packet result field. --HG-- extra : convert_revision : 359d0ebe4b4665867f4e26e7394ec0f1d17cfc26
Diffstat (limited to 'cpu')
-rw-r--r--cpu/base.hh8
-rw-r--r--cpu/exec_context.cc6
-rw-r--r--cpu/exec_context.hh4
-rw-r--r--cpu/simple/cpu.cc210
-rw-r--r--cpu/simple/cpu.hh26
5 files changed, 166 insertions, 88 deletions
diff --git a/cpu/base.hh b/cpu/base.hh
index 870e26a39..c0e087f42 100644
--- a/cpu/base.hh
+++ b/cpu/base.hh
@@ -155,14 +155,6 @@ class BaseCPU : public SimObject
int number_of_threads;
/**
- * A pointer to the port into the memory system to be used by syscall
- * emulation. This way the data being accessed via syscalls looks in
- * the memory heirachy for any changes that haven't been written back
- * to main memory yet.
- */
- Port* memPort;
-
- /**
* Vector of per-thread instruction-based event queues. Used for
* scheduling events based on number of instructions committed by
* a particular thread.
diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc
index fa91eb672..0b91992cf 100644
--- a/cpu/exec_context.cc
+++ b/cpu/exec_context.cc
@@ -37,13 +37,13 @@
#include "base/output.hh"
#include "cpu/profile.hh"
#include "kern/kernel_stats.hh"
-#include "mem/translating_port.hh"
#include "sim/serialize.hh"
#include "sim/sim_exit.hh"
#include "sim/system.hh"
#include "targetarch/stacktrace.hh"
#else
#include "sim/process.hh"
+#include "mem/translating_port.hh"
#endif
using namespace std;
@@ -78,14 +78,14 @@ ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
}
#else
ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
- Process *_process, int _asid)
+ Process *_process, int _asid, Port *mem_port)
: _status(ExecContext::Unallocated),
cpu(_cpu), thread_num(_thread_num), cpu_id(-1),
process(_process),
asid(_asid),
func_exe_inst(0), storeCondFailures(0)
{
- port = new TranslatingPort(cpu->memPort, process->pTable);
+ port = new TranslatingPort(mem_port, process->pTable);
memset(&regs, 0, sizeof(RegFile));
}
#endif
diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh
index 8e9e5f2fd..f55b45de1 100644
--- a/cpu/exec_context.hh
+++ b/cpu/exec_context.hh
@@ -35,7 +35,6 @@
#include "sim/host.hh"
#include "sim/serialize.hh"
#include "targetarch/byte_swap.hh"
-#include "mem/translating_port.hh"
class BaseCPU;
@@ -52,6 +51,7 @@ namespace Kernel { class Binning; class Statistics; }
#else // !FULL_SYSTEM
#include "sim/process.hh"
+class TranslatingPort;
#endif // FULL_SYSTEM
@@ -187,7 +187,7 @@ class ExecContext
AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem);
#else
ExecContext(BaseCPU *_cpu, int _thread_num,
- Process *_process, int _asid);
+ Process *_process, int _asid, Port *mem_port);
#endif
virtual ~ExecContext();
diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc
index 41acd2456..d8d4c3644 100644
--- a/cpu/simple/cpu.cc
+++ b/cpu/simple/cpu.cc
@@ -132,16 +132,6 @@ SimpleCPU::SimpleCPU(Params *p)
dcachePort(this), tickEvent(this, p->width), xc(NULL)
{
_status = Idle;
-#if FULL_SYSTEM
- xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
-
- // initialize CPU, including PC
- TheISA::initCPU(&xc->regs);
-#else
- xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);
-#endif // !FULL_SYSTEM
-
- memPort = &dcachePort;
//Create Memory Ports (conect them up)
p->mem->addPort("DCACHE");
@@ -152,11 +142,39 @@ SimpleCPU::SimpleCPU(Params *p)
icachePort.setPeer(p->mem->getPort("ICACHE"));
(p->mem->getPort("ICACHE"))->setPeer(&icachePort);
+#if FULL_SYSTEM
+ xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
+ // initialize CPU, including PC
+ TheISA::initCPU(&xc->regs);
+#else
+ xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
+ &dcachePort);
+#endif // !FULL_SYSTEM
- req = new CpuRequest;
-
- req->asid = 0;
+#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
+ ifetch_req = new CpuRequest;
+ ifetch_req->asid = 0;
+ ifetch_req->size = sizeof(MachInst);
+ ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->data = (uint8_t *)&inst;
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+
+ data_read_req = new CpuRequest;
+ data_read_req->asid = 0;
+ data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->data = new uint8_t[8];
+ data_read_pkt->req = data_read_req;
+
+ data_write_req = new CpuRequest;
+ data_write_req->asid = 0;
+ data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+#endif
numInst = 0;
startNumInst = 0;
@@ -425,6 +443,7 @@ SimpleCPU::copy(Addr dest)
}
return fault;
#else
+ panic("copy not implemented");
return No_Fault;
#endif
}
@@ -437,8 +456,8 @@ SimpleCPU::read(Addr addr, T &data, unsigned flags)
if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) {
// Fault fault = xc->read(memReq,data);
// Not sure what to check for no fault...
- if (pkt->result == Success) {
- memcpy(&data, pkt->data, sizeof(T));
+ if (data_read_pkt->result == Success) {
+ memcpy(&data, data_read_pkt->data, sizeof(T));
}
if (traceData) {
@@ -451,19 +470,45 @@ SimpleCPU::read(Addr addr, T &data, unsigned flags)
// memReq->reset(addr, sizeof(T), flags);
+#if SIMPLE_CPU_MEM_TIMING
+ CpuRequest *data_read_req = new CpuRequest;
+#endif
+
+ data_read_req->vaddr = addr;
+ data_read_req->size = sizeof(T);
+ data_read_req->flags = flags;
+ data_read_req->time = curTick;
+
// translate to physical address
- // NEED NEW TRANSLATION HERE
- Fault fault = xc->translateDataReadReq(req);
+ Fault fault = xc->translateDataReadReq(data_read_req);
// Now do the access.
if (fault == No_Fault) {
- pkt = new Packet;
- pkt->cmd = Read;
- req->paddr = addr;
- pkt->size = sizeof(T);
- pkt->req = req;
+#if SIMPLE_CPU_MEM_TIMING
+ data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->req = data_read_req;
+ data_read_pkt->data = new uint8_t[8];
+#endif
+ data_read_pkt->addr = data_read_req->paddr;
+ data_read_pkt->size = sizeof(T);
+
+ sendDcacheRequest(data_read_pkt);
+
+#if SIMPLE_CPU_MEM_IMMEDIATE
+ // Need to find a way to not duplicate code above.
- sendDcacheRequest();
+ if (data_read_pkt->result == Success) {
+ memcpy(&data, data_read_pkt->data, sizeof(T));
+ }
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+
+ // @todo: Figure out a way to create a Fault from the packet result.
+ return No_Fault;
+#endif
}
/*
memReq->cmd = Read;
@@ -493,7 +538,7 @@ SimpleCPU::read(Addr addr, T &data, unsigned flags)
}
*/
// This will need a new way to tell if it has a dcache attached.
- if (/*!dcacheInterface && */(req->flags & UNCACHEABLE))
+ if (data_read_req->flags & UNCACHEABLE)
recordEvent("Uncached Read");
return fault;
@@ -546,27 +591,29 @@ template <class T>
Fault
SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
-// memReq->reset(addr, sizeof(T), flags);
- req->vaddr = addr;
- req->time = curTick;
- req->size = sizeof(T);
+ data_write_req->vaddr = addr;
+ data_write_req->time = curTick;
+ data_write_req->size = sizeof(T);
+ data_write_req->flags = flags;
// translate to physical address
- // NEED NEW TRANSLATION HERE
- Fault fault = xc->translateDataWriteReq(req);
+ Fault fault = xc->translateDataWriteReq(data_write_req);
// Now do the access.
if (fault == No_Fault) {
- pkt = new Packet;
- pkt->cmd = Write;
- pkt->size = sizeof(T);
- pkt->req = req;
-
- // Copy data into the packet.
- pkt->data = new uint8_t[64];
- memcpy(pkt->data, &data, sizeof(T));
+#if SIMPLE_CPU_MEM_TIMING
+ data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+ data_write_pkt->data = new uint8_t[64];
+ memcpy(data_write_pkt->data, &data, sizeof(T));
+#else
+ data_write_pkt->data = (uint8_t *)&data;
+#endif
+ data_write_pkt->addr = data_write_req->paddr;
+ data_write_pkt->size = sizeof(T);
- sendDcacheRequest();
+ sendDcacheRequest(data_write_pkt);
}
/*
@@ -594,10 +641,10 @@ SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
}
*/
if (res && (fault == No_Fault))
- *res = pkt->result;
+ *res = data_write_pkt->result;
// This will need a new way to tell if it's hooked up to a cache or not.
- if (/*!dcacheInterface && */(req->flags & UNCACHEABLE))
+ if (data_write_req->flags & UNCACHEABLE)
recordEvent("Uncached Write");
// If the write needs to have a fault on the access, consider calling
@@ -657,9 +704,11 @@ SimpleCPU::dbg_vtophys(Addr addr)
#endif // FULL_SYSTEM
void
-SimpleCPU::sendIcacheRequest()
+SimpleCPU::sendIcacheRequest(Packet *pkt)
{
-#if 0
+ assert(!tickEvent.scheduled());
+#if SIMPLE_CPU_MEM_TIMING
+ retry_pkt = pkt;
bool success = icachePort.sendTiming(*pkt);
unscheduleTickEvent();
@@ -673,7 +722,7 @@ SimpleCPU::sendIcacheRequest()
// Need to wait for cache to respond
_status = IcacheWaitResponse;
}
-#else
+#elif SIMPLE_CPU_MEM_ATOMIC
Tick latency = icachePort.sendAtomic(*pkt);
unscheduleTickEvent();
@@ -685,17 +734,21 @@ SimpleCPU::sendIcacheRequest()
icacheStallCycles += latency;
_status = IcacheAccessComplete;
-
- delete pkt;
+#elif SIMPLE_CPU_MEM_IMMEDIATE
+ icachePort.sendAtomic(*pkt);
+#else
+#error "SimpleCPU has no mem model set"
#endif
}
void
-SimpleCPU::sendDcacheRequest()
+SimpleCPU::sendDcacheRequest(Packet *pkt)
{
+ assert(!tickEvent.scheduled());
+#if SIMPLE_CPU_MEM_TIMING
unscheduleTickEvent();
-#if 0
+ retry_pkt = pkt;
bool success = dcachePort.sendTiming(*pkt);
lastDcacheStall = curTick;
@@ -705,7 +758,9 @@ SimpleCPU::sendDcacheRequest()
} else {
_status = DcacheWaitResponse;
}
-#else
+#elif SIMPLE_CPU_MEM_ATOMIC
+ unscheduleTickEvent();
+
Tick latency = dcachePort.sendAtomic(*pkt);
scheduleTickEvent(latency);
@@ -714,19 +769,22 @@ SimpleCPU::sendDcacheRequest()
// we check the status of the packet sent (is this valid?),
// we won't know if the latency is a hit or a miss.
dcacheStallCycles += latency;
-
- // Delete the packet right here?
- delete pkt;
+#elif SIMPLE_CPU_MEM_IMMEDIATE
+ dcachePort.sendAtomic(*pkt);
+#else
+#error "SimpleCPU has no mem model set"
#endif
}
void
SimpleCPU::processResponse(Packet &response)
{
+ assert(SIMPLE_CPU_MEM_TIMING);
+
// For what things is the CPU the consumer of the packet it sent
// out? This may create a memory leak if that's the case and it's
// expected of the SimpleCPU to delete its own packet.
- pkt = &response;
+ Packet *pkt = &response;
switch (status()) {
case IcacheWaitResponse:
@@ -780,19 +838,23 @@ SimpleCPU::processResponse(Packet &response)
Packet *
SimpleCPU::processRetry()
{
+#if SIMPLE_CPU_MEM_TIMING
switch(status()) {
case IcacheRetry:
icacheRetryCycles += curTick - lastIcacheStall;
- return pkt;
+ return retry_pkt;
break;
case DcacheRetry:
dcacheRetryCycles += curTick - lastDcacheStall;
- return pkt;
+ return retry_pkt;
break;
default:
panic("SimpleCPU::processRetry: bad state");
break;
}
+#else
+ panic("shouldn't be here");
+#endif
}
#if FULL_SYSTEM
@@ -884,28 +946,35 @@ SimpleCPU::tick()
#define IFETCH_FLAGS(pc) 0
#endif
- req->vaddr = xc->regs.pc & ~3;
- req->time = curTick;
- req->size = sizeof(MachInst);
+#if SIMPLE_CPU_MEM_TIMING
+ CpuRequest *ifetch_req = new CpuRequest();
+ ifetch_req->size = sizeof(MachInst);
+#endif
+
+ ifetch_req->vaddr = xc->regs.pc & ~3;
+ ifetch_req->time = curTick;
/* memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
IFETCH_FLAGS(xc->regs.pc));
*/
- fault = xc->translateInstReq(req);
+ fault = xc->translateInstReq(ifetch_req);
if (fault == No_Fault) {
- pkt = new Packet;
- pkt->cmd = Read;
- pkt->addr = req->paddr;
- pkt->size = sizeof(MachInst);
- pkt->req = req;
- pkt->data = (uint8_t *)&inst;
-
- sendIcacheRequest();
- return;
-/* fault = xc->mem->read(memReq, inst);
+#if SIMPLE_CPU_MEM_TIMING
+ Packet *ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->data = (uint8_t *)&inst;
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+#endif
+ ifetch_pkt->addr = ifetch_req->paddr;
+ sendIcacheRequest(ifetch_pkt);
+#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC
+ return;
+#endif
+/*
if (icacheInterface && fault == No_Fault) {
memReq->completionEvent = NULL;
@@ -980,8 +1049,7 @@ SimpleCPU::tick()
// If we have a dcache miss, then we can't finialize the instruction
// trace yet because we want to populate it with the data later
- if (traceData &&
- !(status() == DcacheWaitResponse && pkt->cmd == Read)) {
+ if (traceData && (status() != DcacheWaitResponse)) {
traceData->finalize();
}
diff --git a/cpu/simple/cpu.hh b/cpu/simple/cpu.hh
index 3354166cc..ca10134f7 100644
--- a/cpu/simple/cpu.hh
+++ b/cpu/simple/cpu.hh
@@ -64,6 +64,16 @@ namespace Trace {
class InstRecord;
}
+
+// Set exactly one of these symbols to 1 to set the memory access
+// model. Probably should make these template parameters, or even
+// just fork the CPU models.
+//
+#define SIMPLE_CPU_MEM_TIMING 0
+#define SIMPLE_CPU_MEM_ATOMIC 0
+#define SIMPLE_CPU_MEM_IMMEDIATE 1
+
+
class SimpleCPU : public BaseCPU
{
class CpuPort : public Port
@@ -188,8 +198,16 @@ class SimpleCPU : public BaseCPU
// current instruction
MachInst inst;
- CpuRequest *req;
- Packet *pkt;
+#if SIMPLE_CPU_MEM_TIMING
+ Packet *retry_pkt;
+#elif SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
+ CpuRequest *ifetch_req;
+ Packet *ifetch_pkt;
+ CpuRequest *data_read_req;
+ Packet *data_read_pkt;
+ CpuRequest *data_write_req;
+ Packet *data_write_pkt;
+#endif
// Pointer to the sampler that is telling us to switchover.
// Used to signal the completion of the pipe drain and schedule
@@ -246,8 +264,8 @@ class SimpleCPU : public BaseCPU
Stats::Scalar<> dcacheRetryCycles;
Counter lastDcacheRetry;
- void sendIcacheRequest();
- void sendDcacheRequest();
+ void sendIcacheRequest(Packet *pkt);
+ void sendDcacheRequest(Packet *pkt);
void processResponse(Packet &response);
Packet * processRetry();