From 21fd15ad9a79510be1f4474e135a22f6742327f6 Mon Sep 17 00:00:00 2001 From: Vilas Sridharan Date: Thu, 6 Mar 2008 00:27:09 -0500 Subject: O3CPU: Don't call dumpInsts if DEBUG is not defined --HG-- extra : convert_revision : 3194bde4c624d118969bfbf92282539963a72245 --- src/cpu/base_dyn_inst_impl.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 5c18ae694..66075c60a 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -171,8 +171,8 @@ BaseDynInst::initVars() ++instcount; if (instcount > 1500) { - cpu->dumpInsts(); #ifdef DEBUG + cpu->dumpInsts(); dumpSNList(); #endif assert(instcount <= 1500); -- cgit v1.2.3 From 93ab43288a75061746701c9d22a355793f330a9c Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Mon, 24 Mar 2008 01:08:02 -0400 Subject: Don't FastAlloc MSHRs since we don't allocate them on the fly. --HG-- extra : convert_revision : 02775cfb460afe6df0df0938c62cccd93a71e775 --- src/cpu/memtest/memtest.hh | 3 ++- src/cpu/o3/lsq_unit.hh | 3 ++- src/cpu/ozone/lw_lsq.hh | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index ac2d0a058..43f141af6 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -35,6 +35,7 @@ #include #include "base/statistics.hh" +#include "base/fast_alloc.hh" #include "params/MemTest.hh" #include "sim/eventq.hh" #include "sim/sim_exit.hh" @@ -116,7 +117,7 @@ class MemTest : public MemObject bool snoopRangeSent; - class MemTestSenderState : public Packet::SenderState + class MemTestSenderState : public Packet::SenderState, public FastAlloc { public: /** Constructor. */ diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 128a71dbc..3ae69723d 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -40,6 +40,7 @@ #include "arch/faults.hh" #include "arch/locked_mem.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" @@ -245,7 +246,7 @@ class LSQUnit { Port *dcachePort; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index 7fc8b6307..2525da76e 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -39,6 +39,7 @@ #include "arch/faults.hh" #include "arch/types.hh" #include "config/full_system.hh" +#include "base/fast_alloc.hh" #include "base/hashmap.hh" #include "cpu/inst_seq.hh" #include "mem/packet.hh" @@ -301,7 +302,7 @@ class OzoneLWLSQ { }; /** Derived class to hold any sender state the LSQ needs. */ - class LSQSenderState : public Packet::SenderState + class LSQSenderState : public Packet::SenderState, public FastAlloc { public: /** Default constructor. */ -- cgit v1.2.3 From ed27c4c52183d9527a0c123b9be84bbe968f4afa Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 8 Apr 2008 11:08:26 -0400 Subject: SCons: Manually specifying header only directories with Dir() works around the problem --HG-- extra : convert_revision : d9713228d934cf4a45114a972603b8bca2bd27d3 --- src/cpu/SConscript | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/SConscript b/src/cpu/SConscript index c7d0c33bd..2abddef22 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -148,6 +148,8 @@ if env['USE_CHECKER']: print i, print ", please set USE_CHECKER=False or use one of those CPU models" Exit(1) +else: + Dir('checker') TraceFlag('Activity') TraceFlag('Commit') -- cgit v1.2.3 From 8af6dc118c28a0d24315290e136204c50f1d6d8a Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Thu, 10 Apr 2008 15:38:10 -0400 Subject: SCons: add comments to SConscript documenting bug workaround --HG-- extra : convert_revision : e6cdffe953d56b96c76c7ff14d2dcc3de3ccfcc3 --- src/cpu/SConscript | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/SConscript b/src/cpu/SConscript index 2abddef22..c6a959d9d 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -148,6 +148,8 @@ if env['USE_CHECKER']: print i, print ", please set USE_CHECKER=False or use one of those CPU models" Exit(1) +# Workaround for bug in SCons version > 0.97d20071212 +# Scons bug id: 2006 M5 Bug id: 308 else: Dir('checker') -- cgit v1.2.3 From d093fcb07924cc4341b8142c448b905dd94f7125 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 12 Jun 2008 00:35:50 -0400 Subject: CPU: Make the simple cpu trace data for loads/stores. --- src/cpu/simple/atomic.cc | 6 ++++++ src/cpu/simple/timing.cc | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 23bd40b9b..acd280568 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -355,6 +355,9 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) if (secondAddr <= addr) { data = gtoh(data); + if (traceData) { + traceData->setData(data); + } return fault; } @@ -568,6 +571,9 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) // If the write needs to have a fault on the access, consider // calling changeStatus() and changing it to "bad addr write" // or something. + if (traceData) { + traceData->setData(data); + } return fault; } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index a76824ff3..d0c7dd787 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -296,6 +296,9 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) delete req; } + if (traceData) { + traceData->setData(data); + } return fault; } @@ -431,6 +434,9 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) delete req; } + if (traceData) { + traceData->setData(data); + } // If the write needs to have a fault on the access, consider calling // changeStatus() and changing it to "bad addr write" or something. -- cgit v1.2.3 From e3c267a3dbe628516777dd74662c786ef4eedceb Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sun, 15 Jun 2008 21:34:32 -0700 Subject: port: Clean up default port setup and port switchover code. --- src/cpu/base.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 23195f720..6ce082996 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -351,22 +351,17 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) // Connect new CPU to old CPU's memory only if new CPU isn't // connected to anything. Also connect old CPU's memory to new // CPU. - Port *peer; - if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("icache_port")->getPeer(); + if (!ic->isConnected()) { + Port *peer = oldCPU->getPort("icache_port")->getPeer(); ic->setPeer(peer); - } else { - peer = ic->getPeer(); + peer->setPeer(ic); } - peer->setPeer(ic); - if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) { - peer = oldCPU->getPort("dcache_port")->getPeer(); + if (!dc->isConnected()) { + Port *peer = oldCPU->getPort("dcache_port")->getPeer(); dc->setPeer(peer); - } else { - peer = dc->getPeer(); + peer->setPeer(dc); } - peer->setPeer(dc); } -- cgit v1.2.3 From 163465ac08674125fed1d4e843cab6c1c2bf2033 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 17 Jun 2008 21:11:20 -0700 Subject: ThreadState: Ensure that kernelStats is properly initialized --- src/cpu/simple_thread.cc | 5 +---- src/cpu/thread_state.cc | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 93772fbe1..5a5444de4 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -86,11 +86,8 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, profileNode = &dummyNode; profilePC = 3; - if (use_kernel_stats) { + if (use_kernel_stats) kernelStats = new TheISA::Kernel::Statistics(system); - } else { - kernelStats = NULL; - } } #else SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index be8f822f2..bcfc9c924 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -46,7 +46,7 @@ ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid) : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), - physPort(NULL), virtPort(NULL), + kernelStats(NULL), physPort(NULL), virtPort(NULL), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #else ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, -- cgit v1.2.3 From 67a33eed40f0a551fdf9bf1059928cda1c2d7fdb Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 18 Jun 2008 10:15:21 -0700 Subject: AtomicSimpleCPU: Separate data stalls from instruction stalls. Separate simulation of icache stalls and dat stalls. --- src/cpu/simple/AtomicSimpleCPU.py | 3 ++- src/cpu/simple/atomic.cc | 39 +++++++++++++++++++++++++-------------- src/cpu/simple/atomic.hh | 6 ++++-- 3 files changed, 31 insertions(+), 17 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index 28c2aa9c9..a0b358439 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -33,7 +33,8 @@ from BaseCPU import BaseCPU class AtomicSimpleCPU(BaseCPU): type = 'AtomicSimpleCPU' width = Param.Int(1, "CPU width") - simulate_stalls = Param.Bool(False, "Simulate cache stall cycles") + simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles") + simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") if build_env['FULL_SYSTEM']: diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index acd280568..b25d3330f 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -153,8 +153,9 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port) } AtomicSimpleCPU::AtomicSimpleCPU(Params *p) - : BaseSimpleCPU(p), tickEvent(this), - width(p->width), simulate_stalls(p->simulate_stalls), + : BaseSimpleCPU(p), tickEvent(this), width(p->width), + simulate_data_stalls(p->simulate_data_stalls), + simulate_inst_stalls(p->simulate_inst_stalls), icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), physmemPort(name() + "-iport", this), hasPhysMemPort(false) { @@ -711,7 +712,7 @@ AtomicSimpleCPU::tick() { DPRINTF(SimpleCPU, "Tick\n"); - Tick latency = ticks(1); // instruction takes one cycle by default + Tick latency = 0; for (int i = 0; i < width; ++i) { numCycles++; @@ -769,16 +770,21 @@ AtomicSimpleCPU::tick() curStaticInst->isFirstMicroop())) instCnt++; - if (simulate_stalls) { - Tick icache_stall = - icache_access ? icache_latency - ticks(1) : 0; - Tick dcache_stall = - dcache_access ? dcache_latency - ticks(1) : 0; - Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1); - if (ticks(stall_cycles) < (icache_stall + dcache_stall)) - latency += ticks(stall_cycles+1); - else - latency += ticks(stall_cycles); + Tick stall_ticks = 0; + if (simulate_inst_stalls && icache_access) + stall_ticks += icache_latency; + + if (simulate_data_stalls && dcache_access) + stall_ticks += dcache_latency; + + if (stall_ticks) { + Tick stall_cycles = stall_ticks / ticks(1); + Tick aligned_stall_ticks = ticks(stall_cycles); + + if (aligned_stall_ticks < stall_ticks) + aligned_stall_ticks += 1; + + latency += aligned_stall_ticks; } } @@ -786,6 +792,10 @@ AtomicSimpleCPU::tick() advancePC(fault); } + // instruction takes at least one cycle + if (latency < ticks(1)) + latency = ticks(1); + if (_status != Idle) tickEvent.schedule(curTick + latency); } @@ -819,7 +829,8 @@ AtomicSimpleCPUParams::create() params->functionTrace = function_trace; params->functionTraceStart = function_trace_start; params->width = width; - params->simulate_stalls = simulate_stalls; + params->simulate_data_stalls = simulate_data_stalls; + params->simulate_inst_stalls = simulate_inst_stalls; params->system = system; params->cpu_id = cpu_id; params->tracer = tracer; diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 19bc0e13b..ccea15073 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -39,7 +39,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU struct Params : public BaseSimpleCPU::Params { int width; - bool simulate_stalls; + bool simulate_data_stalls; + bool simulate_inst_stalls; }; AtomicSimpleCPU(Params *params); @@ -74,7 +75,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU TickEvent tickEvent; const int width; - const bool simulate_stalls; + const bool simulate_data_stalls; + const bool simulate_inst_stalls; // main simulation loop (one cycle) void tick(); -- cgit v1.2.3 From 6b45238316052f458ba9ebc9d24a91cfa9e41cf1 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Sat, 21 Jun 2008 01:04:43 -0400 Subject: Generate more useful error messages for unconnected ports. Force all non-default ports to provide a name and an owner in the constructor. --- src/cpu/o3/fetch.hh | 4 ++-- src/cpu/o3/fetch_impl.hh | 2 +- src/cpu/o3/lsq.hh | 4 ++-- src/cpu/o3/lsq_impl.hh | 2 +- src/cpu/o3/thread_context_impl.hh | 1 - src/cpu/ozone/cpu_impl.hh | 1 - src/cpu/simple_thread.cc | 1 - src/cpu/thread_state.cc | 4 ++-- 8 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index d954bd1e7..3ada0328f 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -80,8 +80,8 @@ class DefaultFetch public: /** Default constructor. */ - IcachePort(DefaultFetch *_fetch) - : Port(_fetch->name() + "-iport"), fetch(_fetch) + IcachePort(DefaultFetch *_fetch, O3CPU *_cpu) + : Port(_fetch->name() + "-iport", _cpu), fetch(_fetch) { } bool snoopRangeSent; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 7d344fa33..ecfbacd98 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -167,7 +167,7 @@ DefaultFetch::DefaultFetch(O3CPU *_cpu, Params *params) instSize = sizeof(TheISA::MachInst); // Name is finally available, so create the port. - icachePort = new IcachePort(this); + icachePort = new IcachePort(this, cpu); icachePort->snoopRangeSent = false; diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 06de608e0..82d73c6ee 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -296,8 +296,8 @@ class LSQ { public: /** Default constructor. */ - DcachePort(LSQ *_lsq) - : Port(_lsq->name() + "-dport"), lsq(_lsq) + DcachePort(LSQ *_lsq, O3CPU *_cpu) + : Port(_lsq->name() + "-dport", _cpu), lsq(_lsq) { } bool snoopRangeSent; diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 8ed6f7f54..41ab66dd0 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -112,7 +112,7 @@ LSQ::DcachePort::recvRetry() template LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) - : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), + : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this, cpu_ptr), LQEntries(params->LQEntries), SQEntries(params->SQEntries), numThreads(params->numberOfThreads), diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 865d58635..514d3de64 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -103,7 +103,6 @@ void O3ThreadContext::delVirtPort(VirtualPort *vp) { if (vp != thread->getVirtPort()) { - vp->removeConn(); delete vp; } } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 0c7105382..4cb55fa23 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -747,7 +747,6 @@ template void OzoneCPU::OzoneTC::delVirtPort(VirtualPort *vp) { - vp->removeConn(); delete vp; } #endif diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 5a5444de4..47b69d05f 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -302,7 +302,6 @@ void SimpleThread::delVirtPort(VirtualPort *vp) { if (vp != virtPort) { - vp->removeConn(); delete vp; } } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index bcfc9c924..56839ca7f 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -126,7 +126,7 @@ ThreadState::connectPhysPort() // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. if (physPort) - physPort->removeConn(); + physPort->disconnectFromPeer(); else physPort = new FunctionalPort(csprintf("%s-%d-funcport", baseCpu->name(), tid)); @@ -140,7 +140,7 @@ ThreadState::connectVirtPort() // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. if (virtPort) - virtPort->removeConn(); + virtPort->disconnectFromPeer(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", baseCpu->name(), tid)); -- cgit v1.2.3 From caaac16803db6eaf3ee20b5d062ec2211fe6584d Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Sat, 28 Jun 2008 13:19:38 -0400 Subject: Backed out changeset 94a7bb476fca: caused memory leak. --- src/cpu/o3/fetch.hh | 4 ++-- src/cpu/o3/fetch_impl.hh | 2 +- src/cpu/o3/lsq.hh | 4 ++-- src/cpu/o3/lsq_impl.hh | 2 +- src/cpu/o3/thread_context_impl.hh | 1 + src/cpu/ozone/cpu_impl.hh | 1 + src/cpu/simple_thread.cc | 1 + src/cpu/thread_state.cc | 4 ++-- 8 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 3ada0328f..d954bd1e7 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -80,8 +80,8 @@ class DefaultFetch public: /** Default constructor. */ - IcachePort(DefaultFetch *_fetch, O3CPU *_cpu) - : Port(_fetch->name() + "-iport", _cpu), fetch(_fetch) + IcachePort(DefaultFetch *_fetch) + : Port(_fetch->name() + "-iport"), fetch(_fetch) { } bool snoopRangeSent; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index ecfbacd98..7d344fa33 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -167,7 +167,7 @@ DefaultFetch::DefaultFetch(O3CPU *_cpu, Params *params) instSize = sizeof(TheISA::MachInst); // Name is finally available, so create the port. - icachePort = new IcachePort(this, cpu); + icachePort = new IcachePort(this); icachePort->snoopRangeSent = false; diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 82d73c6ee..06de608e0 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -296,8 +296,8 @@ class LSQ { public: /** Default constructor. */ - DcachePort(LSQ *_lsq, O3CPU *_cpu) - : Port(_lsq->name() + "-dport", _cpu), lsq(_lsq) + DcachePort(LSQ *_lsq) + : Port(_lsq->name() + "-dport"), lsq(_lsq) { } bool snoopRangeSent; diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 41ab66dd0..8ed6f7f54 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -112,7 +112,7 @@ LSQ::DcachePort::recvRetry() template LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) - : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this, cpu_ptr), + : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), LQEntries(params->LQEntries), SQEntries(params->SQEntries), numThreads(params->numberOfThreads), diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 514d3de64..865d58635 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -103,6 +103,7 @@ void O3ThreadContext::delVirtPort(VirtualPort *vp) { if (vp != thread->getVirtPort()) { + vp->removeConn(); delete vp; } } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 4cb55fa23..0c7105382 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -747,6 +747,7 @@ template void OzoneCPU::OzoneTC::delVirtPort(VirtualPort *vp) { + vp->removeConn(); delete vp; } #endif diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 47b69d05f..5a5444de4 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -302,6 +302,7 @@ void SimpleThread::delVirtPort(VirtualPort *vp) { if (vp != virtPort) { + vp->removeConn(); delete vp; } } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 56839ca7f..bcfc9c924 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -126,7 +126,7 @@ ThreadState::connectPhysPort() // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. if (physPort) - physPort->disconnectFromPeer(); + physPort->removeConn(); else physPort = new FunctionalPort(csprintf("%s-%d-funcport", baseCpu->name(), tid)); @@ -140,7 +140,7 @@ ThreadState::connectVirtPort() // already existed. Fix this memory leak once the bus port IDs // for functional ports is resolved. if (virtPort) - virtPort->disconnectFromPeer(); + virtPort->removeConn(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", baseCpu->name(), tid)); -- cgit v1.2.3 From 9bd0bfe559d8c9633c5686ccf100ab921eb6eda2 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 1 Jul 2008 10:24:09 -0400 Subject: After a checkpoint (and thus a stats reset), the not_idle_fraction/notIdleFraction statistic is really wrong. The notIdleFraction statistic isn't updated when the statistics reset, probably because the cpu Status information was pulled into the atomic and timing cpus. This changeset pulls Status back into the BaseSimpleCPU object. Anyone care to comment on the odd naming of the Status instance? It shouldn't just be status because that is confusing with Port::Status, but _status seems a bit strage too. --- src/cpu/simple/atomic.cc | 5 +---- src/cpu/simple/atomic.hh | 13 ------------- src/cpu/simple/base.cc | 4 +++- src/cpu/simple/base.hh | 14 ++++++++++++++ src/cpu/simple/timing.cc | 4 ++-- src/cpu/simple/timing.hh | 18 ------------------ 6 files changed, 20 insertions(+), 38 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index b25d3330f..6b07502ef 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -176,8 +176,6 @@ AtomicSimpleCPU::serialize(ostream &os) { SimObject::State so_state = SimObject::getState(); SERIALIZE_ENUM(so_state); - Status _status = status(); - SERIALIZE_ENUM(_status); BaseSimpleCPU::serialize(os); nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); @@ -188,7 +186,6 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { SimObject::State so_state; UNSERIALIZE_ENUM(so_state); - UNSERIALIZE_ENUM(_status); BaseSimpleCPU::unserialize(cp, section); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); } @@ -213,7 +210,7 @@ AtomicSimpleCPU::resume() void AtomicSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; tickEvent.squash(); diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index ccea15073..008397533 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -48,19 +48,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU virtual void init(); - public: - // - enum Status { - Running, - Idle, - SwitchedOut - }; - - protected: - Status _status; - - Status status() const { return _status; } - private: struct TickEvent : public Event diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4a91a9e12..0c1162032 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -174,12 +174,13 @@ void BaseSimpleCPU::resetStats() { // startNumInst = numInst; - // notIdleFraction = (_status != Idle); + notIdleFraction = (_status != Idle); } void BaseSimpleCPU::serialize(ostream &os) { + SERIALIZE_ENUM(_status); BaseCPU::serialize(os); // SERIALIZE_SCALAR(inst); nameOut(os, csprintf("%s.xc.0", name())); @@ -189,6 +190,7 @@ BaseSimpleCPU::serialize(ostream &os) void BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { + UNSERIALIZE_ENUM(_status); BaseCPU::unserialize(cp, section); // UNSERIALIZE_SCALAR(inst); thread->unserialize(cp, csprintf("%s.xc.0", section)); diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 918965fdb..62bb31de8 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -129,6 +129,20 @@ class BaseSimpleCPU : public BaseCPU protected: int cpuId; + enum Status { + Idle, + Running, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + Status _status; + public: #if FULL_SYSTEM diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index d0c7dd787..2cf7d584d 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -145,7 +145,7 @@ TimingSimpleCPU::drain(Event *drain_event) { // TimingSimpleCPU is ready to drain if it's not waiting for // an access to complete. - if (status() == Idle || status() == Running || status() == SwitchedOut) { + if (_status == Idle || _status == Running || _status == SwitchedOut) { changeState(SimObject::Drained); return 0; } else { @@ -179,7 +179,7 @@ TimingSimpleCPU::resume() void TimingSimpleCPU::switchOut() { - assert(status() == Running || status() == Idle); + assert(_status == Running || _status == Idle); _status = SwitchedOut; numCycles += tickToCycles(curTick - previousTick); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index f8b77604a..a748d47b4 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -46,24 +46,6 @@ class TimingSimpleCPU : public BaseSimpleCPU virtual void init(); public: - // - enum Status { - Idle, - Running, - IcacheRetry, - IcacheWaitResponse, - IcacheWaitSwitch, - DcacheRetry, - DcacheWaitResponse, - DcacheWaitSwitch, - SwitchedOut - }; - - protected: - Status _status; - - Status status() const { return _status; } - Event *drainEvent; private: -- cgit v1.2.3 From 50e3e50e1ac592b357a47eecdc3c99a528172870 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 1 Jul 2008 10:24:16 -0400 Subject: Make the cached virtPort have a thread context so it can do everything that a newly created one can. --- src/cpu/o3/cpu.cc | 2 +- src/cpu/o3/thread_context.hh | 2 +- src/cpu/simple/atomic.cc | 2 +- src/cpu/simple/timing.cc | 2 +- src/cpu/thread_context.hh | 4 ++-- src/cpu/thread_state.cc | 8 ++++---- src/cpu/thread_state.hh | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index c75a08213..fac214174 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -788,7 +788,7 @@ FullO3CPU::updateMemPorts() // Update all ThreadContext's memory ports (Functional/Virtual // Ports) for (int i = 0; i < thread.size(); ++i) - thread[i]->connectMemPorts(); + thread[i]->connectMemPorts(thread[i]->getTC()); } #endif diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index e7bdc6de5..44e26729c 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -98,7 +98,7 @@ class O3ThreadContext : public ThreadContext void delVirtPort(VirtualPort *vp); - virtual void connectMemPorts() { thread->connectMemPorts(); } + virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); } #else virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 6b07502ef..0e04a36b2 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -148,7 +148,7 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 2cf7d584d..b86d4b2d7 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -766,7 +766,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port) #if FULL_SYSTEM // Update the ThreadContext's memory ports (Functional/Virtual // Ports) - cpu->tcBase()->connectMemPorts(); + cpu->tcBase()->connectMemPorts(cpu->tcBase()); #endif } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index cf51c1637..b25a67d59 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -134,7 +134,7 @@ class ThreadContext virtual void delVirtPort(VirtualPort *vp) = 0; - virtual void connectMemPorts() = 0; + virtual void connectMemPorts(ThreadContext *tc) = 0; #else virtual TranslatingPort *getMemPort() = 0; @@ -325,7 +325,7 @@ class ProxyThreadContext : public ThreadContext void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); } - void connectMemPorts() { actualTC->connectMemPorts(); } + void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index bcfc9c924..18845baf7 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -113,10 +113,10 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) #if FULL_SYSTEM void -ThreadState::connectMemPorts() +ThreadState::connectMemPorts(ThreadContext *tc) { connectPhysPort(); - connectVirtPort(); + connectVirtPort(tc); } void @@ -134,7 +134,7 @@ ThreadState::connectPhysPort() } void -ThreadState::connectVirtPort() +ThreadState::connectVirtPort(ThreadContext *tc) { // @todo: For now this disregards any older port that may have // already existed. Fix this memory leak once the bus port IDs @@ -143,7 +143,7 @@ ThreadState::connectVirtPort() virtPort->removeConn(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", - baseCpu->name(), tid)); + baseCpu->name(), tid), tc); connectToMemFunc(virtPort); } diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 4f878db1f..b6a62eebc 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -91,11 +91,11 @@ struct ThreadState { Tick readLastSuspend() { return lastSuspend; } #if FULL_SYSTEM - void connectMemPorts(); + void connectMemPorts(ThreadContext *tc); void connectPhysPort(); - void connectVirtPort(); + void connectVirtPort(ThreadContext *tc); void dumpFuncProfile(); @@ -201,7 +201,7 @@ struct ThreadState { FunctionalPort *physPort; /** A functional port, outgoing only, for functional accesse to virtual - * addresses. That doen't require execution context information */ + * addresses. */ VirtualPort *virtPort; #else TranslatingPort *port; -- cgit v1.2.3 From a4a7a09e9622d6ad1ca91a4df253b9768c73de90 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 1 Jul 2008 10:25:07 -0400 Subject: Remove delVirtPort() and make getVirtPort() only return cached version. --- src/cpu/checker/thread_context.hh | 4 +--- src/cpu/o3/thread_context.hh | 4 +--- src/cpu/o3/thread_context_impl.hh | 23 ++--------------------- src/cpu/ozone/cpu.hh | 6 ++---- src/cpu/ozone/cpu_impl.hh | 10 ---------- src/cpu/simple_thread.cc | 23 ----------------------- src/cpu/simple_thread.hh | 11 +++++------ src/cpu/thread_context.hh | 8 ++------ src/cpu/thread_state.hh | 4 +--- 9 files changed, 14 insertions(+), 79 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 15454c3fe..4ede74c64 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -98,10 +98,8 @@ class CheckerThreadContext : public ThreadContext FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } - - void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); } #else TranslatingPort *getMemPort() { return actualTC->getMemPort(); } diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 44e26729c..66dc47f0b 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -94,9 +94,7 @@ class O3ThreadContext : public ThreadContext virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL); - - void delVirtPort(VirtualPort *vp); + virtual VirtualPort *getVirtPort(); virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); } #else diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 865d58635..a521c3636 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -36,16 +36,9 @@ #if FULL_SYSTEM template VirtualPort * -O3ThreadContext::getVirtPort(ThreadContext *src_tc) +O3ThreadContext::getVirtPort() { - if (!src_tc) - return thread->getVirtPort(); - - VirtualPort *vp; - - vp = new VirtualPort("tc-vport", src_tc); - thread->connectToMemFunc(vp); - return vp; + return thread->getVirtPort(); } template @@ -97,18 +90,6 @@ O3ThreadContext::takeOverFrom(ThreadContext *old_context) thread->trapPending = false; } -#if FULL_SYSTEM -template -void -O3ThreadContext::delVirtPort(VirtualPort *vp) -{ - if (vp != thread->getVirtPort()) { - vp->removeConn(); - delete vp; - } -} -#endif - template void O3ThreadContext::activate(int delay) diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index b0ea2cba9..c3ea33673 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -134,10 +134,8 @@ class OzoneCPU : public BaseCPU FunctionalPort *getPhysPort() { return thread->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) - { return thread->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp); + VirtualPort *getVirtPort() + { return thread->getVirtPort(); } #else TranslatingPort *getMemPort() { return thread->getMemPort(); } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 0c7105382..ec531d571 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -742,16 +742,6 @@ OzoneCPU::OzoneTC::setCpuId(int id) thread->setCpuId(id); } -#if FULL_SYSTEM -template -void -OzoneCPU::OzoneTC::delVirtPort(VirtualPort *vp) -{ - vp->removeConn(); - delete vp; -} -#endif - template void OzoneCPU::OzoneTC::setStatus(Status new_status) diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 5a5444de4..8d5c4eafb 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -286,26 +286,3 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc) TheISA::copyRegs(src_tc, tc); } -#if FULL_SYSTEM -VirtualPort* -SimpleThread::getVirtPort(ThreadContext *src_tc) -{ - if (!src_tc) - return virtPort; - - VirtualPort *vp = new VirtualPort("tc-vport", src_tc); - connectToMemFunc(vp); - return vp; -} - -void -SimpleThread::delVirtPort(VirtualPort *vp) -{ - if (vp != virtPort) { - vp->removeConn(); - delete vp; - } -} - -#endif - diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index fa80a283a..37c3221f5 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -208,12 +208,11 @@ class SimpleThread : public ThreadState FunctionalPort *getPhysPort() { return physPort; } - /** Return a virtual port. If no thread context is specified then a static - * port is returned. Otherwise a port is created and returned. It must be - * deleted by deleteVirtPort(). */ - VirtualPort *getVirtPort(ThreadContext *tc); - - void delVirtPort(VirtualPort *vp); + /** Return a virtual port. This port cannot be cached locally in an object. + * After a CPU switch it may point to the wrong memory object which could + * mean stale data. + */ + VirtualPort *getVirtPort() { return virtPort; } #endif Status status() const { return _status; } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index b25a67d59..b1687a494 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -130,9 +130,7 @@ class ThreadContext virtual FunctionalPort *getPhysPort() = 0; - virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0; - - virtual void delVirtPort(VirtualPort *vp) = 0; + virtual VirtualPort *getVirtPort() = 0; virtual void connectMemPorts(ThreadContext *tc) = 0; #else @@ -321,9 +319,7 @@ class ProxyThreadContext : public ThreadContext FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); } - - void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); } + VirtualPort *getVirtPort() { return actualTC->getVirtPort(); } void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); } #else diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index b6a62eebc..1b667f72a 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -111,9 +111,7 @@ struct ThreadState { void setPhysPort(FunctionalPort *port) { physPort = port; } - VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; } - - void setVirtPort(VirtualPort *port) { virtPort = port; } + VirtualPort *getVirtPort() { return virtPort; } #else Process *getProcessPtr() { return process; } -- cgit v1.2.3 From 8e7ddce28493c93564aeb20f1856fbe6bff0ece4 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Tue, 15 Jul 2008 14:38:51 -0400 Subject: Use ReadResp instead of LoadLockedResp for LoadLockedReq responses. --- src/cpu/simple/timing.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index b86d4b2d7..4451dfe81 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -730,7 +730,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) traceData = NULL; } - if (pkt->isRead() && pkt->isLocked()) { + // the locked flag may be cleared on the response packet, so check + // pkt->req and not pkt to see if it was a load-locked + if (pkt->isRead() && pkt->req->isLocked()) { TheISA::handleLockedRead(thread, pkt->req); } -- cgit v1.2.3 From 50ef39af82413ef463609f24173b22af13fad268 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sun, 3 Aug 2008 18:19:55 -0700 Subject: sockets: Add a function to disable all listening sockets. When invoking several copies of m5 on the same machine at the same time, there can be a race for TCP ports for the terminal connections or remote gdb. Expose a function to disable those ports, and have the regression scripts disable them. There are some SimObjects that have no other function than to be used with ports (NativeTrace and EtherTap), so they will panic if the ports are disabled. --- src/cpu/nativetrace.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 7152602fe..c23a9e4ad 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -50,8 +50,12 @@ using namespace TheISA; namespace Trace { -NativeTrace::NativeTrace(const Params *p) : InstTracer(p) +NativeTrace::NativeTrace(const Params *p) + : InstTracer(p) { + if (ListenSocket::allDisabled()) + fatal("All listeners are disabled!"); + int port = 8000; while(!native_listener.listen(port, true)) { -- cgit v1.2.3 From ee62a0fec8e63f45f816c61ab9fb28aba7414185 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 11 Aug 2008 12:22:16 -0700 Subject: params: Convert the CPU objects to use the auto generated param structs. A whole bunch of stuff has been converted to use the new params stuff, but the CPU wasn't one of them. While we're at it, make some things a bit more stylish. Most of the work was done by Gabe, I just cleaned stuff up a bit more at the end. --- src/cpu/BaseCPU.py | 11 ++- src/cpu/CheckerCPU.py | 44 ++++++++++ src/cpu/SConscript | 1 + src/cpu/base.cc | 49 +++++------ src/cpu/base.hh | 40 ++------- src/cpu/checker/cpu.hh | 17 +--- src/cpu/o3/O3CPU.py | 6 -- src/cpu/o3/alpha/cpu.hh | 4 +- src/cpu/o3/alpha/cpu_builder.cc | 132 ++-------------------------- src/cpu/o3/alpha/cpu_impl.hh | 6 +- src/cpu/o3/alpha/impl.hh | 4 - src/cpu/o3/alpha/params.hh | 61 ------------- src/cpu/o3/bpred_unit.hh | 5 +- src/cpu/o3/bpred_unit_impl.hh | 4 +- src/cpu/o3/commit.hh | 5 +- src/cpu/o3/commit_impl.hh | 6 +- src/cpu/o3/cpu.cc | 14 +-- src/cpu/o3/cpu.hh | 11 +-- src/cpu/o3/decode.hh | 5 +- src/cpu/o3/decode_impl.hh | 6 +- src/cpu/o3/fetch.hh | 5 +- src/cpu/o3/fetch_impl.hh | 6 +- src/cpu/o3/iew.hh | 4 +- src/cpu/o3/iew_impl.hh | 5 +- src/cpu/o3/inst_queue.hh | 5 +- src/cpu/o3/inst_queue_impl.hh | 6 +- src/cpu/o3/isa_specific.hh | 3 - src/cpu/o3/lsq.hh | 5 +- src/cpu/o3/lsq_impl.hh | 6 +- src/cpu/o3/lsq_unit.hh | 8 +- src/cpu/o3/lsq_unit_impl.hh | 5 +- src/cpu/o3/mem_dep_unit.hh | 7 +- src/cpu/o3/mem_dep_unit_impl.hh | 6 +- src/cpu/o3/mips/cpu.hh | 4 +- src/cpu/o3/mips/cpu_builder.cc | 122 +++----------------------- src/cpu/o3/mips/cpu_impl.hh | 5 +- src/cpu/o3/mips/impl.hh | 4 - src/cpu/o3/mips/params.hh | 64 -------------- src/cpu/o3/params.hh | 180 -------------------------------------- src/cpu/o3/regfile.hh | 1 + src/cpu/o3/rename.hh | 5 +- src/cpu/o3/rename_impl.hh | 5 +- src/cpu/o3/sparc/cpu.hh | 4 +- src/cpu/o3/sparc/cpu_builder.cc | 132 ++-------------------------- src/cpu/o3/sparc/cpu_impl.hh | 6 +- src/cpu/o3/sparc/impl.hh | 4 - src/cpu/o3/sparc/params.hh | 61 ------------- src/cpu/o3/thread_state.hh | 4 +- src/cpu/simple/AtomicSimpleCPU.py | 6 +- src/cpu/simple/BaseSimpleCPU.py | 34 +++++++ src/cpu/simple/SConscript | 1 + src/cpu/simple/TimingSimpleCPU.py | 6 +- src/cpu/simple/atomic.cc | 37 +------- src/cpu/simple/atomic.hh | 9 +- src/cpu/simple/base.cc | 6 +- src/cpu/simple/base.hh | 12 +-- src/cpu/simple/timing.cc | 34 +------ src/cpu/simple/timing.hh | 7 +- src/cpu/simple_thread.cc | 7 +- 59 files changed, 273 insertions(+), 989 deletions(-) create mode 100644 src/cpu/CheckerCPU.py delete mode 100644 src/cpu/o3/alpha/params.hh delete mode 100644 src/cpu/o3/mips/params.hh delete mode 100755 src/cpu/o3/params.hh delete mode 100644 src/cpu/o3/sparc/params.hh create mode 100644 src/cpu/simple/BaseSimpleCPU.py (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index c2a865113..1e3f0dbbc 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -26,7 +26,7 @@ # # Authors: Nathan Binkert -from m5.SimObject import SimObject +from MemObject import MemObject from m5.params import * from m5.proxy import * from m5 import build_env @@ -48,14 +48,21 @@ elif build_env['TARGET_ISA'] == 'mips': elif build_env['TARGET_ISA'] == 'arm': from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB -class BaseCPU(SimObject): +class BaseCPU(MemObject): type = 'BaseCPU' abstract = True system = Param.System(Parent.any, "system object") cpu_id = Param.Int("CPU identifier") + numThreads = Param.Unsigned(1, "number of HW thread contexts") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") + + checker = Param.BaseCPU("checker CPU") if build_env['FULL_SYSTEM']: + profile = Param.Latency('0ns', "trace the kernel stack") do_quiesce = Param.Bool(True, "enable quiesce instructions") do_checkpoint_insts = Param.Bool(True, "enable checkpoint pseudo instructions") diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py new file mode 100644 index 000000000..06df9c1b1 --- /dev/null +++ b/src/cpu/CheckerCPU.py @@ -0,0 +1,44 @@ +# Copyright (c) 2007 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: Nathan Binkert + +from m5.params import * +from m5 import build_env +from BaseCPU import BaseCPU + +class CheckerCPU(BaseCPU): + type = 'CheckerCPU' + abstract = True + exitOnError = Param.Bool(False, "Exit on an error") + updateOnError = Param.Bool(False, + "Update the checker with the main CPU's state on an error") + warnOnlyOnLoadError = Param.Bool(False, + "If a load result is incorrect, only print a warning and do not exit") + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") + if build_env['FULL_SYSTEM']: + profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/SConscript b/src/cpu/SConscript index c6a959d9d..750e1ee4c 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -71,6 +71,7 @@ temp_cpu_list = env['CPU_MODELS'][:] if env['USE_CHECKER']: temp_cpu_list.append('CheckerCPU') + SimObject('CheckerCPU.py') # Generate header. def gen_cpu_exec_signatures(target, source, env): diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 6ce082996..f79b79350 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -37,17 +37,17 @@ #include "base/loader/symtab.hh" #include "base/misc.hh" #include "base/output.hh" +#include "base/trace.hh" #include "cpu/base.hh" #include "cpu/cpuevent.hh" #include "cpu/thread_context.hh" #include "cpu/profile.hh" +#include "params/BaseCPU.hh" #include "sim/sim_exit.hh" #include "sim/process.hh" #include "sim/sim_events.hh" #include "sim/system.hh" -#include "base/trace.hh" - // Hack #include "sim/stat_control.hh" @@ -95,13 +95,13 @@ CPUProgressEvent::description() const #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0), - params(p), number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), instCnt(0), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #else BaseCPU::BaseCPU(Params *p) - : MemObject(makeParams(p->name)), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads), system(p->system), + : MemObject(p), clock(p->clock), + number_of_threads(p->numThreads), system(p->system), phase(p->phase) #endif { @@ -166,34 +166,25 @@ BaseCPU::BaseCPU(Params *p) } functionTracingEnabled = false; - if (p->functionTrace) { + if (p->function_trace) { functionTraceStream = simout.find(csprintf("ftrace.%s", name())); currentFunctionStart = currentFunctionEnd = 0; - functionEntryTick = p->functionTraceStart; + functionEntryTick = p->function_trace_start; - if (p->functionTraceStart == 0) { + if (p->function_trace_start == 0) { functionTracingEnabled = true; } else { - new EventWrapper(this, - p->functionTraceStart, - true); + new EventWrapper( + this, p->function_trace_start, true); } } #if FULL_SYSTEM profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - tracer = params->tracer; -} - -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; + if (params()->profile) + profileEvent = new ProfileEvent(this, params()->profile); #endif - checker = NULL; - tracer = NULL; + tracer = params()->tracer; } void @@ -209,7 +200,7 @@ BaseCPU::~BaseCPU() void BaseCPU::init() { - if (!params->deferRegistration) + if (!params()->defer_registration) registerThreadContexts(); } @@ -217,13 +208,13 @@ void BaseCPU::startup() { #if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) + if (!params()->defer_registration && profileEvent) profileEvent->schedule(curTick); #endif - if (params->progress_interval) { + if (params()->progress_interval) { new CPUProgressEvent(&mainEventQueue, - ticks(params->progress_interval), + ticks(params()->progress_interval), this); } } @@ -281,7 +272,7 @@ BaseCPU::registerThreadContexts() ThreadContext *tc = threadContexts[i]; #if FULL_SYSTEM - int id = params->cpu_id; + int id = params()->cpu_id; if (id != -1) id += i; diff --git a/src/cpu/base.hh b/src/cpu/base.hh index bdc7d7c8b..6e9e1dc39 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -45,6 +45,7 @@ #include "arch/interrupts.hh" #endif +class BaseCPUParams; class BranchPred; class CheckerCPU; class ThreadContext; @@ -162,40 +163,9 @@ class BaseCPU : public MemObject ThreadContext *getContext(int tn) { return threadContexts[tn]; } public: - struct Params - { - std::string name; - int numberOfThreads; - bool deferRegistration; - Counter max_insts_any_thread; - Counter max_insts_all_threads; - Counter max_loads_any_thread; - Counter max_loads_all_threads; - Tick clock; - bool functionTrace; - Tick functionTraceStart; - System *system; - int cpu_id; - Trace::InstTracer * tracer; - - Tick phase; -#if FULL_SYSTEM - Tick profile; - - bool do_statistics_insts; - bool do_checkpoint_insts; - bool do_quiesce; -#endif - Tick progress_interval; - BaseCPU *checker; - - TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core - - Params(); - }; - - const Params *params; - + typedef BaseCPUParams Params; + const Params *params() const + { return reinterpret_cast(_params); } BaseCPU(Params *params); virtual ~BaseCPU(); @@ -221,6 +191,8 @@ class BaseCPU : public MemObject */ int number_of_threads; + TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core + /** * Vector of per-thread instruction-based event queues. Used for * scheduling events based on number of instructions committed by diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 35dc59ff4..17648d508 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -65,6 +65,7 @@ class Process; #endif // FULL_SYSTEM template class BaseDynInst; +class CheckerCPUParams; class ThreadContext; class MemInterface; class Checkpoint; @@ -96,20 +97,10 @@ class CheckerCPU : public BaseCPU public: virtual void init(); - struct Params : public BaseCPU::Params - { -#if FULL_SYSTEM - TheISA::ITB *itb; - TheISA::DTB *dtb; -#else - Process *process; -#endif - bool exitOnError; - bool updateOnError; - bool warnOnlyOnLoadError; - }; - public: + typedef CheckerCPUParams Params; + const Params *params() const + { return reinterpret_cast(_params); } CheckerCPU(Params *p); virtual ~CheckerCPU(); diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index f0284b2cf..56e537ad2 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -38,10 +38,7 @@ if build_env['USE_CHECKER']: class DerivO3CPU(BaseCPU): type = 'DerivO3CPU' activity = Param.Unsigned(0, "Initial count") - numThreads = Param.Unsigned(1, "number of HW thread contexts") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") if build_env['USE_CHECKER']: if not build_env['FULL_SYSTEM']: checker = Param.BaseCPU(O3Checker(workload=Parent.workload, @@ -134,9 +131,6 @@ class DerivO3CPU(BaseCPU): instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - smtNumFetchingThreads = Param.Unsigned(1, "SMT Number of Fetching Threads") smtFetchPolicy = Param.String('SingleThread', "SMT Fetch policy") smtLSQPolicy = Param.String('Partitioned', "SMT LSQ Sharing Policy") diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh index ebc4e7b23..f9f0000d4 100644 --- a/src/cpu/o3/alpha/cpu.hh +++ b/src/cpu/o3/alpha/cpu.hh @@ -37,6 +37,7 @@ #include "cpu/o3/cpu.hh" #include "sim/byteswap.hh" +class DerivO3CPUParams; class EndQuiesceEvent; namespace Kernel { class Statistics; @@ -58,10 +59,9 @@ class AlphaO3CPU : public FullO3CPU public: typedef O3ThreadState ImplState; typedef O3ThreadState Thread; - typedef typename Impl::Params Params; /** Constructs an AlphaO3CPU with the given parameters. */ - AlphaO3CPU(Params *params); + AlphaO3CPU(DerivO3CPUParams *params); /** Registers statistics. */ void regStats(); diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc index f569c048b..0ff0d5d52 100644 --- a/src/cpu/o3/alpha/cpu_builder.cc +++ b/src/cpu/o3/alpha/cpu_builder.cc @@ -34,14 +34,13 @@ #include "cpu/base.hh" #include "cpu/o3/alpha/cpu.hh" #include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/alpha/params.hh" #include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" class DerivO3CPU : public AlphaO3CPU { public: - DerivO3CPU(AlphaSimpleParams *p) + DerivO3CPU(DerivO3CPUParams *p) : AlphaO3CPU(p) { } }; @@ -49,8 +48,6 @@ class DerivO3CPU : public AlphaO3CPU DerivO3CPU * DerivO3CPUParams::create() { - DerivO3CPU *cpu; - #if FULL_SYSTEM // Full-system only supports a single thread for the moment. int actual_num_threads = 1; @@ -65,135 +62,18 @@ DerivO3CPUParams::create() } #endif - AlphaSimpleParams *params = new AlphaSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; + numThreads = actual_num_threads; // Default smtFetchPolicy to "RoundRobin", if necessary. std::string round_robin_policy = "RoundRobin"; std::string single_thread = "SingleThread"; if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; + smtFetchPolicy = round_robin_policy; else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; + smtFetchPolicy = smtFetchPolicy; - cpu = new DerivO3CPU(params); + instShiftAmt = 2; - return cpu; + return new DerivO3CPU(this); } diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh index 7f8f0547b..dc64113e1 100644 --- a/src/cpu/o3/alpha/cpu_impl.hh +++ b/src/cpu/o3/alpha/cpu_impl.hh @@ -40,7 +40,6 @@ #include "sim/stats.hh" #include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/params.hh" #include "cpu/o3/alpha/thread_context.hh" #include "cpu/o3/comm.hh" #include "cpu/o3/thread_state.hh" @@ -54,8 +53,11 @@ #include "sim/system.hh" #endif +#include "params/DerivO3CPU.hh" + template -AlphaO3CPU::AlphaO3CPU(Params *params) : FullO3CPU(this, params) +AlphaO3CPU::AlphaO3CPU(DerivO3CPUParams *params) : + FullO3CPU(this, params) { DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n"); diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh index b928ae654..d2d04292c 100644 --- a/src/cpu/o3/alpha/impl.hh +++ b/src/cpu/o3/alpha/impl.hh @@ -33,7 +33,6 @@ #include "arch/alpha/isa_traits.hh" -#include "cpu/o3/alpha/params.hh" #include "cpu/o3/cpu_policy.hh" @@ -77,9 +76,6 @@ struct AlphaSimpleImpl */ typedef O3CPU CPUType; - /** The Params to be passed to each stage. */ - typedef AlphaSimpleParams Params; - enum { MaxWidth = 8, MaxThreads = 4 diff --git a/src/cpu/o3/alpha/params.hh b/src/cpu/o3/alpha/params.hh deleted file mode 100644 index 164c25312..000000000 --- a/src/cpu/o3/alpha/params.hh +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_PARAMS_HH__ -#define __CPU_O3_ALPHA_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace AlphaISA -{ - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ - -class AlphaSimpleParams : public O3Params -{ - public: - - AlphaISA::ITB *itb; - AlphaISA::DTB *dtb; -}; - -#endif // __CPU_O3_ALPHA_PARAMS_HH__ diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 3c4c8e478..34fe74178 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -43,6 +43,8 @@ #include +class DerivO3CPUParams; + /** * Basically a wrapper class to hold both the branch predictor * and the BTB. @@ -51,7 +53,6 @@ template class BPredUnit { private: - typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; enum PredType { @@ -66,7 +67,7 @@ class BPredUnit /** * @param params The params object, that has the size of the BP and BTB. */ - BPredUnit(Params *params); + BPredUnit(DerivO3CPUParams *params); /** * Registers statistics. diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh index 84c50b4da..ded72a1b5 100644 --- a/src/cpu/o3/bpred_unit_impl.hh +++ b/src/cpu/o3/bpred_unit_impl.hh @@ -34,8 +34,10 @@ #include "base/traceflags.hh" #include "cpu/o3/bpred_unit.hh" +#include "params/DerivO3CPU.hh" + template -BPredUnit::BPredUnit(Params *params) +BPredUnit::BPredUnit(DerivO3CPUParams *params) : BTB(params->BTBEntries, params->BTBTagSize, params->instShiftAmt) diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index 80e42fa8b..ff1e517f2 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -37,6 +37,8 @@ #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" +class DerivO3CPUParams; + template class O3ThreadState; @@ -69,7 +71,6 @@ class DefaultCommit // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; typedef typename CPUPol::RenameMap RenameMap; @@ -136,7 +137,7 @@ class DefaultCommit public: /** Construct a DefaultCommit with the given parameters. */ - DefaultCommit(O3CPU *_cpu, Params *params); + DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultCommit. */ std::string name() const; diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index ee0f2bb59..86b4da8ce 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -46,6 +46,8 @@ #include "cpu/checker/cpu.hh" #endif +#include "params/DerivO3CPU.hh" + template DefaultCommit::TrapEvent::TrapEvent(DefaultCommit *_commit, unsigned _tid) @@ -71,7 +73,7 @@ DefaultCommit::TrapEvent::description() const } template -DefaultCommit::DefaultCommit(O3CPU *_cpu, Params *params) +DefaultCommit::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), squashCounter(0), iewToCommitDelay(params->iewToCommitDelay), @@ -80,7 +82,7 @@ DefaultCommit::DefaultCommit(O3CPU *_cpu, Params *params) fetchToCommitDelay(params->commitToFetchDelay), renameWidth(params->renameWidth), commitWidth(params->commitWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), drainPending(false), switchedOut(false), trapLatency(params->trapLatency) diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index fac214174..f06aee634 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -52,9 +52,11 @@ #include "cpu/checker/cpu.hh" #endif +class BaseCPUParams; + using namespace TheISA; -BaseO3CPU::BaseO3CPU(Params *params) +BaseO3CPU::BaseO3CPU(BaseCPUParams *params) : BaseCPU(params), cpu_id(0) { } @@ -147,7 +149,7 @@ FullO3CPU::DeallocateContextEvent::description() const } template -FullO3CPU::FullO3CPU(O3CPU *o3_cpu, Params *params) +FullO3CPU::FullO3CPU(O3CPU *o3_cpu, DerivO3CPUParams *params) : BaseO3CPU(params), itb(params->itb), dtb(params->dtb), @@ -162,16 +164,16 @@ FullO3CPU::FullO3CPU(O3CPU *o3_cpu, Params *params) regFile(o3_cpu, params->numPhysIntRegs, params->numPhysFloatRegs), - freeList(params->numberOfThreads, + freeList(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs), rob(o3_cpu, params->numROBEntries, params->squashWidth, params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), + params->numThreads), - scoreboard(params->numberOfThreads, + scoreboard(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs, TheISA::NumMiscRegs * number_of_threads, @@ -192,7 +194,7 @@ FullO3CPU::FullO3CPU(O3CPU *o3_cpu, Params *params) physmem(system->physmem), #endif // FULL_SYSTEM drainCount(0), - deferRegistration(params->deferRegistration), + deferRegistration(params->defer_registration), numThreads(number_of_threads) { if (!deferRegistration) { diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 61d7dcf22..611d03bad 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -53,6 +53,8 @@ //#include "cpu/o3/thread_context.hh" #include "sim/process.hh" +#include "params/DerivO3CPU.hh" + template class Checker; class ThreadContext; @@ -63,13 +65,13 @@ class Checkpoint; class MemObject; class Process; +class BaseCPUParams; + class BaseO3CPU : public BaseCPU { //Stuff that's pretty ISA independent will go here. public: - typedef BaseCPU::Params Params; - - BaseO3CPU(Params *params); + BaseO3CPU(BaseCPUParams *params); void regStats(); @@ -96,7 +98,6 @@ class FullO3CPU : public BaseO3CPU typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; typedef O3ThreadState Thread; @@ -256,7 +257,7 @@ class FullO3CPU : public BaseO3CPU public: /** Constructs a CPU with the given parameters. */ - FullO3CPU(O3CPU *o3_cpu, Params *params); + FullO3CPU(O3CPU *o3_cpu, DerivO3CPUParams *params); /** Destructor. */ ~FullO3CPU(); diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index 3e82033ca..dc8063f29 100644 --- a/src/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultDecode class handles both single threaded and SMT * decode. Its width is specified by the parameters; each cycles it @@ -50,7 +52,6 @@ class DefaultDecode // Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol CPUPol; // Typedefs from the CPU policy. @@ -86,7 +87,7 @@ class DefaultDecode public: /** DefaultDecode constructor. */ - DefaultDecode(O3CPU *_cpu, Params *params); + DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of decode. */ std::string name() const; diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh index ce6738456..015bc8d7f 100644 --- a/src/cpu/o3/decode_impl.hh +++ b/src/cpu/o3/decode_impl.hh @@ -30,15 +30,17 @@ #include "cpu/o3/decode.hh" +#include "params/DerivO3CPU.hh" + template -DefaultDecode::DefaultDecode(O3CPU *_cpu, Params *params) +DefaultDecode::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), renameToDecodeDelay(params->renameToDecodeDelay), iewToDecodeDelay(params->iewToDecodeDelay), commitToDecodeDelay(params->commitToDecodeDelay), fetchToDecodeDelay(params->fetchToDecodeDelay), decodeWidth(params->decodeWidth), - numThreads(params->numberOfThreads) + numThreads(params->numThreads) { _status = Inactive; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index d954bd1e7..f12228ff9 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -41,6 +41,8 @@ #include "mem/port.hh" #include "sim/eventq.hh" +class DerivO3CPUParams; + /** * DefaultFetch class handles both single threaded and SMT fetch. Its * width is specified by the parameters; each cycle it tries to fetch @@ -58,7 +60,6 @@ class DefaultFetch typedef typename Impl::DynInst DynInst; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; /** Typedefs from the CPU policy. */ typedef typename CPUPol::BPredUnit BPredUnit; @@ -160,7 +161,7 @@ class DefaultFetch public: /** DefaultFetch constructor. */ - DefaultFetch(O3CPU *_cpu, Params *params); + DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of fetch. */ std::string name() const; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 7d344fa33..0b5ce9380 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -51,6 +51,8 @@ #include "sim/system.hh" #endif // FULL_SYSTEM +#include "params/DerivO3CPU.hh" + template void DefaultFetch::IcachePort::setPeer(Port *port) @@ -111,7 +113,7 @@ DefaultFetch::IcachePort::recvRetry() } template -DefaultFetch::DefaultFetch(O3CPU *_cpu, Params *params) +DefaultFetch::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), branchPred(params), predecoder(NULL), @@ -123,7 +125,7 @@ DefaultFetch::DefaultFetch(O3CPU *_cpu, Params *params) cacheBlocked(false), retryPkt(NULL), retryTid(-1), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), numFetchingThreads(params->smtNumFetchingThreads), interruptPending(false), drainPending(false), diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 457e2a024..3caf847ed 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -41,6 +41,7 @@ #include "cpu/o3/scoreboard.hh" #include "cpu/o3/lsq.hh" +class DerivO3CPUParams; class FUPool; /** @@ -70,7 +71,6 @@ class DefaultIEW typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; typedef typename CPUPol::IQ IQ; typedef typename CPUPol::RenameMap RenameMap; @@ -115,7 +115,7 @@ class DefaultIEW public: /** Constructs a DefaultIEW with the given parameters. */ - DefaultIEW(O3CPU *_cpu, Params *params); + DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of the DefaultIEW stage. */ std::string name() const; diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 84d10e966..1daecd669 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -37,9 +37,10 @@ #include "base/timebuf.hh" #include "cpu/o3/fu_pool.hh" #include "cpu/o3/iew.hh" +#include "params/DerivO3CPU.hh" template -DefaultIEW::DefaultIEW(O3CPU *_cpu, Params *params) +DefaultIEW::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params) : issueToExecQueue(params->backComSize, params->forwardComSize), cpu(_cpu), instQueue(_cpu, this, params), @@ -52,7 +53,7 @@ DefaultIEW::DefaultIEW(O3CPU *_cpu, Params *params) issueWidth(params->issueWidth), wbOutstanding(0), wbWidth(params->wbWidth), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), switchedOut(false) { _status = Active; diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index d0f503977..43da1565d 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -41,8 +41,10 @@ #include "cpu/inst_seq.hh" #include "cpu/o3/dep_graph.hh" #include "cpu/op_class.hh" +#include "sim/eventq.hh" #include "sim/host.hh" +class DerivO3CPUParams; class FUPool; class MemInterface; @@ -70,7 +72,6 @@ class InstructionQueue //Typedefs from the Impl. typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; typedef typename Impl::CPUPol::IEW IEW; typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; @@ -110,7 +111,7 @@ class InstructionQueue }; /** Constructs an IQ. */ - InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Destructs the IQ. */ ~InstructionQueue(); diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index fb06f20df..f3ce770fa 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -37,6 +37,8 @@ #include "enums/OpClass.hh" #include "sim/core.hh" +#include "params/DerivO3CPU.hh" + template InstructionQueue::FUCompletion::FUCompletion(DynInstPtr &_inst, int fu_idx, @@ -65,7 +67,7 @@ InstructionQueue::FUCompletion::description() const template InstructionQueue::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, - Params *params) + DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), fuPool(params->fuPool), @@ -79,7 +81,7 @@ InstructionQueue::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, switchedOut = false; - numThreads = params->numberOfThreads; + numThreads = params->numThreads; // Set the number of physical registers as the number of int + float numPhysRegs = numPhysIntRegs + numPhysFloatRegs; diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 72a8d4021..9e74f4c8c 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -33,17 +33,14 @@ #if THE_ISA == ALPHA_ISA #include "cpu/o3/alpha/cpu.hh" #include "cpu/o3/alpha/impl.hh" - #include "cpu/o3/alpha/params.hh" #include "cpu/o3/alpha/dyn_inst.hh" #elif THE_ISA == MIPS_ISA #include "cpu/o3/mips/cpu.hh" #include "cpu/o3/mips/impl.hh" - #include "cpu/o3/mips/params.hh" #include "cpu/o3/mips/dyn_inst.hh" #elif THE_ISA == SPARC_ISA #include "cpu/o3/sparc/cpu.hh" #include "cpu/o3/sparc/impl.hh" - #include "cpu/o3/sparc/params.hh" #include "cpu/o3/sparc/dyn_inst.hh" #else #error "ISA-specific header files O3CPU not defined ISA" diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 06de608e0..44b69ab40 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -40,10 +40,11 @@ #include "mem/port.hh" #include "sim/sim_object.hh" +class DerivO3CPUParams; + template class LSQ { public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -57,7 +58,7 @@ class LSQ { }; /** Constructs an LSQ with the given parameters. */ - LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params); + LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params); /** Returns the name of the LSQ. */ std::string name() const; diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 8ed6f7f54..f8e77b64e 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -34,6 +34,8 @@ #include "cpu/o3/lsq.hh" +#include "params/DerivO3CPU.hh" + template void LSQ::DcachePort::setPeer(Port *port) @@ -111,11 +113,11 @@ LSQ::DcachePort::recvRetry() } template -LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) +LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), LQEntries(params->LQEntries), SQEntries(params->SQEntries), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), retryTid(-1) { dcachePort.snoopRangeSent = false; diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 3ae69723d..a82ba3ad5 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -46,6 +46,8 @@ #include "mem/packet.hh" #include "mem/port.hh" +class DerivO3CPUParams; + /** * Class that implements the actual LQ and SQ for each specific * thread. Both are circular queues; load entries are freed upon @@ -63,7 +65,6 @@ class LSQUnit { protected: typedef TheISA::IntReg IntReg; public: - typedef typename Impl::Params Params; typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; @@ -75,8 +76,9 @@ class LSQUnit { LSQUnit(); /** Initializes the LSQ unit with the specified number of entries. */ - void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id); + void init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id); /** Returns the name of the LSQ unit. */ std::string name() const; diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index e6ff5e931..4b8d693a6 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -112,8 +112,9 @@ LSQUnit::LSQUnit() template void -LSQUnit::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr, - unsigned maxLQEntries, unsigned maxSQEntries, unsigned id) +LSQUnit::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params, + LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, + unsigned id) { cpu = cpu_ptr; iewStage = iew_ptr; diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index a12a3001b..4f66b4599 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -48,6 +48,8 @@ struct SNHash { } }; +class DerivO3CPUParams; + template class InstructionQueue; @@ -65,14 +67,13 @@ class InstructionQueue; template class MemDepUnit { public: - typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; /** Empty constructor. Must call init() prior to using in this case. */ MemDepUnit(); /** Constructs a MemDepUnit with given parameters. */ - MemDepUnit(Params *params); + MemDepUnit(DerivO3CPUParams *params); /** Frees up any memory allocated. */ ~MemDepUnit(); @@ -81,7 +82,7 @@ class MemDepUnit { std::string name() const; /** Initializes the unit with parameters and a thread id. */ - void init(Params *params, int tid); + void init(DerivO3CPUParams *params, int tid); /** Registers statistics. */ void regStats(); diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh index 64558efaa..124c087f8 100644 --- a/src/cpu/o3/mem_dep_unit_impl.hh +++ b/src/cpu/o3/mem_dep_unit_impl.hh @@ -33,6 +33,8 @@ #include "cpu/o3/inst_queue.hh" #include "cpu/o3/mem_dep_unit.hh" +#include "params/DerivO3CPU.hh" + template MemDepUnit::MemDepUnit() : loadBarrier(false), loadBarrierSN(0), storeBarrier(false), @@ -41,7 +43,7 @@ MemDepUnit::MemDepUnit() } template -MemDepUnit::MemDepUnit(Params *params) +MemDepUnit::MemDepUnit(DerivO3CPUParams *params) : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) { @@ -82,7 +84,7 @@ MemDepUnit::name() const template void -MemDepUnit::init(Params *params, int tid) +MemDepUnit::init(DerivO3CPUParams *params, int tid) { DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh index 3724ced46..38eba5aeb 100755 --- a/src/cpu/o3/mips/cpu.hh +++ b/src/cpu/o3/mips/cpu.hh @@ -39,6 +39,7 @@ #include "sim/byteswap.hh" #include "sim/faults.hh" +class DerivO3CPUParams; class EndQuiesceEvent; namespace Kernel { class Statistics; @@ -60,10 +61,9 @@ class MipsO3CPU : public FullO3CPU public: typedef O3ThreadState ImplState; typedef O3ThreadState Thread; - typedef typename Impl::Params Params; /** Constructs an MipsO3CPU with the given parameters. */ - MipsO3CPU(Params *params); + MipsO3CPU(DerivO3CPUParams *params); /** Registers statistics. */ void regStats(); diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc index 4690b9804..8fe34afab 100644 --- a/src/cpu/o3/mips/cpu_builder.cc +++ b/src/cpu/o3/mips/cpu_builder.cc @@ -35,14 +35,13 @@ #include "cpu/base.hh" #include "cpu/o3/mips/cpu.hh" #include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/params.hh" #include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" class DerivO3CPU : public MipsO3CPU { public: - DerivO3CPU(MipsSimpleParams *p) + DerivO3CPU(DerivO3CPUParams *p) : MipsO3CPU(p) { } }; @@ -50,8 +49,10 @@ class DerivO3CPU : public MipsO3CPU DerivO3CPU * DerivO3CPUParams::create() { - DerivO3CPU *cpu; - +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else // In non-full-system mode, we infer the number of threads from // the workload if it's not explicitly specified. int actual_num_threads = @@ -60,123 +61,20 @@ DerivO3CPUParams::create() if (workload.size() == 0) { fatal("Must specify at least one workload!"); } - - MipsSimpleParams *params = new MipsSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->workload = workload; - -#if USE_CHECKER - params->checker = checker; #endif - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; + numThreads = actual_num_threads; // Default smtFetchPolicy to "RoundRobin", if necessary. std::string round_robin_policy = "RoundRobin"; std::string single_thread = "SingleThread"; if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; + smtFetchPolicy = round_robin_policy; else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; + smtFetchPolicy = smtFetchPolicy; - cpu = new DerivO3CPU(params); + instShiftAmt = 2; - return cpu; + return new DerivO3CPU(this); } diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh index 09d73b4a2..70dbb4ac4 100644 --- a/src/cpu/o3/mips/cpu_impl.hh +++ b/src/cpu/o3/mips/cpu_impl.hh @@ -40,13 +40,14 @@ #include "sim/stats.hh" #include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/params.hh" #include "cpu/o3/mips/thread_context.hh" #include "cpu/o3/comm.hh" #include "cpu/o3/thread_state.hh" +#include "params/DerivO3CPU.hh" + template -MipsO3CPU::MipsO3CPU(Params *params) +MipsO3CPU::MipsO3CPU(DerivO3CPUParams *params) : FullO3CPU(this, params) { DPRINTF(O3CPU, "Creating MipsO3CPU object.\n"); diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh index ac7181a19..481184006 100644 --- a/src/cpu/o3/mips/impl.hh +++ b/src/cpu/o3/mips/impl.hh @@ -34,7 +34,6 @@ #include "arch/mips/isa_traits.hh" -#include "cpu/o3/mips/params.hh" #include "cpu/o3/cpu_policy.hh" @@ -78,9 +77,6 @@ struct MipsSimpleImpl */ typedef O3CPU CPUType; - /** The Params to be passed to each stage. */ - typedef MipsSimpleParams Params; - enum { MaxWidth = 8, MaxThreads = 4 diff --git a/src/cpu/o3/mips/params.hh b/src/cpu/o3/mips/params.hh deleted file mode 100644 index 2688d3fb3..000000000 --- a/src/cpu/o3/mips/params.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_PARAMS_HH__ -#define __CPU_O3_MIPS_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace MipsISA -{ - class MipsDTB; - class MipsITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the MipsO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ - -class MipsSimpleParams : public O3Params -{ - public: - MipsSimpleParams() {} - - //Full System Paramater Objects place here - MipsISA::ITB *itb; - MipsISA::DTB *dtb; -}; - -#endif // __CPU_O3_MIPS_PARAMS_HH__ diff --git a/src/cpu/o3/params.hh b/src/cpu/o3/params.hh deleted file mode 100755 index b487778c6..000000000 --- a/src/cpu/o3/params.hh +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#ifndef __CPU_O3_PARAMS_HH__ -#define __CPU_O3_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" - -//Forward declarations -class FUPool; - -/** - * This file defines the parameters that will be used for the O3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ -class O3Params : public BaseO3CPU::Params -{ - public: - unsigned activity; - - // - // Pointers to key objects - // -#if !FULL_SYSTEM - std::vector workload; - Process *process; -#endif // FULL_SYSTEM - - BaseCPU *checker; - - // - // Caches - // - // MemInterface *icacheInterface; - // MemInterface *dcacheInterface; - - unsigned cachePorts; - - // - // Fetch - // - unsigned decodeToFetchDelay; - unsigned renameToFetchDelay; - unsigned iewToFetchDelay; - unsigned commitToFetchDelay; - unsigned fetchWidth; - - // - // Decode - // - unsigned renameToDecodeDelay; - unsigned iewToDecodeDelay; - unsigned commitToDecodeDelay; - unsigned fetchToDecodeDelay; - unsigned decodeWidth; - - // - // Rename - // - unsigned iewToRenameDelay; - unsigned commitToRenameDelay; - unsigned decodeToRenameDelay; - unsigned renameWidth; - - // - // IEW - // - unsigned commitToIEWDelay; - unsigned renameToIEWDelay; - unsigned issueToExecuteDelay; - unsigned dispatchWidth; - unsigned issueWidth; - unsigned wbWidth; - unsigned wbDepth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - Tick trapLatency; - Tick fetchTrapLatency; - - // - // Timebuffer sizes - // - unsigned backComSize; - unsigned forwardComSize; - - // - // Branch predictor (BP, BTB, RAS) - // - std::string predType; - unsigned localPredictorSize; - unsigned localCtrBits; - unsigned localHistoryTableSize; - unsigned localHistoryBits; - unsigned globalPredictorSize; - unsigned globalCtrBits; - unsigned globalHistoryBits; - unsigned choicePredictorSize; - unsigned choiceCtrBits; - - unsigned BTBEntries; - unsigned BTBTagSize; - - unsigned RASSize; - - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; - - // - // Memory dependence - // - unsigned SSITSize; - unsigned LFSTSize; - - // - // Miscellaneous - // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; - - //SMT Parameters - unsigned smtNumFetchingThreads; - - std::string smtFetchPolicy; - - std::string smtIQPolicy; - unsigned smtIQThreshold; - - std::string smtLSQPolicy; - unsigned smtLSQThreshold; - - std::string smtCommitPolicy; - - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; -}; - -#endif // __CPU_O3_ALPHA_PARAMS_HH__ diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh index 75d3fa6eb..8bd867136 100644 --- a/src/cpu/o3/regfile.hh +++ b/src/cpu/o3/regfile.hh @@ -33,6 +33,7 @@ #define __CPU_O3_REGFILE_HH__ #include "arch/isa_traits.hh" +#include "arch/regfile.hh" #include "arch/types.hh" #include "base/trace.hh" #include "config/full_system.hh" diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index b2faffe43..c9e0d418d 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -36,6 +36,8 @@ #include "base/statistics.hh" #include "base/timebuf.hh" +class DerivO3CPUParams; + /** * DefaultRename handles both single threaded and SMT rename. Its * width is specified by the parameters; each cycle it tries to rename @@ -56,7 +58,6 @@ class DefaultRename typedef typename Impl::CPUPol CPUPol; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; - typedef typename Impl::Params Params; // Typedefs from the CPUPol typedef typename CPUPol::DecodeStruct DecodeStruct; @@ -107,7 +108,7 @@ class DefaultRename public: /** DefaultRename constructor. */ - DefaultRename(O3CPU *_cpu, Params *params); + DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params); /** Returns the name of rename. */ std::string name() const; diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 49c885753..81647b133 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -35,9 +35,10 @@ #include "arch/regfile.hh" #include "config/full_system.hh" #include "cpu/o3/rename.hh" +#include "params/DerivO3CPU.hh" template -DefaultRename::DefaultRename(O3CPU *_cpu, Params *params) +DefaultRename::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), iewToRenameDelay(params->iewToRenameDelay), decodeToRenameDelay(params->decodeToRenameDelay), @@ -46,7 +47,7 @@ DefaultRename::DefaultRename(O3CPU *_cpu, Params *params) commitWidth(params->commitWidth), resumeSerialize(false), resumeUnblocking(false), - numThreads(params->numberOfThreads), + numThreads(params->numThreads), maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs) { _status = Inactive; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh index 3fd193e0f..cccfd7d52 100644 --- a/src/cpu/o3/sparc/cpu.hh +++ b/src/cpu/o3/sparc/cpu.hh @@ -37,6 +37,7 @@ #include "cpu/o3/cpu.hh" #include "sim/byteswap.hh" +class DerivO3CPUParams; class EndQuiesceEvent; namespace Kernel { class Statistics; @@ -58,10 +59,9 @@ class SparcO3CPU : public FullO3CPU public: typedef O3ThreadState ImplState; typedef O3ThreadState Thread; - typedef typename Impl::Params Params; /** Constructs an AlphaO3CPU with the given parameters. */ - SparcO3CPU(Params *params); + SparcO3CPU(DerivO3CPUParams *params); /** Registers statistics. */ void regStats(); diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc index b08845b4e..c5ea31210 100644 --- a/src/cpu/o3/sparc/cpu_builder.cc +++ b/src/cpu/o3/sparc/cpu_builder.cc @@ -35,14 +35,13 @@ #include "cpu/base.hh" #include "cpu/o3/sparc/cpu.hh" #include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/params.hh" #include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" class DerivO3CPU : public SparcO3CPU { public: - DerivO3CPU(SparcSimpleParams *p) + DerivO3CPU(DerivO3CPUParams *p) : SparcO3CPU(p) { } }; @@ -50,8 +49,6 @@ class DerivO3CPU : public SparcO3CPU DerivO3CPU * DerivO3CPUParams::create() { - DerivO3CPU *cpu; - #if FULL_SYSTEM // Full-system only supports a single thread for the moment. int actual_num_threads = 1; @@ -66,135 +63,18 @@ DerivO3CPUParams::create() } #endif - SparcSimpleParams *params = new SparcSimpleParams; - - params->clock = clock; - params->phase = phase; - - params->tracer = tracer; - - params->name = name; - params->numberOfThreads = actual_num_threads; - params->cpu_id = cpu_id; - params->activity = activity; - - params->itb = itb; - params->dtb = dtb; - - params->system = system; -#if FULL_SYSTEM - params->profile = profile; - - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else - params->workload = workload; -#endif // FULL_SYSTEM - -#if USE_CHECKER - params->checker = checker; -#endif - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - - // - // Caches - // - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->dispatchWidth = dispatchWidth; - params->issueWidth = issueWidth; - params->wbWidth = wbWidth; - params->wbDepth = wbDepth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - - params->backComSize = backComSize; - params->forwardComSize = forwardComSize; - - params->predType = predType; - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; + numThreads = actual_num_threads; // Default smtFetchPolicy to "RoundRobin", if necessary. std::string round_robin_policy = "RoundRobin"; std::string single_thread = "SingleThread"; if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - params->smtFetchPolicy = round_robin_policy; + smtFetchPolicy = round_robin_policy; else - params->smtFetchPolicy = smtFetchPolicy; - - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; + smtFetchPolicy = smtFetchPolicy; - cpu = new DerivO3CPU(params); + instShiftAmt = 2; - return cpu; + return new DerivO3CPU(this); } diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh index 068057fc0..2dd38845f 100644 --- a/src/cpu/o3/sparc/cpu_impl.hh +++ b/src/cpu/o3/sparc/cpu_impl.hh @@ -41,7 +41,6 @@ #include "sim/stats.hh" #include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/params.hh" #include "cpu/o3/sparc/thread_context.hh" #include "cpu/o3/comm.hh" #include "cpu/o3/thread_state.hh" @@ -54,8 +53,11 @@ #include "sim/system.hh" #endif +#include "params/DerivO3CPU.hh" + template -SparcO3CPU::SparcO3CPU(Params *params) : FullO3CPU(this, params) +SparcO3CPU::SparcO3CPU(DerivO3CPUParams *params) : + FullO3CPU(this, params) { DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh index 0a970c2f0..982fe36cc 100644 --- a/src/cpu/o3/sparc/impl.hh +++ b/src/cpu/o3/sparc/impl.hh @@ -33,7 +33,6 @@ #include "arch/sparc/isa_traits.hh" -#include "cpu/o3/sparc/params.hh" #include "cpu/o3/cpu_policy.hh" @@ -77,9 +76,6 @@ struct SparcSimpleImpl */ typedef O3CPU CPUType; - /** The Params to be passed to each stage. */ - typedef SparcSimpleParams Params; - enum { MaxWidth = 8, MaxThreads = 4 diff --git a/src/cpu/o3/sparc/params.hh b/src/cpu/o3/sparc/params.hh deleted file mode 100644 index 09f523818..000000000 --- a/src/cpu/o3/sparc/params.hh +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#ifndef __CPU_O3_SPARC_PARAMS_HH__ -#define __CPU_O3_SPARC_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/params.hh" - -//Forward declarations -namespace SparcISA -{ - class DTB; - class ITB; -} -class MemObject; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaO3CPU. - * This must be defined externally so that the Impl can have a params class - * defined that it can pass to all of the individual stages. - */ - -class SparcSimpleParams : public O3Params -{ - public: - - SparcISA::ITB *itb; - SparcISA::DTB *dtb; -}; - -#endif // __CPU_O3_SPARC_PARAMS_HH__ diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh index d8720b3ab..8c634f67e 100644 --- a/src/cpu/o3/thread_state.hh +++ b/src/cpu/o3/thread_state.hh @@ -80,8 +80,8 @@ struct O3ThreadState : public ThreadState { : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), inSyscall(0), trapPending(0) { - if (cpu->params->profile) { - profile = new FunctionProfile(cpu->params->system->kernelSymtab); + if (cpu->params()->profile) { + profile = new FunctionProfile(cpu->params()->system->kernelSymtab); Callback *cb = new MakeCallback(this); diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index a0b358439..e1c1e4cd1 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -28,9 +28,9 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class AtomicSimpleCPU(BaseCPU): +class AtomicSimpleCPU(BaseSimpleCPU): type = 'AtomicSimpleCPU' width = Param.Int(1, "CPU width") simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles") @@ -42,5 +42,5 @@ class AtomicSimpleCPU(BaseCPU): icache_port = Port("Instruction Port") dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") - _mem_ports = BaseCPU._mem_ports + \ + _mem_ports = BaseSimpleCPU._mem_ports + \ ['icache_port', 'dcache_port', 'physmem_port'] diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py new file mode 100644 index 000000000..9f528bc20 --- /dev/null +++ b/src/cpu/simple/BaseSimpleCPU.py @@ -0,0 +1,34 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# 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: Gabe Black + +from m5.params import * +from BaseCPU import BaseCPU + +class BaseSimpleCPU(BaseCPU): + type = 'BaseSimpleCPU' + abstract = True diff --git a/src/cpu/simple/SConscript b/src/cpu/simple/SConscript index c090a938c..76598666f 100644 --- a/src/cpu/simple/SConscript +++ b/src/cpu/simple/SConscript @@ -47,3 +47,4 @@ if 'AtomicSimpleCPU' in env['CPU_MODELS'] or \ if need_simple_base: Source('base.cc') + SimObject('BaseSimpleCPU.py') diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index 7e777e813..f2b14a175 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -28,9 +28,9 @@ from m5.params import * from m5 import build_env -from BaseCPU import BaseCPU +from BaseSimpleCPU import BaseSimpleCPU -class TimingSimpleCPU(BaseCPU): +class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") @@ -38,4 +38,4 @@ class TimingSimpleCPU(BaseCPU): profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") - _mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port'] + _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port'] diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 0e04a36b2..7ed1ee0c3 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -152,7 +152,7 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port) #endif } -AtomicSimpleCPU::AtomicSimpleCPU(Params *p) +AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) : BaseSimpleCPU(p), tickEvent(this), width(p->width), simulate_data_stalls(p->simulate_data_stalls), simulate_inst_stalls(p->simulate_inst_stalls), @@ -812,39 +812,10 @@ AtomicSimpleCPU::printAddr(Addr a) AtomicSimpleCPU * AtomicSimpleCPUParams::create() { - AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); - params->name = name; - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->phase = phase; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->width = width; - params->simulate_data_stalls = simulate_data_stalls; - params->simulate_inst_stalls = simulate_inst_stalls; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); - return cpu; + return new AtomicSimpleCPU(this); } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 008397533..24400df22 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -32,18 +32,13 @@ #define __CPU_SIMPLE_ATOMIC_HH__ #include "cpu/simple/base.hh" +#include "params/AtomicSimpleCPU.hh" class AtomicSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - int width; - bool simulate_data_stalls; - bool simulate_inst_stalls; - }; - - AtomicSimpleCPU(Params *params); + AtomicSimpleCPU(AtomicSimpleCPUParams *params); virtual ~AtomicSimpleCPU(); virtual void init(); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 0c1162032..3fd699868 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -65,16 +65,18 @@ #include "mem/mem_object.hh" #endif // FULL_SYSTEM +#include "params/BaseSimpleCPU.hh" + using namespace std; using namespace TheISA; -BaseSimpleCPU::BaseSimpleCPU(Params *p) +BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p) : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL) { #if FULL_SYSTEM thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); #else - thread = new SimpleThread(this, /* thread_num */ 0, p->process, + thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0], p->itb, p->dtb, /* asid */ 0); #endif // !FULL_SYSTEM diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 62bb31de8..aeae1a3d8 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -76,6 +76,8 @@ namespace Trace { class InstRecord; } +class BaseSimpleCPUParams; + class BaseSimpleCPU : public BaseCPU { @@ -107,15 +109,7 @@ class BaseSimpleCPU : public BaseCPU }; public: - struct Params : public BaseCPU::Params - { - TheISA::ITB *itb; - TheISA::DTB *dtb; -#if !FULL_SYSTEM - Process *process; -#endif - }; - BaseSimpleCPU(Params *params); + BaseSimpleCPU(BaseSimpleCPUParams *params); virtual ~BaseSimpleCPU(); public: diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 4451dfe81..ac67341ff 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -104,7 +104,7 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) Event::schedule(t); } -TimingSimpleCPU::TimingSimpleCPU(Params *p) +TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) { _status = Idle; @@ -852,36 +852,10 @@ TimingSimpleCPU::printAddr(Addr a) TimingSimpleCPU * TimingSimpleCPUParams::create() { - TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); - params->name = name; - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->progress_interval = progress_interval; - params->deferRegistration = defer_registration; - params->clock = clock; - params->phase = phase; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->system = system; - params->cpu_id = cpu_id; - params->tracer = tracer; - - params->itb = itb; - params->dtb = dtb; -#if FULL_SYSTEM - params->profile = profile; - params->do_quiesce = do_quiesce; - params->do_checkpoint_insts = do_checkpoint_insts; - params->do_statistics_insts = do_statistics_insts; -#else + numThreads = 1; +#if !FULL_SYSTEM if (workload.size() != 1) panic("only one workload allowed"); - params->process = workload[0]; #endif - - TimingSimpleCPU *cpu = new TimingSimpleCPU(params); - return cpu; + return new TimingSimpleCPU(this); } diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index a748d47b4..e405f6a41 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -33,14 +33,13 @@ #include "cpu/simple/base.hh" +#include "params/TimingSimpleCPU.hh" + class TimingSimpleCPU : public BaseSimpleCPU { public: - struct Params : public BaseSimpleCPU::Params { - }; - - TimingSimpleCPU(Params *params); + TimingSimpleCPU(TimingSimpleCPUParams * params); virtual ~TimingSimpleCPU(); virtual void init(); diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 8d5c4eafb..ba3312a7a 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -37,9 +37,11 @@ #include "cpu/base.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" +#include "params/BaseCPU.hh" #if FULL_SYSTEM #include "arch/kernel_stats.hh" +#include "arch/stacktrace.hh" #include "base/callback.hh" #include "base/cprintf.hh" #include "base/output.hh" @@ -48,11 +50,10 @@ #include "cpu/quiesce_event.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" -#include "arch/stacktrace.hh" #else +#include "mem/translating_port.hh" #include "sim/process.hh" #include "sim/system.hh" -#include "mem/translating_port.hh" #endif using namespace std; @@ -72,7 +73,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, regs.clear(); - if (cpu->params->profile) { + if (cpu->params()->profile) { profile = new FunctionProfile(system->kernelSymtab); Callback *cb = new MakeCallback Date: Mon, 18 Aug 2008 10:50:58 -0700 Subject: Changed BaseCPU::ProfileEvent's interval member to be of type Tick. This was done to be consistent with its python type of a latency. In addition, the multiple definitions of profile in the different cpu models caused problems for intialization of the interval value. If a child class's profile value was defined, the parent BaseCPU::ProfileEvent interval field would be initialized with a garbage value. The fix was to remove the multiple redifitions of profile in the child CPU classes. --- src/cpu/CheckerCPU.py | 2 -- src/cpu/base.cc | 2 +- src/cpu/base.hh | 4 ++-- src/cpu/o3/O3Checker.py | 2 -- src/cpu/ozone/OzoneCPU.py | 2 -- src/cpu/ozone/OzoneChecker.py | 2 -- src/cpu/simple/AtomicSimpleCPU.py | 2 -- src/cpu/simple/TimingSimpleCPU.py | 2 -- 8 files changed, 3 insertions(+), 15 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py index 06df9c1b1..bff9af62d 100644 --- a/src/cpu/CheckerCPU.py +++ b/src/cpu/CheckerCPU.py @@ -40,5 +40,3 @@ class CheckerCPU(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/base.cc b/src/cpu/base.cc index f79b79350..7b6404419 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -357,7 +357,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) #if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) +BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) : Event(&mainEventQueue), cpu(_cpu), interval(_interval) { } diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 6e9e1dc39..251adc1b7 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -122,10 +122,10 @@ class BaseCPU : public MemObject { private: BaseCPU *cpu; - int interval; + Tick interval; public: - ProfileEvent(BaseCPU *cpu, int interval); + ProfileEvent(BaseCPU *cpu, Tick interval); void process(); }; ProfileEvent *profileEvent; diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py index 43a71d67b..edc6dc9b6 100644 --- a/src/cpu/o3/O3Checker.py +++ b/src/cpu/o3/O3Checker.py @@ -39,5 +39,3 @@ class O3Checker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/ozone/OzoneCPU.py b/src/cpu/ozone/OzoneCPU.py index b9cfb448f..37386898d 100644 --- a/src/cpu/ozone/OzoneCPU.py +++ b/src/cpu/ozone/OzoneCPU.py @@ -40,8 +40,6 @@ class DerivOzoneCPU(BaseCPU): if build_env['USE_CHECKER']: checker = Param.BaseCPU("Checker CPU") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") diff --git a/src/cpu/ozone/OzoneChecker.py b/src/cpu/ozone/OzoneChecker.py index f20b8770e..bfa39ead9 100644 --- a/src/cpu/ozone/OzoneChecker.py +++ b/src/cpu/ozone/OzoneChecker.py @@ -39,5 +39,3 @@ class OzoneChecker(BaseCPU): "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index e1c1e4cd1..87e8b5509 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -37,8 +37,6 @@ class AtomicSimpleCPU(BaseSimpleCPU): simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index f2b14a175..b7f044bfa 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -34,8 +34,6 @@ class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - if build_env['FULL_SYSTEM']: - profile = Param.Latency('0ns', "trace the kernel stack") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port'] -- cgit v1.2.3 From 3633a916c299a1f5df9f6d34a0215cdae68a3e93 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 19 Aug 2008 21:59:09 -0700 Subject: CPU: Get rid of two more duplicated CPU params. --- src/cpu/simple/AtomicSimpleCPU.py | 2 -- src/cpu/simple/TimingSimpleCPU.py | 2 -- 2 files changed, 4 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index 87e8b5509..b7174bb43 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -35,8 +35,6 @@ class AtomicSimpleCPU(BaseSimpleCPU): width = Param.Int(1, "CPU width") simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles") simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles") - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index b7f044bfa..ce6839241 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -32,8 +32,6 @@ from BaseSimpleCPU import BaseSimpleCPU class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") icache_port = Port("Instruction Port") dcache_port = Port("Data Port") _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port'] -- cgit v1.2.3 From 3a3e356f4e61e86f6f1427dd85cf1e41fa9125c0 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 10 Sep 2008 14:26:15 -0400 Subject: style: Remove non-leading tabs everywhere they shouldn't be. Developers should configure their editors to not insert tabs --- src/cpu/base_dyn_inst.hh | 30 +++++++-------- src/cpu/checker/cpu.hh | 2 +- src/cpu/checker/cpu_impl.hh | 4 +- src/cpu/memtest/memtest.hh | 14 +++---- src/cpu/o3/alpha/dyn_inst.hh | 4 +- src/cpu/o3/mips/dyn_inst.hh | 4 +- src/cpu/o3/regfile.hh | 2 +- src/cpu/ozone/back_end.hh | 10 ++--- src/cpu/ozone/cpu_impl.hh | 2 +- src/cpu/ozone/front_end.hh | 2 +- src/cpu/ozone/inorder_back_end.hh | 10 ++--- src/cpu/ozone/lsq_unit_impl.hh | 2 +- src/cpu/ozone/lw_back_end.hh | 2 +- src/cpu/simple/base.hh | 2 +- src/cpu/simple_thread.cc | 4 +- src/cpu/simple_thread.hh | 2 +- src/cpu/static_inst.hh | 78 +++++++++++++++++++-------------------- 17 files changed, 87 insertions(+), 87 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index bea680fac..b03a2f63e 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -77,8 +77,8 @@ class BaseDynInst : public FastAlloc, public RefCounted typedef typename std::list::iterator ListIt; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs }; /** The StaticInst used by this BaseDynInst. */ @@ -486,24 +486,24 @@ class BaseDynInst : public FastAlloc, public RefCounted // // Instruction types. Forward checks to StaticInst object. // - bool isNop() const { return staticInst->isNop(); } - bool isMemRef() const { return staticInst->isMemRef(); } - bool isLoad() const { return staticInst->isLoad(); } - bool isStore() const { return staticInst->isStore(); } + bool isNop() const { return staticInst->isNop(); } + bool isMemRef() const { return staticInst->isMemRef(); } + bool isLoad() const { return staticInst->isLoad(); } + bool isStore() const { return staticInst->isStore(); } bool isStoreConditional() const { return staticInst->isStoreConditional(); } bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } bool isCopy() const { return staticInst->isCopy(); } - bool isInteger() const { return staticInst->isInteger(); } - bool isFloating() const { return staticInst->isFloating(); } - bool isControl() const { return staticInst->isControl(); } - bool isCall() const { return staticInst->isCall(); } - bool isReturn() const { return staticInst->isReturn(); } - bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } + bool isInteger() const { return staticInst->isInteger(); } + bool isFloating() const { return staticInst->isFloating(); } + bool isControl() const { return staticInst->isControl(); } + bool isCall() const { return staticInst->isCall(); } + bool isReturn() const { return staticInst->isReturn(); } + bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } - bool isCondCtrl() const { return staticInst->isCondCtrl(); } - bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } + bool isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } bool isThreadSync() const { return staticInst->isThreadSync(); } bool isSerializing() const { return staticInst->isSerializing(); } @@ -560,7 +560,7 @@ class BaseDynInst : public FastAlloc, public RefCounted Addr branchTarget() const { return staticInst->branchTarget(PC); } /** Returns the number of source registers. */ - int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } /** Returns the number of destination registers. */ int8_t numDestRegs() const { return staticInst->numDestRegs(); } diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 17648d508..5b3c4582c 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -180,7 +180,7 @@ class CheckerCPU : public BaseCPU // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } + Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } void prefetch(Addr addr, unsigned flags) { diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index f3f8a0bb3..33c70569a 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -141,9 +141,9 @@ Checker::verify(DynInstPtr &completed_inst) // Try to fetch the instruction #if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 #else -#define IFETCH_FLAGS(pc) 0 +#define IFETCH_FLAGS(pc) 0 #endif uint64_t fetch_PC = thread->readPC() & ~3; diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index 43f141af6..5a7e0b9ae 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -133,10 +133,10 @@ class MemTest : public MemObject bool accessRetry; - unsigned size; // size of testing memory region + unsigned size; // size of testing memory region - unsigned percentReads; // target percentage of read accesses - unsigned percentFunctional; // target percentage of functional accesses + unsigned percentReads; // target percentage of read accesses + unsigned percentFunctional; // target percentage of functional accesses unsigned percentUncacheable; int id; @@ -154,12 +154,12 @@ class MemTest : public MemObject Addr traceBlockAddr; - Addr baseAddr1; // fix this to option - Addr baseAddr2; // fix this to option + Addr baseAddr1; // fix this to option + Addr baseAddr2; // fix this to option Addr uncacheAddr; - unsigned progressInterval; // frequency of progress reports - Tick nextProgressMessage; // access # for next progress report + unsigned progressInterval; // frequency of progress reports + Tick nextProgressMessage; // access # for next progress report unsigned percentSourceUnaligned; unsigned percentDestUnaligned; diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh index a6fb7b885..180545c3d 100644 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ b/src/cpu/o3/alpha/dyn_inst.hh @@ -67,8 +67,8 @@ class AlphaDynInst : public BaseDynInst typedef TheISA::MiscReg MiscReg; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs }; public: diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh index b1a29ccf9..861577966 100755 --- a/src/cpu/o3/mips/dyn_inst.hh +++ b/src/cpu/o3/mips/dyn_inst.hh @@ -64,8 +64,8 @@ class MipsDynInst : public BaseDynInst typedef TheISA::MiscReg MiscReg; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs }; public: diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh index 8bd867136..53ac2d683 100644 --- a/src/cpu/o3/regfile.hh +++ b/src/cpu/o3/regfile.hh @@ -265,7 +265,7 @@ class PhysRegFile #if FULL_SYSTEM private: - int intrflag; // interrupt flag + int intrflag; // interrupt flag #endif private: diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh index 4cdc86c3c..84429f3c1 100644 --- a/src/cpu/ozone/back_end.hh +++ b/src/cpu/ozone/back_end.hh @@ -447,7 +447,7 @@ class BackEnd Stats::Scalar<> ROB_fcount; Stats::Formula ROB_full_rate; - Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Vector<> ROB_count; // cumulative ROB occupancy Stats::Formula ROB_occ_rate; Stats::VectorDistribution<> ROB_occ_dist; public: @@ -482,8 +482,8 @@ BackEnd::read(RequestPtr req, T &data, int load_idx) memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } else { // do functional access @@ -524,8 +524,8 @@ BackEnd::write(RequestPtr req, T &data, int store_idx) if (result != MA_HIT && dcacheInterface->doEvents()) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; +// unscheduleTickEvent(); +// status = DcacheMissStall; DPRINTF(OzoneCPU, "Dcache miss stall!\n"); } } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index ec531d571..ceb980d4c 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -585,7 +585,7 @@ OzoneCPU::post_interrupt(int int_num, int index) if (_status == Idle) { DPRINTF(IPI,"Suspended Processor awoke\n"); -// thread.activate(); +// thread.activate(); // Hack for now. Otherwise might have to go through the tc, or // I need to figure out what's the right thing to call. activateContext(thread.readTid(), 1); diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index 667392c06..fac243449 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -307,7 +307,7 @@ class FrontEnd Stats::Formula idleRate; Stats::Formula branchRate; Stats::Formula fetchRate; - Stats::Scalar<> IFQCount; // cumulative IFQ occupancy + Stats::Scalar<> IFQCount; // cumulative IFQ occupancy Stats::Formula IFQOccupancy; Stats::Formula IFQLatency; Stats::Scalar<> IFQFcount; // cumulative IFQ full count diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index aef29b1e2..c23d801ba 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -222,7 +222,7 @@ InorderBackEnd::read(Addr addr, T &data, unsigned flags) // are executed twice. memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -249,7 +249,7 @@ InorderBackEnd::write(T data, Addr addr, unsigned flags, uint64_t *res) if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; -// memcpy(memReq->data,(uint8_t *)&data,memReq->size); +// memcpy(memReq->data,(uint8_t *)&data,memReq->size); memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; @@ -261,7 +261,7 @@ InorderBackEnd::write(T data, Addr addr, unsigned flags, uint64_t *res) if (result != MA_HIT) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { @@ -307,7 +307,7 @@ InorderBackEnd::read(MemReqPtr &req, T &data, int load_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss load stall!\n"); } else { @@ -372,7 +372,7 @@ InorderBackEnd::write(MemReqPtr &req, T &data, int store_idx) if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; -// unscheduleTickEvent(); +// unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss store stall!\n"); } else { diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh index 84a90eede..c24410520 100644 --- a/src/cpu/ozone/lsq_unit_impl.hh +++ b/src/cpu/ozone/lsq_unit_impl.hh @@ -553,7 +553,7 @@ OzoneLSQ::writebackStores() MemReqPtr req = storeQueue[storeWBIdx].req; storeQueue[storeWBIdx].committed = true; -// Fault fault = cpu->translateDataReadReq(req); +// Fault fault = cpu->translateDataReadReq(req); req->cmd = Write; req->completionEvent = NULL; req->time = curTick; diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh index a335ab7dc..8ab50d5c9 100644 --- a/src/cpu/ozone/lw_back_end.hh +++ b/src/cpu/ozone/lw_back_end.hh @@ -407,7 +407,7 @@ class LWBackEnd Stats::Scalar<> ROBFcount; Stats::Formula ROBFullRate; - Stats::Vector<> ROBCount; // cumulative ROB occupancy + Stats::Vector<> ROBCount; // cumulative ROB occupancy Stats::Formula ROBOccRate; // Stats::VectorDistribution<> ROBOccDist; public: diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index aeae1a3d8..b7fcf1708 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -227,7 +227,7 @@ class BaseSimpleCPU : public BaseCPU // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); M5_DUMMY_RETURN} void prefetch(Addr addr, unsigned flags) diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index ba3312a7a..0124184e0 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -220,8 +220,8 @@ SimpleThread::activate(int delay) lastActivate = curTick; // if (status() == ThreadContext::Unallocated) { -// cpu->activateWhenReady(tid); -// return; +// cpu->activateWhenReady(tid); +// return; // } _status = ThreadContext::Active; diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 37c3221f5..377bfcd79 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -99,7 +99,7 @@ class SimpleThread : public ThreadState typedef ThreadContext::Status Status; protected: - RegFile regs; // correct-path register context + RegFile regs; // correct-path register context public: // pointer to CPU associated with this SimpleThread diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index ceda78d90..cd4009e76 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -105,38 +105,38 @@ class StaticInstBase : public RefCounted /// implement this behavior via the execute() methods. /// enum Flags { - IsNop, ///< Is a no-op (no effect at all). + IsNop, ///< Is a no-op (no effect at all). - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. + IsInteger, ///< References integer regs. + IsFloating, ///< References FP regs. - IsMemRef, ///< References memory (load, store, or prefetch). - IsLoad, ///< Reads from memory (load or prefetch). - IsStore, ///< Writes to memory. + IsMemRef, ///< References memory (load, store, or prefetch). + IsLoad, ///< Reads from memory (load or prefetch). + IsStore, ///< Writes to memory. IsStoreConditional, ///< Store conditional instruction. IsIndexed, ///< Accesses memory with an indexed address computation - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. + IsInstPrefetch, ///< Instruction-cache prefetch. + IsDataPrefetch, ///< Data-cache prefetch. IsCopy, ///< Fast Cache block copy - IsControl, ///< Control transfer instruction. - IsDirectControl, ///< PC relative control transfer. - IsIndirectControl, ///< Register indirect control transfer. - IsCondControl, ///< Conditional control transfer. - IsUncondControl, ///< Unconditional control transfer. - IsCall, ///< Subroutine call. - IsReturn, ///< Subroutine return. + IsControl, ///< Control transfer instruction. + IsDirectControl, ///< PC relative control transfer. + IsIndirectControl, ///< Register indirect control transfer. + IsCondControl, ///< Conditional control transfer. + IsUncondControl, ///< Unconditional control transfer. + IsCall, ///< Subroutine call. + IsReturn, ///< Subroutine return. IsCondDelaySlot,///< Conditional Delay-Slot Instruction - IsThreadSync, ///< Thread synchronization operation. + IsThreadSync, ///< Thread synchronization operation. - IsSerializing, ///< Serializes pipeline: won't execute until all + IsSerializing, ///< Serializes pipeline: won't execute until all /// older instructions have committed. IsSerializeBefore, IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier + IsMemBarrier, ///< Is a memory barrier + IsWriteBarrier, ///< Is a write barrier IsERET, /// <- Causes the IFU to stall (MIPS ISA) IsNonSpeculative, ///< Should not be executed speculatively @@ -150,12 +150,12 @@ class StaticInstBase : public RefCounted //Flags for microcode IsMacroop, ///< Is a macroop containing microops - IsMicroop, ///< Is a microop - IsDelayedCommit, ///< This microop doesn't commit right away - IsLastMicroop, ///< This microop ends a microop sequence - IsFirstMicroop, ///< This microop begins a microop sequence + IsMicroop, ///< Is a microop + IsDelayedCommit, ///< This microop doesn't commit right away + IsLastMicroop, ///< This microop ends a microop sequence + IsFirstMicroop, ///< This microop begins a microop sequence //This flag doesn't do anything yet - IsMicroBranch, ///< This microop branches within the microcode for a macroop + IsMicroBranch, ///< This microop branches within the microcode for a macroop IsDspOp, NumFlags @@ -215,26 +215,26 @@ class StaticInstBase : public RefCounted /// of the individual flags. //@{ - bool isNop() const { return flags[IsNop]; } + bool isNop() const { return flags[IsNop]; } - bool isMemRef() const { return flags[IsMemRef]; } - bool isLoad() const { return flags[IsLoad]; } - bool isStore() const { return flags[IsStore]; } - bool isStoreConditional() const { return flags[IsStoreConditional]; } + bool isMemRef() const { return flags[IsMemRef]; } + bool isLoad() const { return flags[IsLoad]; } + bool isStore() const { return flags[IsStore]; } + bool isStoreConditional() const { return flags[IsStoreConditional]; } bool isInstPrefetch() const { return flags[IsInstPrefetch]; } bool isDataPrefetch() const { return flags[IsDataPrefetch]; } bool isCopy() const { return flags[IsCopy];} - bool isInteger() const { return flags[IsInteger]; } - bool isFloating() const { return flags[IsFloating]; } + bool isInteger() const { return flags[IsInteger]; } + bool isFloating() const { return flags[IsFloating]; } - bool isControl() const { return flags[IsControl]; } - bool isCall() const { return flags[IsCall]; } - bool isReturn() const { return flags[IsReturn]; } - bool isDirectCtrl() const { return flags[IsDirectControl]; } + bool isControl() const { return flags[IsControl]; } + bool isCall() const { return flags[IsCall]; } + bool isReturn() const { return flags[IsReturn]; } + bool isDirectCtrl() const { return flags[IsDirectControl]; } bool isIndirectCtrl() const { return flags[IsIndirectControl]; } - bool isCondCtrl() const { return flags[IsCondControl]; } - bool isUncondCtrl() const { return flags[IsUncondControl]; } + bool isCondCtrl() const { return flags[IsCondControl]; } + bool isUncondCtrl() const { return flags[IsUncondControl]; } bool isCondDelaySlot() const { return flags[IsCondDelaySlot]; } bool isThreadSync() const { return flags[IsThreadSync]; } @@ -287,8 +287,8 @@ class StaticInst : public StaticInstBase typedef TheISA::RegIndex RegIndex; enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs }; -- cgit v1.2.3 From 6efb930e19056e3421f3bb1996bf370883873b32 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 22 Sep 2008 08:25:57 -0700 Subject: gcc: Version 4.3 is pretty anal about shadowing types, placate it. In the future, it would be nice to put the O3CPU into its own namespace so that we don't end up hardcoding pointers to the global namespace. --- src/cpu/o3/cpu_policy.hh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh index 32a0adcf1..c06c9a201 100644 --- a/src/cpu/o3/cpu_policy.hh +++ b/src/cpu/o3/cpu_policy.hh @@ -65,7 +65,7 @@ struct SimpleCPUPolicy /** Typedef for the branch prediction unit (which includes the BP, * RAS, and BTB). */ - typedef BPredUnit BPredUnit; + typedef ::BPredUnit BPredUnit; /** Typedef for the register file. Most classes assume a unified * physical register file. */ @@ -75,15 +75,15 @@ struct SimpleCPUPolicy /** Typedef for the rename map. */ typedef SimpleRenameMap RenameMap; /** Typedef for the ROB. */ - typedef ROB ROB; + typedef ::ROB ROB; /** Typedef for the instruction queue/scheduler. */ typedef InstructionQueue IQ; /** Typedef for the memory dependence unit. */ - typedef MemDepUnit MemDepUnit; + typedef ::MemDepUnit MemDepUnit; /** Typedef for the LSQ. */ - typedef LSQ LSQ; + typedef ::LSQ LSQ; /** Typedef for the thread-specific LSQ units. */ - typedef LSQUnit LSQUnit; + typedef ::LSQUnit LSQUnit; /** Typedef for fetch. */ typedef DefaultFetch Fetch; @@ -109,7 +109,7 @@ struct SimpleCPUPolicy typedef DefaultIEWDefaultCommit IEWStruct; /** The struct for communication within the IEW stage. */ - typedef IssueStruct IssueStruct; + typedef ::IssueStruct IssueStruct; /** The struct for all backwards communication. */ typedef TimeBufStruct TimeStruct; -- cgit v1.2.3 From 712a8ee70090abc8c8c0fdb4a907e3ec419ae56e Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Fri, 26 Sep 2008 07:44:06 -0700 Subject: O3CPU: Add a hack to ensure that nextPC is set correctly after syscalls. Just check CPU's nextPC before and after syscall and if it changes, update this instruction's nextPC because the syscall must have changed the nextPC. --- src/cpu/o3/alpha/dyn_inst_impl.hh | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/alpha/dyn_inst_impl.hh index 6dfe0ccdd..610a313cf 100644 --- a/src/cpu/o3/alpha/dyn_inst_impl.hh +++ b/src/cpu/o3/alpha/dyn_inst_impl.hh @@ -161,7 +161,15 @@ template void AlphaDynInst::syscall(int64_t callnum) { + // HACK: check CPU's nextPC before and after syscall. If it + // changes, update this instruction's nextPC because the syscall + // must have changed the nextPC. + Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber); this->cpu->syscall(callnum, this->threadNumber); + Addr new_next_pc = this->cpu->readNextPC(this->threadNumber); + if (cpu_next_pc != new_next_pc) { + this->setNextPC(new_next_pc); + } } #endif -- cgit v1.2.3 From b7849032072ed7e93979d625cade3b384aa19948 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Fri, 26 Sep 2008 07:44:07 -0700 Subject: O3CPU: Fix thread writeback logic. Fix the logic in the LSQ that determines if there are any stores to write back. In the commit stage, check for thread specific writebacks instead of just any writeback. --- src/cpu/o3/commit_impl.hh | 8 ++++---- src/cpu/o3/iew.hh | 3 +++ src/cpu/o3/lsq_impl.hh | 15 ++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 86b4da8ce..b16955691 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -814,7 +814,7 @@ DefaultCommit::commit() // @todo: Make this handle multi-cycle communication between // commit and IEW. if (checkEmptyROB[tid] && rob->isEmpty(tid) && - !iewStage->hasStoresToWB() && !committedStores[tid]) { + !iewStage->hasStoresToWB(tid) && !committedStores[tid]) { checkEmptyROB[tid] = false; toIEW->commitInfo[tid].usedROB = true; toIEW->commitInfo[tid].emptyROB = true; @@ -968,7 +968,7 @@ DefaultCommit::commitHead(DynInstPtr &head_inst, unsigned inst_num) "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", head_inst->seqNum, head_inst->readPC()); - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -983,7 +983,7 @@ DefaultCommit::commitHead(DynInstPtr &head_inst, unsigned inst_num) return false; } else if (head_inst->isLoad()) { - if (inst_num > 0 || iewStage->hasStoresToWB()) { + if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { DPRINTF(Commit, "Waiting for all stores to writeback.\n"); return false; } @@ -1038,7 +1038,7 @@ DefaultCommit::commitHead(DynInstPtr &head_inst, unsigned inst_num) DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", head_inst->seqNum, head_inst->readPC()); - if (iewStage->hasStoresToWB() || inst_num > 0) { + if (iewStage->hasStoresToWB(tid) || inst_num > 0) { DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); return false; } diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 3caf847ed..bc60f401b 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -208,6 +208,9 @@ class DefaultIEW /** Returns if the LSQ has any stores to writeback. */ bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } + /** Returns if the LSQ has any stores to writeback. */ + bool hasStoresToWB(unsigned tid) { return ldstQueue.hasStoresToWB(tid); } + void incrWb(InstSeqNum &sn) { if (++wbOutstanding == wbMax) diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index f8e77b64e..5aea020a9 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -584,17 +584,14 @@ LSQ::hasStoresToWB() std::list::iterator threads = activeThreads->begin(); std::list::iterator end = activeThreads->end(); - if (threads == end) - return false; - while (threads != end) { unsigned tid = *threads++; - if (!hasStoresToWB(tid)) - return false; + if (hasStoresToWB(tid)) + return true; } - return true; + return false; } template @@ -607,11 +604,11 @@ LSQ::willWB() while (threads != end) { unsigned tid = *threads++; - if (!willWB(tid)) - return false; + if (willWB(tid)) + return true; } - return true; + return false; } template -- cgit v1.2.3 From 80d9be86e616e819cc3c9a0bbc8a42a5beb41247 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sat, 27 Sep 2008 21:03:49 -0700 Subject: gcc: Add extra parens to quell warnings. Even though we're not incorrect about operator precedence, let's add some parens in some particularly confusing places to placate GCC 4.3 so that we don't have to turn the warning off. Agreed that this is a bit of a pain for those users who get the order of operations correct, but it is likely to prevent bugs in certain cases. --- src/cpu/o3/cpu.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index f06aee634..13a0962fd 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -604,7 +604,7 @@ FullO3CPU::suspendContext(int tid) DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); bool deallocated = deallocateContext(tid, false, 1); // If this was the last thread then unschedule the tick event. - if (activeThreads.size() == 1 && !deallocated || + if ((activeThreads.size() == 1 && !deallocated) || activeThreads.size() == 0) unscheduleTickEvent(); _status = Idle; -- cgit v1.2.3 From c5c6ad7ed6dff171c888aa20d505f87293cc1159 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 9 Oct 2008 00:06:05 -0700 Subject: CPU: Fix where setMicroPC was being called instead of setNextMicroPC. --- src/cpu/thread_context.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index b1687a494..9dffbd8c6 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -429,7 +429,7 @@ class ProxyThreadContext : public ThreadContext uint64_t readNextMicroPC() { return actualTC->readMicroPC(); } - void setNextMicroPC(uint64_t val) { actualTC->setMicroPC(val); } + void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); } MiscReg readMiscRegNoEffect(int misc_reg) { return actualTC->readMiscRegNoEffect(misc_reg); } -- cgit v1.2.3 From e09c403d326488dbc709e3bddc8d497481273950 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 9 Oct 2008 00:08:50 -0700 Subject: O3: Generalize the O3 CPU object so it isn't split out by ISA. --- src/cpu/o3/alpha/cpu.cc | 5 +- src/cpu/o3/alpha/cpu.hh | 149 ----------------- src/cpu/o3/alpha/cpu_builder.cc | 9 +- src/cpu/o3/alpha/cpu_impl.hh | 316 ------------------------------------- src/cpu/o3/alpha/dyn_inst.hh | 2 +- src/cpu/o3/alpha/impl.hh | 4 +- src/cpu/o3/alpha/thread_context.hh | 76 --------- src/cpu/o3/base_dyn_inst.cc | 1 + src/cpu/o3/cpu.cc | 284 +++++++++++++++++++++++++++++++-- src/cpu/o3/cpu.hh | 89 ++++++++++- src/cpu/o3/isa_specific.hh | 3 - src/cpu/o3/mips/cpu.cc | 5 +- src/cpu/o3/mips/cpu.hh | 130 --------------- src/cpu/o3/mips/cpu_builder.cc | 9 +- src/cpu/o3/mips/cpu_impl.hh | 218 ------------------------- src/cpu/o3/mips/dyn_inst.hh | 2 +- src/cpu/o3/mips/impl.hh | 4 +- src/cpu/o3/mips/thread_context.hh | 68 -------- src/cpu/o3/sparc/cpu.cc | 5 +- src/cpu/o3/sparc/cpu.hh | 148 ----------------- src/cpu/o3/sparc/cpu_builder.cc | 8 +- src/cpu/o3/sparc/cpu_impl.hh | 300 ----------------------------------- src/cpu/o3/sparc/dyn_inst.hh | 2 +- src/cpu/o3/sparc/impl.hh | 4 +- src/cpu/o3/sparc/thread_context.hh | 78 --------- src/cpu/o3/thread_context.hh | 44 ++++++ 26 files changed, 428 insertions(+), 1535 deletions(-) delete mode 100644 src/cpu/o3/alpha/cpu.hh delete mode 100644 src/cpu/o3/alpha/cpu_impl.hh delete mode 100644 src/cpu/o3/alpha/thread_context.hh delete mode 100755 src/cpu/o3/mips/cpu.hh delete mode 100644 src/cpu/o3/mips/cpu_impl.hh delete mode 100644 src/cpu/o3/mips/thread_context.hh delete mode 100644 src/cpu/o3/sparc/cpu.hh delete mode 100644 src/cpu/o3/sparc/cpu_impl.hh delete mode 100644 src/cpu/o3/sparc/thread_context.hh (limited to 'src/cpu') diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc index ed10b2fd1..740e6476d 100644 --- a/src/cpu/o3/alpha/cpu.cc +++ b/src/cpu/o3/alpha/cpu.cc @@ -29,10 +29,9 @@ */ #include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/alpha/cpu_impl.hh" -#include "cpu/o3/alpha/dyn_inst.hh" +#include "cpu/o3/cpu.hh" // Force instantiation of AlphaO3CPU for all the implemntations that are // needed. Consider merging this and alpha_dyn_inst.cc, and maybe all // classes that depend on a certain impl, into one file (alpha_impl.cc?). -template class AlphaO3CPU; +template class FullO3CPU; diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh deleted file mode 100644 index f9f0000d4..000000000 --- a/src/cpu/o3/alpha/cpu.hh +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_CPU_HH__ -#define __CPU_O3_ALPHA_CPU_HH__ - -#include "arch/regfile.hh" -#include "arch/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class DerivO3CPUParams; -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * AlphaO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template -class AlphaO3CPU : public FullO3CPU -{ - public: - typedef O3ThreadState ImplState; - typedef O3ThreadState Thread; - - /** Constructs an AlphaO3CPU with the given parameters. */ - AlphaO3CPU(DerivO3CPUParams *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_CPU_HH__ diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc index 0ff0d5d52..deeb437be 100644 --- a/src/cpu/o3/alpha/cpu_builder.cc +++ b/src/cpu/o3/alpha/cpu_builder.cc @@ -30,18 +30,17 @@ #include +#include "config/full_system.hh" #include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/alpha/cpu.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" -class DerivO3CPU : public AlphaO3CPU +class DerivO3CPU : public FullO3CPU { public: DerivO3CPU(DerivO3CPUParams *p) - : AlphaO3CPU(p) + : FullO3CPU(p) { } }; diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh deleted file mode 100644 index dc64113e1..000000000 --- a/src/cpu/o3/alpha/cpu_impl.hh +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#include "config/use_checker.hh" - -#include "arch/alpha/faults.hh" -#include "arch/alpha/isa_traits.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha/cpu.hh" -#include "cpu/o3/alpha/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/alpha/osfpal.hh" -#include "arch/isa_traits.hh" -#include "arch/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -#include "params/DerivO3CPU.hh" - -template -AlphaO3CPU::AlphaO3CPU(DerivO3CPUParams *params) : - FullO3CPU(this, params) -{ - DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - AlphaTC *alpha_tc = - new AlphaTC; - - tc = alpha_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext >( - alpha_tc, this->checker); - } -#endif - - alpha_tc->cpu = this; - alpha_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template -void -AlphaO3CPU::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template -TheISA::MiscReg -AlphaO3CPU::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template -TheISA::MiscReg -AlphaO3CPU::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template -void -AlphaO3CPU::setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template -void -AlphaO3CPU::setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template -void -AlphaO3CPU::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template -void -AlphaO3CPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template -Fault -AlphaO3CPU::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); - - this->thread[tid]->kernelStats->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template -bool -AlphaO3CPU::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->threadContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - exitSimLoop("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template -Fault -AlphaO3CPU::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template -void -AlphaO3CPU::processInterrupts(Fault interrupt) -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template -void -AlphaO3CPU::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template -void -AlphaO3CPU::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template -TheISA::IntReg -AlphaO3CPU::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(AlphaISA::ArgumentReg[i], tid); -} - -template -void -AlphaO3CPU::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(AlphaISA::ArgumentReg[i], val, tid); -} - -template -void -AlphaO3CPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh index 180545c3d..06568bc94 100644 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ b/src/cpu/o3/alpha/dyn_inst.hh @@ -34,8 +34,8 @@ #include "arch/isa_traits.hh" #include "cpu/base_dyn_inst.hh" #include "cpu/inst_seq.hh" -#include "cpu/o3/alpha/cpu.hh" #include "cpu/o3/alpha/impl.hh" +#include "cpu/o3/cpu.hh" class Packet; diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh index d2d04292c..12ee495d1 100644 --- a/src/cpu/o3/alpha/impl.hh +++ b/src/cpu/o3/alpha/impl.hh @@ -41,7 +41,7 @@ template class AlphaDynInst; template -class AlphaO3CPU; +class FullO3CPU; /** Implementation specific struct that defines several key types to the * CPU, the stages within the CPU, the time buffers, and the DynInst. @@ -68,7 +68,7 @@ struct AlphaSimpleImpl typedef RefCountingPtr DynInstPtr; /** The O3CPU type to be used. */ - typedef AlphaO3CPU O3CPU; + typedef FullO3CPU O3CPU; /** Same typedef, but for CPUType. BaseDynInst may not always use * an O3 CPU, so it's clearer to call it CPUType instead in that diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/alpha/thread_context.hh deleted file mode 100644 index 6d61501ac..000000000 --- a/src/cpu/o3/alpha/thread_context.hh +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#include "arch/alpha/types.hh" -#include "cpu/o3/thread_context.hh" - -template -class AlphaTC : public O3ThreadContext -{ - public: -#if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() - { - return this->thread->quiesceEvent; - } -#endif - - virtual uint64_t readNextNPC() - { - return this->readNextPC() + sizeof(TheISA::MachInst); - } - - virtual void setNextNPC(uint64_t val) - { - panic("Alpha has no NextNPC!"); - } - - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } - - - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() - { - this->deallocate(); - - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } -}; diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc index 0979c5c8f..3cf89e1b6 100644 --- a/src/cpu/o3/base_dyn_inst.cc +++ b/src/cpu/o3/base_dyn_inst.cc @@ -29,6 +29,7 @@ */ #include "cpu/base_dyn_inst_impl.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/isa_specific.hh" // Explicit instantiation diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 13a0962fd..18b417141 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -37,6 +37,7 @@ #include "cpu/thread_context.hh" #include "cpu/o3/isa_specific.hh" #include "cpu/o3/cpu.hh" +#include "cpu/o3/thread_context.hh" #include "enums/MemoryMode.hh" #include "sim/core.hh" #include "sim/stat_control.hh" @@ -52,6 +53,10 @@ #include "cpu/checker/cpu.hh" #endif +#if THE_ISA == ALPHA_ISA +#include "arch/alpha/osfpal.hh" +#endif + class BaseCPUParams; using namespace TheISA; @@ -149,26 +154,26 @@ FullO3CPU::DeallocateContextEvent::description() const } template -FullO3CPU::FullO3CPU(O3CPU *o3_cpu, DerivO3CPUParams *params) +FullO3CPU::FullO3CPU(DerivO3CPUParams *params) : BaseO3CPU(params), itb(params->itb), dtb(params->dtb), tickEvent(this), removeInstsThisCycle(false), - fetch(o3_cpu, params), - decode(o3_cpu, params), - rename(o3_cpu, params), - iew(o3_cpu, params), - commit(o3_cpu, params), + fetch(this, params), + decode(this, params), + rename(this, params), + iew(this, params), + commit(this, params), - regFile(o3_cpu, params->numPhysIntRegs, + regFile(this, params->numPhysIntRegs, params->numPhysFloatRegs), freeList(params->numThreads, TheISA::NumIntRegs, params->numPhysIntRegs, TheISA::NumFloatRegs, params->numPhysFloatRegs), - rob(o3_cpu, + rob(this, params->numROBEntries, params->squashWidth, params->smtROBPolicy, params->smtROBThreshold, params->numThreads), @@ -338,8 +343,109 @@ FullO3CPU::FullO3CPU(O3CPU *o3_cpu, DerivO3CPUParams *params) //} contextSwitch = false; + DPRINTF(O3CPU, "Creating O3CPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(O3CPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new typename FullO3CPU::Thread( + (typename Impl::O3CPU *)(this), + i, params->workload[i], i); + + this->thread[i]->setStatus(ThreadContext::Suspended); + + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new typename FullO3CPU::Thread( + (typename Impl::O3CPU *)(this), + i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + O3ThreadContext *o3_tc = new O3ThreadContext; + + tc = o3_tc; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. +#if USE_CHECKER + if (params->checker) { + tc = new CheckerThreadContext >( + o3_tc, this->checker); + } +#endif + + o3_tc->cpu = (typename Impl::O3CPU *)(this); + assert(o3_tc->cpu); + o3_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + this->thread[i]->setCpuId(params->cpu_id); + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + lockAddr = 0; + lockFlag = false; +} + +#if !FULL_SYSTEM + +template +TheISA::IntReg +FullO3CPU::getSyscallArg(int i, int tid) +{ + assert(i < TheISA::NumArgumentRegs); + TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), + TheISA::ArgumentReg[i]); + TheISA::IntReg val = this->readArchIntReg(idx, tid); +#if THE_ISA == SPARC_ISA + if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3)) + val = bits(val, 31, 0); +#endif + return val; } +template +void +FullO3CPU::setSyscallArg(int i, TheISA::IntReg val, int tid) +{ + assert(i < TheISA::NumArgumentRegs); + TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), + TheISA::ArgumentReg[i]); + this->setArchIntReg(idx, val, tid); +} +#endif + template FullO3CPU::~FullO3CPU() { @@ -347,7 +453,7 @@ FullO3CPU::~FullO3CPU() template void -FullO3CPU::fullCPURegStats() +FullO3CPU::regStats() { BaseO3CPU::regStats(); @@ -401,6 +507,11 @@ FullO3CPU::fullCPURegStats() .precision(6); totalIpc = totalCommittedInsts / numCycles; + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); } template @@ -783,6 +894,84 @@ FullO3CPU::activateWhenReady(int tid) } #if FULL_SYSTEM +template +void +FullO3CPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (this->thread[0]->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + this->threadContexts[0]->activate(); + } +} + +template +Fault +FullO3CPU::hwrei(unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + // Need to clear the lock flag upon returning from an interrupt. + this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); + + this->thread[tid]->kernelStats->hwrei(); + + // FIXME: XXX check for interrupts? XXX +#endif + return NoFault; +} + +template +bool +FullO3CPU::simPalCheck(int palFunc, unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->threadContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } +#endif + return true; +} + +template +Fault +FullO3CPU::getInterrupts() +{ + // Check if there are any outstanding interrupts + return this->interrupts.getInterrupt(this->threadContexts[0]); +} + +template +void +FullO3CPU::processInterrupts(Fault interrupt) +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + assert(interrupt != NoFault); + this->interrupts.updateIntrInfo(this->threadContexts[0]); + + DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); + this->trap(interrupt, 0); +} + template void FullO3CPU::updateMemPorts() @@ -794,6 +983,45 @@ FullO3CPU::updateMemPorts() } #endif +template +void +FullO3CPU::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +#if !FULL_SYSTEM + +template +void +FullO3CPU::syscall(int64_t callnum, int tid) +{ + DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +template +void +FullO3CPU::setSyscallReturn(SyscallReturn return_value, int tid) +{ + TheISA::setSyscallReturn(return_value, this->tcBase(tid)); +} + +#endif + template void FullO3CPU::serialize(std::ostream &os) @@ -993,6 +1221,36 @@ FullO3CPU::takeOverFrom(BaseCPU *oldCPU) tickEvent.schedule(nextCycle()); } +template +TheISA::MiscReg +FullO3CPU::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscRegNoEffect(misc_reg, tid); +} + +template +TheISA::MiscReg +FullO3CPU::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template +void +FullO3CPU::setMiscRegNoEffect(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscRegNoEffect(misc_reg, val, tid); +} + +template +void +FullO3CPU::setMiscReg(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscReg(misc_reg, val, tid); +} + template uint64_t FullO3CPU::readIntReg(int reg_idx) @@ -1211,6 +1469,14 @@ FullO3CPU::setNextMicroPC(Addr new_PC,unsigned tid) commit.setNextMicroPC(new_PC, tid); } +template +void +FullO3CPU::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + template typename FullO3CPU::ListIt FullO3CPU::addInst(DynInstPtr &inst) diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 611d03bad..065dd10a0 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -99,6 +99,7 @@ class FullO3CPU : public BaseO3CPU typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::O3CPU O3CPU; + typedef O3ThreadState ImplState; typedef O3ThreadState Thread; typedef typename std::list::iterator ListIt; @@ -201,6 +202,13 @@ class FullO3CPU : public BaseO3CPU activateThreadEvent[tid].squash(); } +#if !FULL_SYSTEM + TheISA::IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, TheISA::IntReg val, int tid); +#endif + /** The tick event used for scheduling CPU ticks. */ ActivateThreadEvent activateThreadEvent[Impl::MaxThreads]; @@ -257,12 +265,12 @@ class FullO3CPU : public BaseO3CPU public: /** Constructs a CPU with the given parameters. */ - FullO3CPU(O3CPU *o3_cpu, DerivO3CPUParams *params); + FullO3CPU(DerivO3CPUParams *params); /** Destructor. */ ~FullO3CPU(); /** Registers statistics. */ - void fullCPURegStats(); + void regStats(); void demapPage(Addr vaddr, uint64_t asn) { @@ -368,12 +376,16 @@ class FullO3CPU : public BaseO3CPU virtual void unserialize(Checkpoint *cp, const std::string §ion); public: - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. */ - virtual void syscall(int tid) { panic("Unimplemented!"); } + void syscall(int64_t callnum, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); + +#endif /** Starts draining the CPU's pipeline of all instructions in * order to stop all memory accesses. */ @@ -395,7 +407,27 @@ class FullO3CPU : public BaseO3CPU InstSeqNum getAndIncrementInstSeq() { return globalSeqNum++; } + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + #if FULL_SYSTEM + /** Posts an interrupt. */ + void post_interrupt(int int_num, int index); + + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + + /** Returns the Fault for any valid interrupt. */ + Fault getInterrupts(); + + /** Processes any an interrupt fault. */ + void processInterrupts(Fault interrupt); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } + /** Update the Virt and Phys ports of all ThreadContexts to * reflect change in memory connections. */ void updateMemPorts(); @@ -425,6 +457,24 @@ class FullO3CPU : public BaseO3CPU #endif /** Register accessors. Index refers to the physical register index. */ + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); + uint64_t readIntReg(int reg_idx); TheISA::FloatReg readFloatReg(int reg_idx); @@ -496,6 +546,12 @@ class FullO3CPU : public BaseO3CPU /** Sets the commit next micro PC of a specific thread. */ void setNextMicroPC(Addr val, unsigned tid); + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + /** Function to add instruction onto the head of the list of the * instructions. Used when new instructions are fetched. */ @@ -711,6 +767,25 @@ class FullO3CPU : public BaseO3CPU /** Available thread ids in the cpu*/ std::vector tids; + /** CPU read function, forwards read to LSQ. */ + template + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; + /** Stat for total number of times the CPU is descheduled. */ Stats::Scalar<> timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 9e74f4c8c..5e759b41d 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -31,15 +31,12 @@ #include "cpu/base.hh" #if THE_ISA == ALPHA_ISA - #include "cpu/o3/alpha/cpu.hh" #include "cpu/o3/alpha/impl.hh" #include "cpu/o3/alpha/dyn_inst.hh" #elif THE_ISA == MIPS_ISA - #include "cpu/o3/mips/cpu.hh" #include "cpu/o3/mips/impl.hh" #include "cpu/o3/mips/dyn_inst.hh" #elif THE_ISA == SPARC_ISA - #include "cpu/o3/sparc/cpu.hh" #include "cpu/o3/sparc/impl.hh" #include "cpu/o3/sparc/dyn_inst.hh" #else diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc index 420f460b2..bb78de0a6 100755 --- a/src/cpu/o3/mips/cpu.cc +++ b/src/cpu/o3/mips/cpu.cc @@ -29,11 +29,10 @@ * Korey Sewell */ +#include "cpu/o3/cpu.hh" #include "cpu/o3/mips/impl.hh" -#include "cpu/o3/mips/cpu_impl.hh" -#include "cpu/o3/mips/dyn_inst.hh" // Force instantiation of MipsO3CPU for all the implemntations that are // needed. Consider merging this and mips_dyn_inst.cc, and maybe all // classes that depend on a certain impl, into one file (mips_impl.cc?). -template class MipsO3CPU; +template class FullO3CPU; diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh deleted file mode 100755 index 38eba5aeb..000000000 --- a/src/cpu/o3/mips/cpu.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_CPU_HH__ -#define __CPU_O3_MIPS_CPU_HH__ - -#include "arch/mips/regfile.hh" -#include "arch/mips/syscallreturn.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" -#include "sim/faults.hh" - -class DerivO3CPUParams; -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * MipsO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template -class MipsO3CPU : public FullO3CPU -{ - public: - typedef O3ThreadState ImplState; - typedef O3ThreadState Thread; - - /** Constructs an MipsO3CPU with the given parameters. */ - MipsO3CPU(DerivO3CPUParams *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, - const TheISA::MiscReg &val, unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); - - /** CPU read function, forwards read to LSQ. */ - template - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_MIPS_CPU_HH__ diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc index 8fe34afab..11942e597 100644 --- a/src/cpu/o3/mips/cpu_builder.cc +++ b/src/cpu/o3/mips/cpu_builder.cc @@ -31,18 +31,17 @@ #include +#include "config/full_system.hh" #include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/mips/cpu.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/mips/impl.hh" -#include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" -class DerivO3CPU : public MipsO3CPU +class DerivO3CPU : public FullO3CPU { public: DerivO3CPU(DerivO3CPUParams *p) - : MipsO3CPU(p) + : FullO3CPU(p) { } }; diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh deleted file mode 100644 index 70dbb4ac4..000000000 --- a/src/cpu/o3/mips/cpu_impl.hh +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include "config/use_checker.hh" - -#include "arch/mips/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/mips/cpu.hh" -#include "cpu/o3/mips/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#include "params/DerivO3CPU.hh" - -template -MipsO3CPU::MipsO3CPU(DerivO3CPUParams *params) - : FullO3CPU(this, params) -{ - DPRINTF(O3CPU, "Creating MipsO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - MipsTC *mips_tc = - new MipsTC; - - tc = mips_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext >( - mips_tc, this->checker); - } -#endif - - mips_tc->cpu = this; - mips_tc->thread = this->thread[i]; - - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template -void -MipsO3CPU::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template -MiscReg -MipsO3CPU::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template -MiscReg -MipsO3CPU::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template -void -MipsO3CPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template -void -MipsO3CPU::setMiscReg(int misc_reg, const MiscReg &val, - unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template -void -MipsO3CPU::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -template -void -MipsO3CPU::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template -void -MipsO3CPU::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); - - DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2)); -} - -template -TheISA::IntReg -MipsO3CPU::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - return this->readArchIntReg(MipsISA::ArgumentReg[i], tid); -} - -template -void -MipsO3CPU::setSyscallArg(int i, IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - this->setArchIntReg(MipsISA::ArgumentReg[i], val, tid); -} - -template -void -MipsO3CPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh index 861577966..320d6703f 100755 --- a/src/cpu/o3/mips/dyn_inst.hh +++ b/src/cpu/o3/mips/dyn_inst.hh @@ -35,7 +35,7 @@ #include "arch/isa_traits.hh" #include "cpu/base_dyn_inst.hh" #include "cpu/inst_seq.hh" -#include "cpu/o3/mips/cpu.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/mips/impl.hh" class Packet; diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh index 481184006..dbaa4a276 100644 --- a/src/cpu/o3/mips/impl.hh +++ b/src/cpu/o3/mips/impl.hh @@ -42,7 +42,7 @@ template class MipsDynInst; template -class MipsO3CPU; +class FullO3CPU; /** Implementation specific struct that defines several key types to the * CPU, the stages within the CPU, the time buffers, and the DynInst. @@ -69,7 +69,7 @@ struct MipsSimpleImpl typedef RefCountingPtr DynInstPtr; /** The O3CPU type to be used. */ - typedef MipsO3CPU O3CPU; + typedef FullO3CPU O3CPU; /** Same typedef, but for CPUType. BaseDynInst may not always use * an O3 CPU, so it's clearer to call it CPUType instead in that diff --git a/src/cpu/o3/mips/thread_context.hh b/src/cpu/o3/mips/thread_context.hh deleted file mode 100644 index 26b1e2e7f..000000000 --- a/src/cpu/o3/mips/thread_context.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include "arch/mips/types.hh" -#include "cpu/o3/thread_context.hh" - -template -class MipsTC : public O3ThreadContext -{ - public: - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } - - virtual void setNextNPC(uint64_t val) - { - this->cpu->setNextNPC(val, this->thread->readTid()); - } - - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Mips!"); } - - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() - { - this->deallocate(); - - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } -}; diff --git a/src/cpu/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc index 1546a2b88..738ff0108 100644 --- a/src/cpu/o3/sparc/cpu.cc +++ b/src/cpu/o3/sparc/cpu.cc @@ -28,11 +28,10 @@ * Authors: Gabe Black */ +#include "cpu/o3/cpu.hh" #include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/sparc/cpu_impl.hh" -#include "cpu/o3/sparc/dyn_inst.hh" // Force instantiation of SparcO3CPU for all the implementations that are // needed. Consider merging this and sparc_dyn_inst.cc, and maybe all // classes that depend on a certain impl, into one file (sparc_impl.cc?). -template class SparcO3CPU; +template class FullO3CPU; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh deleted file mode 100644 index cccfd7d52..000000000 --- a/src/cpu/o3/sparc/cpu.hh +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#ifndef __CPU_O3_SPARC_CPU_HH__ -#define __CPU_O3_SPARC_CPU_HH__ - -#include "arch/sparc/regfile.hh" -#include "arch/sparc/types.hh" -#include "cpu/thread_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class DerivO3CPUParams; -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -class TranslatingPort; - -/** - * SparcO3CPU class. Derives from the FullO3CPU class, and - * implements all ISA and implementation specific functions of the - * CPU. This is the CPU class that is used for the SimObjects, and is - * what is given to the DynInsts. Most of its state exists in the - * FullO3CPU; the state is has is mainly for ISA specific - * functionality. - */ -template -class SparcO3CPU : public FullO3CPU -{ - public: - typedef O3ThreadState ImplState; - typedef O3ThreadState Thread; - - /** Constructs an AlphaO3CPU with the given parameters. */ - SparcO3CPU(DerivO3CPUParams *params); - - /** Registers statistics. */ - void regStats(); - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); - - /** Reads a misc. register, including any side effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); - - /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid); - - /** Sets a misc. register, including any side effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val, - unsigned tid); - - /** Initiates a squash of all in-flight instructions for a given - * thread. The source of the squash is an external update of - * state through the TC. - */ - void squashFromTC(unsigned tid); - -#if FULL_SYSTEM - /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - - bool simPalCheck(int palFunc, unsigned tid); - - /** Returns the Fault for any valid interrupt. */ - Fault getInterrupts(); - - /** Processes any an interrupt fault. */ - void processInterrupts(Fault interrupt); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** CPU read function, forwards read to LSQ. */ - template - Fault read(RequestPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** CPU write function, forwards write to LSQ. */ - template - Fault write(RequestPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - /** Temporary fix for the lock flag, works in the UP case. */ - bool lockFlag; -}; - -#endif // __CPU_O3_SPARC_CPU_HH__ diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc index c5ea31210..c19b4871f 100644 --- a/src/cpu/o3/sparc/cpu_builder.cc +++ b/src/cpu/o3/sparc/cpu_builder.cc @@ -32,17 +32,15 @@ #include "config/full_system.hh" #include "config/use_checker.hh" -#include "cpu/base.hh" -#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/sparc/impl.hh" -#include "cpu/o3/fu_pool.hh" #include "params/DerivO3CPU.hh" -class DerivO3CPU : public SparcO3CPU +class DerivO3CPU : public FullO3CPU { public: DerivO3CPU(DerivO3CPUParams *p) - : SparcO3CPU(p) + : FullO3CPU(p) { } }; diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh deleted file mode 100644 index 2dd38845f..000000000 --- a/src/cpu/o3/sparc/cpu_impl.hh +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#include "config/use_checker.hh" - -#include "arch/sparc/faults.hh" -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/miscregfile.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/thread_context.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/sparc/cpu.hh" -#include "cpu/o3/sparc/thread_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/kernel_stats.hh" -#include "cpu/quiesce_event.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#endif - -#include "params/DerivO3CPU.hh" - -template -SparcO3CPU::SparcO3CPU(DerivO3CPUParams *params) : - FullO3CPU(this, params) -{ - DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); - - // Setup any thread state. - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - // SMT is not supported in FS mode yet. - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0); - this->thread[i]->setStatus(ThreadContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(O3CPU, "Workload[%i] process is %#x", - i, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - - this->thread[i]->setStatus(ThreadContext::Suspended); - - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty thread so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - ThreadContext *tc; - - // Setup the TC that will serve as the interface to the threads/CPU. - SparcTC *sparc_tc = new SparcTC; - - tc = sparc_tc; - - // If we're using a checker, then the TC should be the - // CheckerThreadContext. -#if USE_CHECKER - if (params->checker) { - tc = new CheckerThreadContext >( - sparc_tc, this->checker); - } -#endif - - sparc_tc->cpu = this; - sparc_tc->thread = this->thread[i]; - -#if FULL_SYSTEM - // Setup quiesce event. - this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); -#endif - // Give the thread the TC. - this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); - - // Add the TC to the CPU's list of TC's. - this->threadContexts.push_back(tc); - } - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->setFuncExeInst(0); - } - - lockAddr = 0; - lockFlag = false; -} - -template -void -SparcO3CPU::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - - -template -TheISA::MiscReg -SparcO3CPU::readMiscRegNoEffect(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscRegNoEffect(misc_reg, tid); -} - -template -TheISA::MiscReg -SparcO3CPU::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template -void -SparcO3CPU::setMiscRegNoEffect(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscRegNoEffect(misc_reg, val, tid); -} - -template -void -SparcO3CPU::setMiscReg(int misc_reg, - const SparcISA::MiscReg &val, unsigned tid) -{ - this->regFile.setMiscReg(misc_reg, val, tid); -} - -template -void -SparcO3CPU::squashFromTC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateTCEvent(tid); -} - -#if FULL_SYSTEM - -template -void -SparcO3CPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - -template -Fault -SparcO3CPU::hwrei(unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return NoFault; -} - -template -bool -SparcO3CPU::simPalCheck(int palFunc, unsigned tid) -{ - panic("This doesn't make sense for SPARC\n"); - return true; -} - -template -Fault -SparcO3CPU::getInterrupts() -{ - // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); -} - -template -void -SparcO3CPU::processInterrupts(Fault interrupt) -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); - - DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); - this->trap(interrupt, 0); -} - -#endif // FULL_SYSTEM - -template -void -SparcO3CPU::trap(Fault fault, unsigned tid) -{ - // Pass the thread's TC into the invoke method. - fault->invoke(this->threadContexts[tid]); -} - -#if !FULL_SYSTEM - -template -void -SparcO3CPU::syscall(int64_t callnum, int tid) -{ - DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(callnum); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template -TheISA::IntReg -SparcO3CPU::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - TheISA::IntReg val = this->readArchIntReg(idx, tid); - if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3)) - val = bits(val, 31, 0); - return val; -} - -template -void -SparcO3CPU::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - SparcISA::ArgumentReg[i]); - this->setArchIntReg(idx, val, tid); -} - -template -void -SparcO3CPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} -#endif diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh index a7ab6cd79..4ec41946d 100644 --- a/src/cpu/o3/sparc/dyn_inst.hh +++ b/src/cpu/o3/sparc/dyn_inst.hh @@ -35,7 +35,7 @@ #include "arch/sparc/types.hh" #include "cpu/base_dyn_inst.hh" #include "cpu/inst_seq.hh" -#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/cpu.hh" #include "cpu/o3/sparc/impl.hh" class Packet; diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh index 982fe36cc..bcf8e5cc6 100644 --- a/src/cpu/o3/sparc/impl.hh +++ b/src/cpu/o3/sparc/impl.hh @@ -41,7 +41,7 @@ template class SparcDynInst; template -class SparcO3CPU; +class FullO3CPU; /** Implementation specific struct that defines several key types to the * CPU, the stages within the CPU, the time buffers, and the DynInst. @@ -68,7 +68,7 @@ struct SparcSimpleImpl typedef RefCountingPtr DynInstPtr; /** The O3CPU type to be used. */ - typedef SparcO3CPU O3CPU; + typedef FullO3CPU O3CPU; /** Same typedef, but for CPUType. BaseDynInst may not always use * an O3 CPU, so it's clearer to call it CPUType instead in that diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/cpu/o3/sparc/thread_context.hh deleted file mode 100644 index 7497959e4..000000000 --- a/src/cpu/o3/sparc/thread_context.hh +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#include "arch/sparc/types.hh" -#include "cpu/o3/thread_context.hh" - -template -class SparcTC : public O3ThreadContext -{ - public: -#if FULL_SYSTEM - /** Returns pointer to the quiesce event. */ - virtual EndQuiesceEvent *getQuiesceEvent() - { - return this->thread->quiesceEvent; - } -#endif - - virtual uint64_t readNextNPC() - { - return this->cpu->readNextNPC(this->thread->readTid()); - } - - virtual void setNextNPC(uint64_t val) - { - this->cpu->setNextNPC(val, this->thread->readTid()); - } - - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - //XXX Ignore this for now. This -really- needs to get fixed. - } - - - /** This function exits the thread context in the CPU and returns - * 1 if the CPU has no more active threads (meaning it's OK to exit); - * Used in syscall-emulation mode when a thread executes the 'exit' - * syscall. - */ - virtual int exit() - { - this->deallocate(); - - // If there are still threads executing in the system - if (this->cpu->numActiveThreads()) - return 0; // don't exit simulation - else - return 1; // exit simulation - } -}; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 66dc47f0b..d92f85317 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -260,7 +260,51 @@ class O3ThreadContext : public ThreadContext /** Reads the funcExeInst counter. */ virtual Counter readFuncExeInst() { return thread->funcExeInst; } +#else + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent() + { + return this->thread->quiesceEvent; + } +#endif + + virtual uint64_t readNextNPC() + { + return this->cpu->readNextNPC(this->thread->readTid()); + } + + virtual void setNextNPC(uint64_t val) + { +#if THE_ISA == ALPHA_ISA + panic("Not supported on Alpha!"); #endif + this->cpu->setNextNPC(val, this->thread->readTid()); + } + + virtual void changeRegFileContext(TheISA::RegContextParam param, + TheISA::RegContextVal val) + { +#if THE_ISA != SPARC_ISA + panic("changeRegFileContext not implemented."); +#endif + } + + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system + if (this->cpu->numActiveThreads()) + return 0; // don't exit simulation + else + return 1; // exit simulation + } }; #endif -- cgit v1.2.3 From f57c286d2c3fceae84fde60f148f70305c846772 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 9 Oct 2008 00:09:26 -0700 Subject: O3: Generaize the O3 dynamic instruction class so it isn't split out by ISA. --HG-- rename : src/cpu/o3/dyn_inst.hh => src/cpu/o3/dyn_inst_decl.hh rename : src/cpu/o3/alpha/dyn_inst_impl.hh => src/cpu/o3/dyn_inst_impl.hh --- src/cpu/o3/alpha/dyn_inst.cc | 4 +- src/cpu/o3/alpha/dyn_inst.hh | 277 ------------------------------------- src/cpu/o3/alpha/dyn_inst_impl.hh | 175 ----------------------- src/cpu/o3/alpha/impl.hh | 4 +- src/cpu/o3/dyn_inst.hh | 282 ++++++++++++++++++++++++++++++++++---- src/cpu/o3/dyn_inst_decl.hh | 56 ++++++++ src/cpu/o3/dyn_inst_impl.hh | 181 ++++++++++++++++++++++++ src/cpu/o3/isa_specific.hh | 4 +- src/cpu/o3/mips/dyn_inst.cc | 4 +- src/cpu/o3/mips/dyn_inst.hh | 281 ------------------------------------- src/cpu/o3/mips/dyn_inst_impl.hh | 130 ------------------ src/cpu/o3/mips/impl.hh | 5 +- src/cpu/o3/sparc/dyn_inst.cc | 4 +- src/cpu/o3/sparc/dyn_inst.hh | 265 ----------------------------------- src/cpu/o3/sparc/dyn_inst_impl.hh | 154 --------------------- src/cpu/o3/sparc/impl.hh | 4 +- src/cpu/static_inst.hh | 2 +- 17 files changed, 507 insertions(+), 1325 deletions(-) delete mode 100644 src/cpu/o3/alpha/dyn_inst.hh delete mode 100644 src/cpu/o3/alpha/dyn_inst_impl.hh create mode 100644 src/cpu/o3/dyn_inst_decl.hh create mode 100644 src/cpu/o3/dyn_inst_impl.hh delete mode 100755 src/cpu/o3/mips/dyn_inst.hh delete mode 100755 src/cpu/o3/mips/dyn_inst_impl.hh delete mode 100644 src/cpu/o3/sparc/dyn_inst.hh delete mode 100644 src/cpu/o3/sparc/dyn_inst_impl.hh (limited to 'src/cpu') diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc index 97d2f3d08..28e70be8a 100644 --- a/src/cpu/o3/alpha/dyn_inst.cc +++ b/src/cpu/o3/alpha/dyn_inst.cc @@ -28,9 +28,9 @@ * Authors: Kevin Lim */ -#include "cpu/o3/alpha/dyn_inst_impl.hh" #include "cpu/o3/alpha/impl.hh" +#include "cpu/o3/dyn_inst_impl.hh" // Force instantiation of AlphaDynInst for all the implementations that // are needed. -template class AlphaDynInst; +template class BaseO3DynInst; diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh deleted file mode 100644 index 06568bc94..000000000 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/cpu.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific AlphaDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The AlphaDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template -class AlphaDynInst : public BaseDynInst -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - AlphaDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_ALPHA_DYN_INST_HH__ - diff --git a/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/alpha/dyn_inst_impl.hh deleted file mode 100644 index 610a313cf..000000000 --- a/src/cpu/o3/alpha/dyn_inst_impl.hh +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#include "cpu/o3/alpha/dyn_inst.hh" - -template -AlphaDynInst::AlphaDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -AlphaDynInst::AlphaDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, - Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -AlphaDynInst::AlphaDynInst(StaticInstPtr &_staticInst) - : BaseDynInst(_staticInst) -{ - initVars(); -} - -template -void -AlphaDynInst::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template -Fault -AlphaDynInst::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -AlphaDynInst::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -AlphaDynInst::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -#if FULL_SYSTEM -template -Fault -AlphaDynInst::hwrei() -{ - // Can only do a hwrei when in pal mode. - if (!(this->readPC() & 0x3)) - return new AlphaISA::UnimplementedOpcodeFault; - - // Set the next PC based on the value of the EXC_ADDR IPR. - this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, - this->threadNumber)); - - // Tell CPU to clear any state it needs to if a hwrei is taken. - this->cpu->hwrei(this->threadNumber); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template -void -AlphaDynInst::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template -bool -AlphaDynInst::simPalCheck(int palFunc) -{ - return this->cpu->simPalCheck(palFunc, this->threadNumber); -} -#else -template -void -AlphaDynInst::syscall(int64_t callnum) -{ - // HACK: check CPU's nextPC before and after syscall. If it - // changes, update this instruction's nextPC because the syscall - // must have changed the nextPC. - Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber); - this->cpu->syscall(callnum, this->threadNumber); - Addr new_next_pc = this->cpu->readNextPC(this->threadNumber); - if (cpu_next_pc != new_next_pc) { - this->setNextPC(new_next_pc); - } -} -#endif - diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh index 12ee495d1..7d956cd6a 100644 --- a/src/cpu/o3/alpha/impl.hh +++ b/src/cpu/o3/alpha/impl.hh @@ -38,7 +38,7 @@ // Forward declarations. template -class AlphaDynInst; +class BaseO3DynInst; template class FullO3CPU; @@ -60,7 +60,7 @@ struct AlphaSimpleImpl typedef SimpleCPUPolicy CPUPol; /** The DynInst type to be used. */ - typedef AlphaDynInst DynInst; + typedef BaseO3DynInst DynInst; /** The refcounted DynInst pointer to be used. In most cases this is * what should be used, and not DynInst *. diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index a1f9e0591..292547b6b 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,36 +25,266 @@ * (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: Korey Sewell + * Authors: Kevin Lim */ #ifndef __CPU_O3_DYN_INST_HH__ #define __CPU_O3_DYN_INST_HH__ -#include "arch/isa_specific.hh" - -#if THE_ISA == ALPHA_ISA - template class AlphaDynInst; - struct AlphaSimpleImpl; - typedef AlphaDynInst O3DynInst; -#elif THE_ISA == MIPS_ISA - template class MipsDynInst; - struct MipsSimpleImpl; - typedef MipsDynInst O3DynInst; -#elif THE_ISA == SPARC_ISA - template class SparcDynInst; - struct SparcSimpleImpl; - typedef SparcDynInst O3DynInst; -#elif THE_ISA == X86_ISA - template class X86DynInst; - struct X86SimpleImpl; - typedef X86DynInst O3DynInst; -#elif THE_ISA == ARM_ISA - template class ArmDynInst; - struct ArmSimpleImpl; - typedef ArmDynInst O3DynInst; +#include "arch/isa_traits.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/isa_specific.hh" + +class Packet; + +/** + * Mostly implementation & ISA specific AlphaDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The AlphaDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template +class BaseO3DynInst : public BaseDynInst +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::O3CPU O3CPU; + + /** Binary machine instruction type. */ + typedef TheISA::MachInst MachInst; + /** Extended machine instruction type. */ + typedef TheISA::ExtMachInst ExtMachInst; + /** Logical register index type. */ + typedef TheISA::RegIndex RegIndex; + /** Integer register index type. */ + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + /** Misc register index type. */ + typedef TheISA::MiscReg MiscReg; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. */ + BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a binary instruction. */ + BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + BaseO3DynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(PacketPtr pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg) + { + return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val) + { + return this->cpu->setMiscReg(misc_reg, val, + this->threadNumber); + } + + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) + { + return this->cpu->readMiscRegNoEffect( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readMiscReg( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) + { + return this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); #else - #error "O3DynInst not defined for this ISA" + /** Calls a syscall. */ + void syscall(int64_t callnum); #endif -#endif // __CPU_O3_DYN_INST_HH__ + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(this->_srcRegIdx[idx]); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); + } + + FloatReg readFloatRegOperand(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); + } + + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(this->_destRegIdx[idx], val); + BaseDynInst::setIntRegOperand(si, idx, val); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); + BaseDynInst::setFloatRegOperand(si, idx, val, width); + } + + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val); + BaseDynInst::setFloatRegOperand(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); + BaseDynInst::setFloatRegOperandBits(si, idx, val); + } + + void setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); + BaseDynInst::setFloatRegOperandBits(si, idx, val); + } + +#if THE_ISA == MIPS_ISA + uint64_t readRegOtherThread(int misc_reg) + { + panic("MIPS MT not defined for O3 CPU.\n"); + return 0; + } + + void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) + { + panic("MIPS MT not defined for O3 CPU.\n"); + } +#endif + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_ALPHA_DYN_INST_HH__ + diff --git a/src/cpu/o3/dyn_inst_decl.hh b/src/cpu/o3/dyn_inst_decl.hh new file mode 100644 index 000000000..750c3279d --- /dev/null +++ b/src/cpu/o3/dyn_inst_decl.hh @@ -0,0 +1,56 @@ +/* + * 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: Korey Sewell + */ + +#ifndef __CPU_O3_DYN_INST_DECL_HH__ +#define __CPU_O3_DYN_INST_DECL_HH__ + +#include "arch/isa_specific.hh" + +template class BaseO3DynInst; +#if THE_ISA == ALPHA_ISA + struct AlphaSimpleImpl; + typedef BaseO3DynInst O3DynInst; +#elif THE_ISA == MIPS_ISA + struct MipsSimpleImpl; + typedef BaseO3DynInst O3DynInst; +#elif THE_ISA == SPARC_ISA + struct SparcSimpleImpl; + typedef BaseO3DynInst O3DynInst; +#elif THE_ISA == X86_ISA + struct X86SimpleImpl; + typedef BaseO3DynInst O3DynInst; +#elif THE_ISA == ARM_ISA + struct ArmSimpleImpl; + typedef BaseO3DynInst O3DynInst; +#else + #error "O3DynInst not defined for this ISA" +#endif + +#endif // __CPU_O3_DYN_INST_DECL_HH__ diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh new file mode 100644 index 000000000..6398a3afe --- /dev/null +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2004-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: Kevin Lim + */ + +#include "cpu/o3/dyn_inst.hh" + +template +BaseO3DynInst::BaseO3DynInst(StaticInstPtr staticInst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) + : BaseDynInst(staticInst, PC, NPC, microPC, + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) +{ + initVars(); +} + +template +BaseO3DynInst::BaseO3DynInst(ExtMachInst inst, + Addr PC, Addr NPC, Addr microPC, + Addr Pred_PC, Addr Pred_NPC, + Addr Pred_MicroPC, + InstSeqNum seq_num, O3CPU *cpu) + : BaseDynInst(inst, PC, NPC, microPC, + Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) +{ + initVars(); +} + +template +BaseO3DynInst::BaseO3DynInst(StaticInstPtr &_staticInst) + : BaseDynInst(_staticInst) +{ + initVars(); +} + +template +void +BaseO3DynInst::initVars() +{ + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + this->_destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } +} + +template +Fault +BaseO3DynInst::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template +Fault +BaseO3DynInst::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template +Fault +BaseO3DynInst::completeAcc(PacketPtr pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +#if FULL_SYSTEM +template +Fault +BaseO3DynInst::hwrei() +{ +#if THE_ISA == ALPHA_ISA + // Can only do a hwrei when in pal mode. + if (!(this->readPC() & 0x3)) + return new AlphaISA::UnimplementedOpcodeFault; + + // Set the next PC based on the value of the EXC_ADDR IPR. + this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, + this->threadNumber)); + + // Tell CPU to clear any state it needs to if a hwrei is taken. + this->cpu->hwrei(this->threadNumber); +#else + +#endif + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template +void +BaseO3DynInst::trap(Fault fault) +{ + this->cpu->trap(fault, this->threadNumber); +} + +template +bool +BaseO3DynInst::simPalCheck(int palFunc) +{ +#if THE_ISA != ALPHA_ISA + panic("simPalCheck called, but PAL only exists in Alpha!\n"); +#endif + return this->cpu->simPalCheck(palFunc, this->threadNumber); +} +#else +template +void +BaseO3DynInst::syscall(int64_t callnum) +{ + // HACK: check CPU's nextPC before and after syscall. If it + // changes, update this instruction's nextPC because the syscall + // must have changed the nextPC. + Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber); + this->cpu->syscall(callnum, this->threadNumber); + Addr new_next_pc = this->cpu->readNextPC(this->threadNumber); + if (cpu_next_pc != new_next_pc) { + this->setNextPC(new_next_pc); + } +} +#endif + diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 5e759b41d..6111a5336 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -32,13 +32,11 @@ #if THE_ISA == ALPHA_ISA #include "cpu/o3/alpha/impl.hh" - #include "cpu/o3/alpha/dyn_inst.hh" #elif THE_ISA == MIPS_ISA #include "cpu/o3/mips/impl.hh" - #include "cpu/o3/mips/dyn_inst.hh" #elif THE_ISA == SPARC_ISA #include "cpu/o3/sparc/impl.hh" - #include "cpu/o3/sparc/dyn_inst.hh" #else #error "ISA-specific header files O3CPU not defined ISA" #endif +#include "cpu/o3/dyn_inst.hh" diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc index 216aa7d2c..88205afaf 100755 --- a/src/cpu/o3/mips/dyn_inst.cc +++ b/src/cpu/o3/mips/dyn_inst.cc @@ -29,9 +29,9 @@ * Korey Sewell */ -#include "cpu/o3/mips/dyn_inst_impl.hh" +#include "cpu/o3/dyn_inst_impl.hh" #include "cpu/o3/mips/impl.hh" // Force instantiation of MipsDynInst for all the implementations that // are needed. -template class MipsDynInst; +template class BaseO3DynInst; diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh deleted file mode 100755 index 320d6703f..000000000 --- a/src/cpu/o3/mips/dyn_inst.hh +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_DYN_INST_HH__ -#define __CPU_O3_MIPS_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/cpu.hh" -#include "cpu/o3/mips/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific MipsDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The MipsDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template -class MipsDynInst : public BaseDynInst -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - MipsDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - /** TODO: Use thread number from argument if given, will probably not work for MIPS MT as is */ - MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - MiscReg readMiscReg(int misc_reg, unsigned tid = 0) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - this->instResult.integer = val; - this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - - /** Calls a syscall. */ - void syscall(int64_t callnum); - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(this->_srcRegIdx[idx]); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, - int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, - int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand(const StaticInst *si, int idx, - const MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - uint64_t readRegOtherThread(int misc_reg) - { - panic("MIPS MT not defined for O3 CPU.\n"); - return 0; - } - - void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val) - { - panic("MIPS MT not defined for O3 CPU.\n"); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_MIPS_DYN_INST_HH__ - diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh deleted file mode 100755 index 7e8697b32..000000000 --- a/src/cpu/o3/mips/dyn_inst_impl.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#include "cpu/o3/mips/dyn_inst.hh" - -template -MipsDynInst::MipsDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -MipsDynInst::MipsDynInst(ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -MipsDynInst::MipsDynInst(StaticInstPtr &_staticInst) - : BaseDynInst(_staticInst) -{ - initVars(); -} - -template -void -MipsDynInst::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template -Fault -MipsDynInst::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -MipsDynInst::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -MipsDynInst::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -template -void -MipsDynInst::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} - diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh index dbaa4a276..78afd1387 100644 --- a/src/cpu/o3/mips/impl.hh +++ b/src/cpu/o3/mips/impl.hh @@ -36,10 +36,9 @@ #include "cpu/o3/cpu_policy.hh" - // Forward declarations. template -class MipsDynInst; +class BaseO3DynInst; template class FullO3CPU; @@ -61,7 +60,7 @@ struct MipsSimpleImpl typedef SimpleCPUPolicy CPUPol; /** The DynInst type to be used. */ - typedef MipsDynInst DynInst; + typedef BaseO3DynInst DynInst; /** The refcounted DynInst pointer to be used. In most cases this is * what should be used, and not DynInst *. diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/sparc/dyn_inst.cc index 984b58f4b..ea86f8719 100644 --- a/src/cpu/o3/sparc/dyn_inst.cc +++ b/src/cpu/o3/sparc/dyn_inst.cc @@ -28,9 +28,9 @@ * Authors: Gabe Black */ -#include "cpu/o3/sparc/dyn_inst_impl.hh" +#include "cpu/o3/dyn_inst_impl.hh" #include "cpu/o3/sparc/impl.hh" // Force instantiation of SparcDynInst for all the implementations that // are needed. -template class SparcDynInst; +template class BaseO3DynInst; diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh deleted file mode 100644 index 4ec41946d..000000000 --- a/src/cpu/o3/sparc/dyn_inst.hh +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#ifndef __CPU_O3_SPARC_DYN_INST_HH__ -#define __CPU_O3_SPARC_DYN_INST_HH__ - -#include "arch/sparc/isa_traits.hh" -#include "arch/sparc/types.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/cpu.hh" -#include "cpu/o3/sparc/impl.hh" - -class Packet; - -/** - * Mostly implementation & ISA specific SparcDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The SparcDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template -class SparcDynInst : public BaseDynInst -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::O3CPU O3CPU; - - public: - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a binary instruction. */ - SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - SparcDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(PacketPtr pkt); - - private: - /** Initializes variables. */ - void initVars(); - - public: - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegNoEffect(int misc_reg) - { - return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscReg(int misc_reg, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg(misc_reg, val, - this->threadNumber); - } - - /** Reads a miscellaneous register. */ - TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx) - { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Reads a misc. register, including any side-effects the read - * might have as defined by the architecture. - */ - TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); - } - - /** Sets a misc. register. */ - void setMiscRegOperandNoEffect(const StaticInst * si, - int idx, const TheISA::MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscRegNoEffect( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - - /** Sets a misc. register, including any side-effects the write - * might have as defined by the architecture. - */ - void setMiscRegOperand( - const StaticInst *si, int idx, const TheISA::MiscReg &val) - { - return this->cpu->setMiscReg( - si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - val, this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(int64_t callnum); -#endif - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntRegOperand(const StaticInst *si, int idx) - { - uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]); - DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val); - return val; - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); - } - - TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx) - { - return this->cpu->readFloatReg(this->_srcRegIdx[idx]); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, - int idx, int width) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); - } - - TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) - { - DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val); - this->cpu->setIntReg(this->_destRegIdx[idx], val); - BaseDynInst::setIntRegOperand(si, idx, val); - } - - void setFloatRegOperand(const StaticInst *si, int idx, - TheISA::FloatReg val, int width) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperand(si, idx, val, width); - } - - void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val) - { - this->cpu->setFloatReg(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperand(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, int idx, - TheISA::FloatRegBits val, int width) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - void setFloatRegOperandBits(const StaticInst *si, - int idx, TheISA::FloatRegBits val) - { - this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); - BaseDynInst::setFloatRegOperandBits(si, idx, val); - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_SPARC_DYN_INST_HH__ - diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh deleted file mode 100644 index 6bfe97717..000000000 --- a/src/cpu/o3/sparc/dyn_inst_impl.hh +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#include "cpu/o3/sparc/dyn_inst.hh" - -template -SparcDynInst::SparcDynInst(StaticInstPtr staticInst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(staticInst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -SparcDynInst::SparcDynInst(TheISA::ExtMachInst inst, - Addr PC, Addr NPC, Addr microPC, - Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC, - InstSeqNum seq_num, O3CPU *cpu) - : BaseDynInst(inst, PC, NPC, microPC, - Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu) -{ - initVars(); -} - -template -SparcDynInst::SparcDynInst(StaticInstPtr &_staticInst) - : BaseDynInst(_staticInst) -{ - initVars(); -} - -template -void -SparcDynInst::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - this->_destRegIdx[i] = this->staticInst->destRegIdx(i); - } - - for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); - this->_readySrcRegIdx[i] = 0; - } -} - -template -Fault -SparcDynInst::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -SparcDynInst::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening - // when using the TC during an instruction's execution - // (specifically for instructions that have side-effects that use - // the TC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template -Fault -SparcDynInst::completeAcc(PacketPtr pkt) -{ - this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); - - return this->fault; -} - -#if FULL_SYSTEM -template -Fault -SparcDynInst::hwrei() -{ - return NoFault; -} - -template -void -SparcDynInst::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template -bool -SparcDynInst::simPalCheck(int palFunc) -{ - panic("simPalCheck called, but there's no PAL in SPARC!\n"); - return false; -} -#else -template -void -SparcDynInst::syscall(int64_t callnum) -{ - this->cpu->syscall(callnum, this->threadNumber); -} -#endif - diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh index bcf8e5cc6..cf0e33e42 100644 --- a/src/cpu/o3/sparc/impl.hh +++ b/src/cpu/o3/sparc/impl.hh @@ -38,7 +38,7 @@ // Forward declarations. template -class SparcDynInst; +class BaseO3DynInst; template class FullO3CPU; @@ -60,7 +60,7 @@ struct SparcSimpleImpl typedef SimpleCPUPolicy CPUPol; /** The DynInst type to be used. */ - typedef SparcDynInst DynInst; + typedef BaseO3DynInst DynInst; /** The refcounted DynInst pointer to be used. In most cases this is * what should be used, and not DynInst *. diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index cd4009e76..2c3c3dbc2 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -42,7 +42,7 @@ #include "base/misc.hh" #include "base/refcnt.hh" #include "cpu/op_class.hh" -#include "cpu/o3/dyn_inst.hh" +#include "cpu/o3/dyn_inst_decl.hh" #include "sim/faults.hh" #include "sim/host.hh" -- cgit v1.2.3 From b66eb3b8d1e759bacb55ef187541f4c37767241a Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 9 Oct 2008 00:10:02 -0700 Subject: O3: Generaize the O3 IMPL class so it isn't split out by ISA. --HG-- rename : src/cpu/o3/sparc/cpu_builder.cc => src/cpu/o3/cpu_builder.cc rename : src/cpu/o3/sparc/dyn_inst.cc => src/cpu/o3/dyn_inst.cc rename : src/cpu/o3/sparc/impl.hh => src/cpu/o3/impl.hh rename : src/cpu/o3/sparc/thread_context.cc => src/cpu/o3/thread_context.cc --- src/cpu/o3/SConscript | 21 ++------- src/cpu/o3/alpha/cpu.cc | 37 ---------------- src/cpu/o3/alpha/cpu_builder.cc | 78 --------------------------------- src/cpu/o3/alpha/dyn_inst.cc | 36 ---------------- src/cpu/o3/alpha/impl.hh | 88 -------------------------------------- src/cpu/o3/alpha/thread_context.cc | 36 ---------------- src/cpu/o3/cpu_builder.cc | 78 +++++++++++++++++++++++++++++++++ src/cpu/o3/dyn_inst.cc | 36 ++++++++++++++++ src/cpu/o3/dyn_inst_decl.hh | 56 ------------------------ src/cpu/o3/impl.hh | 85 ++++++++++++++++++++++++++++++++++++ src/cpu/o3/isa_specific.hh | 10 +---- src/cpu/o3/mips/cpu.cc | 38 ---------------- src/cpu/o3/mips/cpu_builder.cc | 79 ---------------------------------- src/cpu/o3/mips/dyn_inst.cc | 37 ---------------- src/cpu/o3/mips/impl.hh | 88 -------------------------------------- src/cpu/o3/mips/thread_context.cc | 36 ---------------- src/cpu/o3/sparc/cpu.cc | 37 ---------------- src/cpu/o3/sparc/cpu_builder.cc | 78 --------------------------------- src/cpu/o3/sparc/dyn_inst.cc | 36 ---------------- src/cpu/o3/sparc/impl.hh | 88 -------------------------------------- src/cpu/o3/sparc/thread_context.cc | 35 --------------- src/cpu/o3/thread_context.cc | 36 ++++++++++++++++ src/cpu/static_inst.hh | 5 ++- 23 files changed, 243 insertions(+), 911 deletions(-) delete mode 100644 src/cpu/o3/alpha/cpu.cc delete mode 100644 src/cpu/o3/alpha/cpu_builder.cc delete mode 100644 src/cpu/o3/alpha/dyn_inst.cc delete mode 100644 src/cpu/o3/alpha/impl.hh delete mode 100755 src/cpu/o3/alpha/thread_context.cc create mode 100644 src/cpu/o3/cpu_builder.cc create mode 100644 src/cpu/o3/dyn_inst.cc delete mode 100644 src/cpu/o3/dyn_inst_decl.hh create mode 100644 src/cpu/o3/impl.hh delete mode 100755 src/cpu/o3/mips/cpu.cc delete mode 100644 src/cpu/o3/mips/cpu_builder.cc delete mode 100755 src/cpu/o3/mips/dyn_inst.cc delete mode 100644 src/cpu/o3/mips/impl.hh delete mode 100755 src/cpu/o3/mips/thread_context.cc delete mode 100644 src/cpu/o3/sparc/cpu.cc delete mode 100644 src/cpu/o3/sparc/cpu_builder.cc delete mode 100644 src/cpu/o3/sparc/dyn_inst.cc delete mode 100644 src/cpu/o3/sparc/impl.hh delete mode 100755 src/cpu/o3/sparc/thread_context.cc create mode 100755 src/cpu/o3/thread_context.cc (limited to 'src/cpu') diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript index 2de106d8b..f05986bf5 100755 --- a/src/cpu/o3/SConscript +++ b/src/cpu/o3/SConscript @@ -51,7 +51,9 @@ if 'O3CPU' in env['CPU_MODELS']: Source('bpred_unit.cc') Source('commit.cc') Source('cpu.cc') + Source('cpu_builder.cc') Source('decode.cc') + Source('dyn_inst.cc') Source('fetch.cc') Source('free_list.cc') Source('fu_pool.cc') @@ -65,6 +67,7 @@ if 'O3CPU' in env['CPU_MODELS']: Source('rob.cc') Source('scoreboard.cc') Source('store_set.cc') + Source('thread_context.cc') TraceFlag('FreeList') TraceFlag('LSQ') @@ -81,24 +84,6 @@ if 'O3CPU' in env['CPU_MODELS']: 'IQ', 'ROB', 'FreeList', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'O3CPU', 'Activity', 'Scoreboard', 'Writeback' ]) - if env['TARGET_ISA'] == 'alpha': - Source('alpha/cpu.cc') - Source('alpha/cpu_builder.cc') - Source('alpha/dyn_inst.cc') - Source('alpha/thread_context.cc') - elif env['TARGET_ISA'] == 'mips': - Source('mips/cpu.cc') - Source('mips/cpu_builder.cc') - Source('mips/dyn_inst.cc') - Source('mips/thread_context.cc') - elif env['TARGET_ISA'] == 'sparc': - Source('sparc/cpu.cc') - Source('sparc/cpu_builder.cc') - Source('sparc/dyn_inst.cc') - Source('sparc/thread_context.cc') - else: - sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA']) - if env['USE_CHECKER']: SimObject('O3Checker.py') Source('checker_builder.cc') diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc deleted file mode 100644 index 740e6476d..000000000 --- a/src/cpu/o3/alpha/cpu.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Kevin Lim - */ - -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/cpu.hh" - -// Force instantiation of AlphaO3CPU for all the implemntations that are -// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (alpha_impl.cc?). -template class FullO3CPU; diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc deleted file mode 100644 index deeb437be..000000000 --- a/src/cpu/o3/alpha/cpu_builder.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - */ - -#include - -#include "config/full_system.hh" -#include "config/use_checker.hh" -#include "cpu/o3/cpu.hh" -#include "cpu/o3/alpha/impl.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public FullO3CPU -{ - public: - DerivO3CPU(DerivO3CPUParams *p) - : FullO3CPU(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - numThreads = actual_num_threads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - smtFetchPolicy = round_robin_policy; - else - smtFetchPolicy = smtFetchPolicy; - - instShiftAmt = 2; - - return new DerivO3CPU(this); -} diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc deleted file mode 100644 index 28e70be8a..000000000 --- a/src/cpu/o3/alpha/dyn_inst.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Kevin Lim - */ - -#include "cpu/o3/alpha/impl.hh" -#include "cpu/o3/dyn_inst_impl.hh" - -// Force instantiation of AlphaDynInst for all the implementations that -// are needed. -template class BaseO3DynInst; diff --git a/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh deleted file mode 100644 index 7d956cd6a..000000000 --- a/src/cpu/o3/alpha/impl.hh +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Kevin Lim - */ - -#ifndef __CPU_O3_ALPHA_IMPL_HH__ -#define __CPU_O3_ALPHA_IMPL_HH__ - -#include "arch/alpha/isa_traits.hh" - -#include "cpu/o3/cpu_policy.hh" - - -// Forward declarations. -template -class BaseO3DynInst; - -template -class FullO3CPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific O3CPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct AlphaSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy CPUPol; - - /** The DynInst type to be used. */ - typedef BaseO3DynInst DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr DynInstPtr; - - /** The O3CPU type to be used. */ - typedef FullO3CPU O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef AlphaSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/alpha/thread_context.cc deleted file mode 100755 index 4a02715bc..000000000 --- a/src/cpu/o3/alpha/thread_context.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-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: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" - -template class O3ThreadContext; - diff --git a/src/cpu/o3/cpu_builder.cc b/src/cpu/o3/cpu_builder.cc new file mode 100644 index 000000000..77d7091ad --- /dev/null +++ b/src/cpu/o3/cpu_builder.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004-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: Kevin Lim + */ + +#include + +#include "config/full_system.hh" +#include "config/use_checker.hh" +#include "cpu/o3/cpu.hh" +#include "cpu/o3/impl.hh" +#include "params/DerivO3CPU.hh" + +class DerivO3CPU : public FullO3CPU +{ + public: + DerivO3CPU(DerivO3CPUParams *p) + : FullO3CPU(p) + { } +}; + +DerivO3CPU * +DerivO3CPUParams::create() +{ +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + (numThreads >= workload.size()) ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } +#endif + + numThreads = actual_num_threads; + + // Default smtFetchPolicy to "RoundRobin", if necessary. + std::string round_robin_policy = "RoundRobin"; + std::string single_thread = "SingleThread"; + + if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) + smtFetchPolicy = round_robin_policy; + else + smtFetchPolicy = smtFetchPolicy; + + instShiftAmt = 2; + + return new DerivO3CPU(this); +} diff --git a/src/cpu/o3/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc new file mode 100644 index 000000000..d828ef1b0 --- /dev/null +++ b/src/cpu/o3/dyn_inst.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 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: Gabe Black + */ + +#include "cpu/o3/dyn_inst_impl.hh" +#include "cpu/o3/impl.hh" + +// Force instantiation of BaseO3DynInst for all the implementations that +// are needed. +template class BaseO3DynInst; diff --git a/src/cpu/o3/dyn_inst_decl.hh b/src/cpu/o3/dyn_inst_decl.hh deleted file mode 100644 index 750c3279d..000000000 --- a/src/cpu/o3/dyn_inst_decl.hh +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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: Korey Sewell - */ - -#ifndef __CPU_O3_DYN_INST_DECL_HH__ -#define __CPU_O3_DYN_INST_DECL_HH__ - -#include "arch/isa_specific.hh" - -template class BaseO3DynInst; -#if THE_ISA == ALPHA_ISA - struct AlphaSimpleImpl; - typedef BaseO3DynInst O3DynInst; -#elif THE_ISA == MIPS_ISA - struct MipsSimpleImpl; - typedef BaseO3DynInst O3DynInst; -#elif THE_ISA == SPARC_ISA - struct SparcSimpleImpl; - typedef BaseO3DynInst O3DynInst; -#elif THE_ISA == X86_ISA - struct X86SimpleImpl; - typedef BaseO3DynInst O3DynInst; -#elif THE_ISA == ARM_ISA - struct ArmSimpleImpl; - typedef BaseO3DynInst O3DynInst; -#else - #error "O3DynInst not defined for this ISA" -#endif - -#endif // __CPU_O3_DYN_INST_DECL_HH__ diff --git a/src/cpu/o3/impl.hh b/src/cpu/o3/impl.hh new file mode 100644 index 000000000..4b29b4daa --- /dev/null +++ b/src/cpu/o3/impl.hh @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004-2005 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: Kevin Lim + */ + +#ifndef __CPU_O3_IMPL_HH__ +#define __CPU_O3_IMPL_HH__ + +#include "arch/isa_traits.hh" + +#include "cpu/o3/cpu_policy.hh" + + +// Forward declarations. +template +class BaseO3DynInst; + +template +class FullO3CPU; + +/** Implementation specific struct that defines several key types to the + * CPU, the stages within the CPU, the time buffers, and the DynInst. + * The struct defines the ISA, the CPU policy, the specific DynInst, the + * specific O3CPU, and all of the structs from the time buffers to do + * communication. + * This is one of the key things that must be defined for each hardware + * specific CPU implementation. + */ +struct O3CPUImpl +{ + /** The type of MachInst. */ + typedef TheISA::MachInst MachInst; + + /** The CPU policy to be used, which defines all of the CPU stages. */ + typedef SimpleCPUPolicy CPUPol; + + /** The DynInst type to be used. */ + typedef BaseO3DynInst DynInst; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst *. + */ + typedef RefCountingPtr DynInstPtr; + + /** The O3CPU type to be used. */ + typedef FullO3CPU O3CPU; + + /** Same typedef, but for CPUType. BaseDynInst may not always use + * an O3 CPU, so it's clearer to call it CPUType instead in that + * case. + */ + typedef O3CPU CPUType; + + enum { + MaxWidth = 8, + MaxThreads = 4 + }; +}; + +#endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 6111a5336..e9347af91 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -30,13 +30,5 @@ #include "cpu/base.hh" -#if THE_ISA == ALPHA_ISA - #include "cpu/o3/alpha/impl.hh" -#elif THE_ISA == MIPS_ISA - #include "cpu/o3/mips/impl.hh" -#elif THE_ISA == SPARC_ISA - #include "cpu/o3/sparc/impl.hh" -#else - #error "ISA-specific header files O3CPU not defined ISA" -#endif +#include "cpu/o3/impl.hh" #include "cpu/o3/dyn_inst.hh" diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc deleted file mode 100755 index bb78de0a6..000000000 --- a/src/cpu/o3/mips/cpu.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/mips/impl.hh" - -// Force instantiation of MipsO3CPU for all the implemntations that are -// needed. Consider merging this and mips_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (mips_impl.cc?). -template class FullO3CPU; diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc deleted file mode 100644 index 11942e597..000000000 --- a/src/cpu/o3/mips/cpu_builder.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include - -#include "config/full_system.hh" -#include "config/use_checker.hh" -#include "cpu/o3/cpu.hh" -#include "cpu/o3/mips/impl.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public FullO3CPU -{ - public: - DerivO3CPU(DerivO3CPUParams *p) - : FullO3CPU(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - numThreads = actual_num_threads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - smtFetchPolicy = round_robin_policy; - else - smtFetchPolicy = smtFetchPolicy; - - instShiftAmt = 2; - - return new DerivO3CPU(this); -} diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc deleted file mode 100755 index 88205afaf..000000000 --- a/src/cpu/o3/mips/dyn_inst.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/dyn_inst_impl.hh" -#include "cpu/o3/mips/impl.hh" - -// Force instantiation of MipsDynInst for all the implementations that -// are needed. -template class BaseO3DynInst; diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh deleted file mode 100644 index 78afd1387..000000000 --- a/src/cpu/o3/mips/impl.hh +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#ifndef __CPU_O3_MIPS_IMPL_HH__ -#define __CPU_O3_MIPS_IMPL_HH__ - -#include "arch/mips/isa_traits.hh" - -#include "cpu/o3/cpu_policy.hh" - -// Forward declarations. -template -class BaseO3DynInst; - -template -class FullO3CPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific O3CPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct MipsSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy CPUPol; - - /** The DynInst type to be used. */ - typedef BaseO3DynInst DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr DynInstPtr; - - /** The O3CPU type to be used. */ - typedef FullO3CPU O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef MipsSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_MIPS_IMPL_HH__ diff --git a/src/cpu/o3/mips/thread_context.cc b/src/cpu/o3/mips/thread_context.cc deleted file mode 100755 index 0061a2a63..000000000 --- a/src/cpu/o3/mips/thread_context.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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: Kevin Lim - * Korey Sewell - */ - -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" - -template class O3ThreadContext; - diff --git a/src/cpu/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc deleted file mode 100644 index 738ff0108..000000000 --- a/src/cpu/o3/sparc/cpu.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Gabe Black - */ - -#include "cpu/o3/cpu.hh" -#include "cpu/o3/sparc/impl.hh" - -// Force instantiation of SparcO3CPU for all the implementations that are -// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (sparc_impl.cc?). -template class FullO3CPU; diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc deleted file mode 100644 index c19b4871f..000000000 --- a/src/cpu/o3/sparc/cpu_builder.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#include - -#include "config/full_system.hh" -#include "config/use_checker.hh" -#include "cpu/o3/cpu.hh" -#include "cpu/o3/sparc/impl.hh" -#include "params/DerivO3CPU.hh" - -class DerivO3CPU : public FullO3CPU -{ - public: - DerivO3CPU(DerivO3CPUParams *p) - : FullO3CPU(p) - { } -}; - -DerivO3CPU * -DerivO3CPUParams::create() -{ -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - (numThreads >= workload.size()) ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } -#endif - - numThreads = actual_num_threads; - - // Default smtFetchPolicy to "RoundRobin", if necessary. - std::string round_robin_policy = "RoundRobin"; - std::string single_thread = "SingleThread"; - - if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) - smtFetchPolicy = round_robin_policy; - else - smtFetchPolicy = smtFetchPolicy; - - instShiftAmt = 2; - - return new DerivO3CPU(this); -} diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/sparc/dyn_inst.cc deleted file mode 100644 index ea86f8719..000000000 --- a/src/cpu/o3/sparc/dyn_inst.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Gabe Black - */ - -#include "cpu/o3/dyn_inst_impl.hh" -#include "cpu/o3/sparc/impl.hh" - -// Force instantiation of SparcDynInst for all the implementations that -// are needed. -template class BaseO3DynInst; diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh deleted file mode 100644 index cf0e33e42..000000000 --- a/src/cpu/o3/sparc/impl.hh +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2004-2005 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: Gabe Black - */ - -#ifndef __CPU_O3_SPARC_IMPL_HH__ -#define __CPU_O3_SPARC_IMPL_HH__ - -#include "arch/sparc/isa_traits.hh" - -#include "cpu/o3/cpu_policy.hh" - - -// Forward declarations. -template -class BaseO3DynInst; - -template -class FullO3CPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific O3CPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct SparcSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy CPUPol; - - /** The DynInst type to be used. */ - typedef BaseO3DynInst DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr DynInstPtr; - - /** The O3CPU type to be used. */ - typedef FullO3CPU O3CPU; - - /** Same typedef, but for CPUType. BaseDynInst may not always use - * an O3 CPU, so it's clearer to call it CPUType instead in that - * case. - */ - typedef O3CPU CPUType; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -/** The O3Impl to be used. */ -typedef SparcSimpleImpl O3CPUImpl; - -#endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/cpu/o3/sparc/thread_context.cc deleted file mode 100755 index d85aff502..000000000 --- a/src/cpu/o3/sparc/thread_context.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2004-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: Gabe Black - */ - -#include "cpu/o3/thread_context.hh" -#include "cpu/o3/thread_context_impl.hh" - -template class O3ThreadContext; - diff --git a/src/cpu/o3/thread_context.cc b/src/cpu/o3/thread_context.cc new file mode 100755 index 000000000..0d8c67643 --- /dev/null +++ b/src/cpu/o3/thread_context.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-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: Kevin Lim + */ + +#include "cpu/o3/thread_context.hh" +#include "cpu/o3/thread_context_impl.hh" +#include "cpu/o3/impl.hh" + +template class O3ThreadContext; + diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index 2c3c3dbc2..8a1b3e749 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -42,7 +42,6 @@ #include "base/misc.hh" #include "base/refcnt.hh" #include "cpu/op_class.hh" -#include "cpu/o3/dyn_inst_decl.hh" #include "sim/faults.hh" #include "sim/host.hh" @@ -54,6 +53,10 @@ class ThreadContext; class DynInst; class Packet; +class O3CPUImpl; +template class BaseO3DynInst; +typedef BaseO3DynInst O3DynInst; + template class OzoneDynInst; -- cgit v1.2.3 From e06321091d4e931ff1a4d753e56d76f9746c3cd2 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 9 Oct 2008 04:58:24 -0700 Subject: eventq: convert all usage of events to use the new API. For now, there is still a single global event queue, but this is necessary for making the steps towards a parallelized m5. --- src/cpu/base.cc | 76 +++++++++++++++++++++++-------------------- src/cpu/base.hh | 2 +- src/cpu/cpuevent.hh | 9 +++-- src/cpu/memtest/memtest.cc | 4 +-- src/cpu/memtest/memtest.hh | 6 ++-- src/cpu/o3/commit_impl.hh | 4 +-- src/cpu/o3/cpu.cc | 17 +++++----- src/cpu/o3/cpu.hh | 20 ++++++------ src/cpu/o3/fetch.hh | 2 +- src/cpu/o3/inst_queue_impl.hh | 9 +++-- src/cpu/o3/lsq.hh | 2 +- src/cpu/o3/lsq_unit.hh | 2 +- src/cpu/o3/lsq_unit_impl.hh | 4 +-- src/cpu/quiesce_event.cc | 2 +- src/cpu/simple/atomic.cc | 15 ++++----- src/cpu/simple/timing.cc | 16 +++++---- src/cpu/simple/timing.hh | 3 +- src/cpu/simple_thread.cc | 4 +-- src/cpu/thread_state.cc | 2 +- 19 files changed, 101 insertions(+), 98 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 7b6404419..5a0359e53 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -60,13 +60,12 @@ vector BaseCPU::cpuList; // been initialized int maxThreadsPerCPU = 1; -CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival, - BaseCPU *_cpu) - : Event(q, Event::Progress_Event_Pri), interval(ival), - lastNumInst(0), cpu(_cpu) +CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) + : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0), + cpu(_cpu) { if (interval) - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } void @@ -84,7 +83,7 @@ CPUProgressEvent::process() curTick, cpu->name(), temp - lastNumInst); #endif lastNumInst = temp; - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } const char * @@ -121,22 +120,26 @@ BaseCPU::BaseCPU(Params *p) // // set up instruction-count-based termination events, if any // - if (p->max_insts_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - schedExitSimLoop("a thread reached the max instruction count", - p->max_insts_any_thread, 0, - comInstEventQueue[i]); + if (p->max_insts_any_thread != 0) { + const char *cause = "a thread reached the max instruction count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } + } if (p->max_insts_all_threads != 0) { + const char *cause = "all threads reached the max instruction count"; + // allocate & initialize shared downcounter: each event will // decrement this when triggered; simulation will terminate // when counter reaches 0 int *counter = new int; *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comInstEventQueue[i], - "all threads reached the max instruction count", - p->max_insts_all_threads, *counter); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comInstEventQueue[i]->schedule(event, p->max_insts_any_thread); + } } // allocate per-thread load-based event queues @@ -147,22 +150,25 @@ BaseCPU::BaseCPU(Params *p) // // set up instruction-count-based termination events, if any // - if (p->max_loads_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - schedExitSimLoop("a thread reached the max load count", - p->max_loads_any_thread, 0, - comLoadEventQueue[i]); + if (p->max_loads_any_thread != 0) { + const char *cause = "a thread reached the max load count"; + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new SimLoopExitEvent(cause, 0); + comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread); + } + } if (p->max_loads_all_threads != 0) { + const char *cause = "all threads reached the max load count"; // allocate & initialize shared downcounter: each event will // decrement this when triggered; simulation will terminate // when counter reaches 0 int *counter = new int; *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comLoadEventQueue[i], - "all threads reached the max load count", - p->max_loads_all_threads, *counter); + for (int i = 0; i < number_of_threads; ++i) { + Event *event = new CountedExitEvent(cause, *counter); + comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads); + } } functionTracingEnabled = false; @@ -174,9 +180,9 @@ BaseCPU::BaseCPU(Params *p) if (p->function_trace_start == 0) { functionTracingEnabled = true; } else { - new EventWrapper( - this, p->function_trace_start, true); + typedef EventWrapper wrap; + Event *event = new wrap(this, true); + schedule(event, p->function_trace_start); } } #if FULL_SYSTEM @@ -209,13 +215,13 @@ BaseCPU::startup() { #if FULL_SYSTEM if (!params()->defer_registration && profileEvent) - profileEvent->schedule(curTick); + schedule(profileEvent, curTick); #endif if (params()->progress_interval) { - new CPUProgressEvent(&mainEventQueue, - ticks(params()->progress_interval), - this); + Tick num_ticks = ticks(params()->progress_interval); + Event *event = new CPUProgressEvent(this, num_ticks); + schedule(event, curTick + num_ticks); } } @@ -300,7 +306,7 @@ BaseCPU::switchOut() // panic("This CPU doesn't support sampling!"); #if FULL_SYSTEM if (profileEvent && profileEvent->scheduled()) - profileEvent->deschedule(); + deschedule(profileEvent); #endif } @@ -336,7 +342,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) threadContexts[i]->profileClear(); if (profileEvent) - profileEvent->schedule(curTick); + schedule(profileEvent, curTick); #endif // Connect new CPU to old CPU's memory only if new CPU isn't @@ -358,7 +364,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) #if FULL_SYSTEM BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) + : cpu(_cpu), interval(_interval) { } void @@ -369,7 +375,7 @@ BaseCPU::ProfileEvent::process() tc->profileSample(); } - schedule(curTick + interval); + cpu->schedule(this, curTick + interval); } void diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 251adc1b7..c2b78a675 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -65,7 +65,7 @@ class CPUProgressEvent : public Event BaseCPU *cpu; public: - CPUProgressEvent(EventQueue *q, Tick ival, BaseCPU *_cpu); + CPUProgressEvent(BaseCPU *_cpu, Tick ival); void process(); diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh index 5816c6ca1..65f0e87e1 100644 --- a/src/cpu/cpuevent.hh +++ b/src/cpu/cpuevent.hh @@ -58,8 +58,8 @@ class CpuEvent : public Event ThreadContext *tc; public: - CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri) - : Event(q, p), tc(_tc) + CpuEvent(ThreadContext *_tc, Priority p = Default_Pri) + : Event(p), tc(_tc) { cpuEventList.push_back(this); } /** delete the cpu event from the global list. */ @@ -81,9 +81,8 @@ class CpuEventWrapper : public CpuEvent T *object; public: - CpuEventWrapper(T *obj, ThreadContext *_tc, - EventQueue *q = &mainEventQueue, Priority p = Default_Pri) - : CpuEvent(q, _tc, p), object(obj) + CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri) + : CpuEvent(_tc, p), object(obj) { } void process() { (object->*F)(tc); } }; diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc index 42889163a..9e5b9d099 100644 --- a/src/cpu/memtest/memtest.cc +++ b/src/cpu/memtest/memtest.cc @@ -152,7 +152,7 @@ MemTest::MemTest(const Params *p) // set up counters noResponseCycles = 0; numReads = 0; - tickEvent.schedule(0); + schedule(tickEvent, 0); id = TESTER_ALLOCATOR++; @@ -262,7 +262,7 @@ void MemTest::tick() { if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + ticks(1)); + schedule(tickEvent, curTick + ticks(1)); if (++noResponseCycles >= 500000) { cerr << name() << ": deadlocked at cycle " << curTick << endl; diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index 5a7e0b9ae..82438b41f 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -74,10 +74,10 @@ class MemTest : public MemObject { private: MemTest *cpu; + public: - TickEvent(MemTest *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} - void process() {cpu->tick();} + TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {} + void process() { cpu->tick(); } virtual const char *description() const { return "MemTest tick"; } }; diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index b16955691..68fc6ef3b 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -51,7 +51,7 @@ template DefaultCommit::TrapEvent::TrapEvent(DefaultCommit *_commit, unsigned _tid) - : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) + : Event(CPU_Tick_Pri), commit(_commit), tid(_tid) { this->setFlags(Event::AutoDelete); } @@ -462,7 +462,7 @@ DefaultCommit::generateTrapEvent(unsigned tid) TrapEvent *trap = new TrapEvent(this, tid); - trap->schedule(curTick + trapLatency); + cpu->schedule(trap, curTick + trapLatency); trapInFlight[tid] = true; } diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 18b417141..eb1115565 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -74,7 +74,7 @@ BaseO3CPU::regStats() template FullO3CPU::TickEvent::TickEvent(FullO3CPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -94,7 +94,7 @@ FullO3CPU::TickEvent::description() const template FullO3CPU::ActivateThreadEvent::ActivateThreadEvent() - : Event(&mainEventQueue, CPU_Switch_Pri) + : Event(CPU_Switch_Pri) { } @@ -123,7 +123,7 @@ FullO3CPU::ActivateThreadEvent::description() const template FullO3CPU::DeallocateContextEvent::DeallocateContextEvent() - : Event(&mainEventQueue, CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) + : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL) { } @@ -576,7 +576,7 @@ FullO3CPU::tick() lastRunningCycle = curTick; timesIdled++; } else { - tickEvent.schedule(nextCycle(curTick + ticks(1))); + schedule(tickEvent, nextCycle(curTick + ticks(1))); DPRINTF(O3CPU, "Scheduling next tick!\n"); } } @@ -584,7 +584,6 @@ FullO3CPU::tick() #if !FULL_SYSTEM updateThreadPriority(); #endif - } template @@ -1121,7 +1120,7 @@ FullO3CPU::resume() #endif if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); _status = Running; } @@ -1214,11 +1213,11 @@ FullO3CPU::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } } if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } template @@ -1687,7 +1686,7 @@ FullO3CPU::wakeCPU() idleCycles += tickToCycles((curTick - 1) - lastRunningCycle); numCycles += tickToCycles((curTick - 1) - lastRunningCycle); - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); } template diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 065dd10a0..406d965be 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -148,9 +148,9 @@ class FullO3CPU : public BaseO3CPU void scheduleTickEvent(int delay) { if (tickEvent.squashed()) - tickEvent.reschedule(nextCycle(curTick + ticks(delay))); + reschedule(tickEvent, nextCycle(curTick + ticks(delay))); else if (!tickEvent.scheduled()) - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); } /** Unschedule tick event, regardless of its current state. */ @@ -188,11 +188,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (activateThreadEvent[tid].squashed()) - activateThreadEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!activateThreadEvent[tid].scheduled()) - activateThreadEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(activateThreadEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule actiavte thread event, regardless of its current state. */ @@ -246,11 +246,11 @@ class FullO3CPU : public BaseO3CPU { // Schedule thread to activate, regardless of its current state. if (deallocateContextEvent[tid].squashed()) - deallocateContextEvent[tid]. - reschedule(nextCycle(curTick + ticks(delay))); + reschedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); else if (!deallocateContextEvent[tid].scheduled()) - deallocateContextEvent[tid]. - schedule(nextCycle(curTick + ticks(delay))); + schedule(deallocateContextEvent[tid], + nextCycle(curTick + ticks(delay))); } /** Unschedule thread deallocation in CPU */ diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index f12228ff9..9886b6675 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -82,7 +82,7 @@ class DefaultFetch public: /** Default constructor. */ IcachePort(DefaultFetch *_fetch) - : Port(_fetch->name() + "-iport"), fetch(_fetch) + : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch) { } bool snoopRangeSent; diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index f3ce770fa..1d0f4b9f6 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -41,10 +41,9 @@ template InstructionQueue::FUCompletion::FUCompletion(DynInstPtr &_inst, - int fu_idx, - InstructionQueue *iq_ptr) - : Event(&mainEventQueue, Stat_Event_Pri), - inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) + int fu_idx, InstructionQueue *iq_ptr) + : Event(Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), + freeFU(false) { this->setFlags(Event::AutoDelete); } @@ -754,7 +753,7 @@ InstructionQueue::scheduleReadyInsts() FUCompletion *execution = new FUCompletion(issuing_inst, idx, this); - execution->schedule(curTick + cpu->ticks(op_latency - 1)); + cpu->schedule(execution, curTick + cpu->ticks(op_latency - 1)); // @todo: Enforce that issue_latency == 1 or op_latency if (issue_latency > 1) { diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index 44b69ab40..f8a825726 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -298,7 +298,7 @@ class LSQ { public: /** Default constructor. */ DcachePort(LSQ *_lsq) - : Port(_lsq->name() + "-dport"), lsq(_lsq) + : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq) { } bool snoopRangeSent; diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index a82ba3ad5..8af8f18e6 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -584,7 +584,7 @@ LSQUnit::read(Request *req, T &data, int load_idx) // We'll say this has a 1 cycle load-store forwarding latency // for now. // @todo: Need to make this a parameter. - wb->schedule(curTick); + cpu->schedule(wb, curTick); ++lsqForwLoads; return NoFault; diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index 4b8d693a6..85662d496 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -45,7 +45,7 @@ template LSQUnit::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt, LSQUnit *lsq_ptr) - : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) + : inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) { this->setFlags(Event::AutoDelete); } @@ -684,7 +684,7 @@ LSQUnit::writebackStores() "Instantly completing it.\n", inst->seqNum); WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this); - wb->schedule(curTick + 1); + cpu->schedule(wb, curTick + 1); completeStore(storeWBIdx); incrStIdx(storeWBIdx); continue; diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc index 81384d529..38ffb74e4 100644 --- a/src/cpu/quiesce_event.cc +++ b/src/cpu/quiesce_event.cc @@ -33,7 +33,7 @@ #include "cpu/quiesce_event.hh" EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc) - : Event(&mainEventQueue), tc(_tc) + : tc(_tc) { } diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 7ed1ee0c3..154a66162 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -43,7 +43,7 @@ using namespace std; using namespace TheISA; AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) + : Event(CPU_Tick_Pri), cpu(c) { } @@ -201,9 +201,8 @@ AtomicSimpleCPU::resume() changeState(SimObject::Running); if (thread->status() == ThreadContext::Active) { - if (!tickEvent.scheduled()) { - tickEvent.schedule(nextCycle()); - } + if (!tickEvent.scheduled()) + schedule(tickEvent, nextCycle()); } } @@ -230,7 +229,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) ThreadContext *tc = threadContexts[i]; if (tc->status() == ThreadContext::Active && _status != Running) { _status = Running; - tickEvent.schedule(nextCycle()); + schedule(tickEvent, nextCycle()); break; } } @@ -260,7 +259,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay) numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend); //Make sure ticks are still on multiples of cycles - tickEvent.schedule(nextCycle(curTick + ticks(delay))); + schedule(tickEvent, nextCycle(curTick + ticks(delay))); _status = Running; } @@ -278,7 +277,7 @@ AtomicSimpleCPU::suspendContext(int thread_num) // tick event may not be scheduled if this gets called from inside // an instruction's execution, e.g. "quiesce" if (tickEvent.scheduled()) - tickEvent.deschedule(); + deschedule(tickEvent); notIdleFraction--; _status = Idle; @@ -794,7 +793,7 @@ AtomicSimpleCPU::tick() latency = ticks(1); if (_status != Idle) - tickEvent.schedule(curTick + latency); + schedule(tickEvent, curTick + latency); } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index ac67341ff..c4635d6a3 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -101,7 +101,7 @@ void TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) { pkt = _pkt; - Event::schedule(t); + cpu->schedule(this, t); } TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) @@ -165,7 +165,7 @@ TimingSimpleCPU::resume() // Delete the old event if it existed. if (fetchEvent) { if (fetchEvent->scheduled()) - fetchEvent->deschedule(); + deschedule(fetchEvent); delete fetchEvent; } @@ -186,7 +186,7 @@ TimingSimpleCPU::switchOut() // If we've been scheduled to resume but are then told to switch out, // we'll need to cancel it. if (fetchEvent && fetchEvent->scheduled()) - fetchEvent->deschedule(); + deschedule(fetchEvent); } @@ -228,7 +228,8 @@ TimingSimpleCPU::activateContext(int thread_num, int delay) _status = Running; // kick things off by initiating the fetch of the next instruction - fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay))); + fetchEvent = new FetchEvent(this); + schedule(fetchEvent, nextCycle(curTick + ticks(delay))); } @@ -819,10 +820,11 @@ TimingSimpleCPU::DcachePort::recvRetry() } } -TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t) - : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu) +TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, + Tick t) + : pkt(_pkt), cpu(_cpu) { - schedule(t); + cpu->schedule(this, t); } void diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index e405f6a41..081051ea7 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -80,8 +80,7 @@ class TimingSimpleCPU : public BaseSimpleCPU PacketPtr pkt; TimingSimpleCPU *cpu; - TickEvent(TimingSimpleCPU *_cpu) - :Event(&mainEventQueue), cpu(_cpu) {} + TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {} const char *description() const { return "Timing CPU tick"; } void schedule(PacketPtr _pkt, Tick t); }; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 0124184e0..42da659f2 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -189,7 +189,7 @@ void SimpleThread::serialize(ostream &os) { ThreadState::serialize(os); - regs.serialize(os); + regs.serialize(cpu, os); // thread_num and cpu_id are deterministic from the config } @@ -198,7 +198,7 @@ void SimpleThread::unserialize(Checkpoint *cp, const std::string §ion) { ThreadState::unserialize(cp, section); - regs.unserialize(cp, section); + regs.unserialize(cpu, cp, section); // thread_num and cpu_id are deterministic from the config } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 18845baf7..8d519c563 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -105,7 +105,7 @@ ThreadState::unserialize(Checkpoint *cp, const std::string §ion) Tick quiesceEndTick; UNSERIALIZE_SCALAR(quiesceEndTick); if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); + baseCpu->schedule(quiesceEvent, quiesceEndTick); if (kernelStats) kernelStats->unserialize(cp, section); #endif -- cgit v1.2.3 From 94b08bed07d13106381a0bb692bf0d879c5353d4 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 9 Oct 2008 22:19:39 -0700 Subject: SimObjects: Clean up handling of C++ namespaces. Make them easier to express by only having the cxx_type parameter which has the full namespace name, and drop the cxx_namespace thing. Add support for multiple levels of namespace. --- src/cpu/ExeTracer.py | 3 +-- src/cpu/IntelTrace.py | 3 +-- src/cpu/LegionTrace.py | 3 +-- src/cpu/NativeTrace.py | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py index e904f9e7d..5754f5d5b 100644 --- a/src/cpu/ExeTracer.py +++ b/src/cpu/ExeTracer.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class ExeTracer(InstTracer): type = 'ExeTracer' - cxx_namespace = 'Trace' - cxx_class = 'ExeTracer' + cxx_class = 'Trace::ExeTracer' diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py index 6e8f567b3..3642f3174 100644 --- a/src/cpu/IntelTrace.py +++ b/src/cpu/IntelTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class IntelTrace(InstTracer): type = 'IntelTrace' - cxx_namespace = 'Trace' - cxx_class = 'IntelTrace' + cxx_class = 'Trace::IntelTrace' diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py index f9b6470a6..d450dd00e 100644 --- a/src/cpu/LegionTrace.py +++ b/src/cpu/LegionTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class LegionTrace(InstTracer): type = 'LegionTrace' - cxx_namespace = 'Trace' - cxx_class = 'LegionTrace' + cxx_class = 'Trace::LegionTrace' diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py index 96b4e991b..f410b5473 100644 --- a/src/cpu/NativeTrace.py +++ b/src/cpu/NativeTrace.py @@ -32,5 +32,4 @@ from InstTracer import InstTracer class NativeTrace(InstTracer): type = 'NativeTrace' - cxx_namespace = 'Trace' - cxx_class = 'NativeTrace' + cxx_class = 'Trace::NativeTrace' -- cgit v1.2.3 From da7209ec93f3cdad11c02906357f06fa29652996 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 11 Oct 2008 02:27:21 -0700 Subject: CPU: Eliminate the hwrei function. --- src/cpu/checker/cpu.hh | 1 - src/cpu/exec_context.hh | 4 ---- src/cpu/o3/cpu.cc | 15 --------------- src/cpu/o3/cpu.hh | 3 --- src/cpu/o3/dyn_inst.hh | 2 -- src/cpu/o3/dyn_inst_impl.hh | 22 ---------------------- src/cpu/ozone/cpu.hh | 1 - src/cpu/ozone/cpu_impl.hh | 15 --------------- src/cpu/ozone/dyn_inst.hh | 1 - src/cpu/ozone/dyn_inst_impl.hh | 15 --------------- src/cpu/simple/base.hh | 1 - src/cpu/simple_thread.hh | 2 -- 12 files changed, 82 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 5b3c4582c..b234bf23f 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -336,7 +336,6 @@ class CheckerCPU : public BaseCPU void translateDataReadReq(Request *req); #if FULL_SYSTEM - Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh index 2b9fe4bcf..93192246c 100644 --- a/src/cpu/exec_context.hh +++ b/src/cpu/exec_context.hh @@ -144,10 +144,6 @@ class ExecContext { void writeHint(Addr addr, int size, unsigned flags); #if FULL_SYSTEM - /** Somewhat Alpha-specific function that handles returning from - * an error or interrupt. */ - Fault hwrei(); - /** * Check for special simulator handling of specific PAL calls. If * return value is false, actual PAL call will be suppressed. diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index eb1115565..174f4a98d 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -905,21 +905,6 @@ FullO3CPU::post_interrupt(int int_num, int index) } } -template -Fault -FullO3CPU::hwrei(unsigned tid) -{ -#if THE_ISA == ALPHA_ISA - // Need to clear the lock flag upon returning from an interrupt. - this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); - - this->thread[tid]->kernelStats->hwrei(); - - // FIXME: XXX check for interrupts? XXX -#endif - return NoFault; -} - template bool FullO3CPU::simPalCheck(int palFunc, unsigned tid) diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 406d965be..cdc1d2e58 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -414,9 +414,6 @@ class FullO3CPU : public BaseO3CPU /** Posts an interrupt. */ void post_interrupt(int int_num, int index); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - bool simPalCheck(int palFunc, unsigned tid); /** Returns the Fault for any valid interrupt. */ diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index 292547b6b..ce59d802b 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -168,8 +168,6 @@ class BaseO3DynInst : public BaseDynInst } #if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); /** Traps to handle specified fault. */ void trap(Fault fault); bool simPalCheck(int palFunc); diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 6398a3afe..f85527f22 100644 --- a/src/cpu/o3/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -124,28 +124,6 @@ BaseO3DynInst::completeAcc(PacketPtr pkt) } #if FULL_SYSTEM -template -Fault -BaseO3DynInst::hwrei() -{ -#if THE_ISA == ALPHA_ISA - // Can only do a hwrei when in pal mode. - if (!(this->readPC() & 0x3)) - return new AlphaISA::UnimplementedOpcodeFault; - - // Set the next PC based on the value of the EXC_ADDR IPR. - this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, - this->threadNumber)); - - // Tell CPU to clear any state it needs to if a hwrei is taken. - this->cpu->hwrei(this->threadNumber); -#else - -#endif - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - template void BaseO3DynInst::trap(Fault fault) diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index c3ea33673..e95accdfd 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -510,7 +510,6 @@ class OzoneCPU : public BaseCPU void dumpInsts() { frontEnd->dumpInsts(); } #if FULL_SYSTEM - Fault hwrei(); bool simPalCheck(int palFunc); void processInterrupts(); #else diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index ceb980d4c..eb7b1a13f 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -668,21 +668,6 @@ OzoneCPU::setSyscallReturn(SyscallReturn return_value, int tid) } } #else -template -Fault -OzoneCPU::hwrei() -{ - // Need to move this to ISA code - // May also need to make this per thread - - lockFlag = false; - lockAddrList.clear(); - thread.kernelStats->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - template void OzoneCPU::processInterrupts() diff --git a/src/cpu/ozone/dyn_inst.hh b/src/cpu/ozone/dyn_inst.hh index e138cbe13..deade9397 100644 --- a/src/cpu/ozone/dyn_inst.hh +++ b/src/cpu/ozone/dyn_inst.hh @@ -240,7 +240,6 @@ class OzoneDynInst : public BaseDynInst void setMiscReg(int misc_reg, const MiscReg &val); #if FULL_SYSTEM - Fault hwrei(); void trap(Fault fault); bool simPalCheck(int palFunc); #else diff --git a/src/cpu/ozone/dyn_inst_impl.hh b/src/cpu/ozone/dyn_inst_impl.hh index 8519917f5..8fc5077a6 100644 --- a/src/cpu/ozone/dyn_inst_impl.hh +++ b/src/cpu/ozone/dyn_inst_impl.hh @@ -248,21 +248,6 @@ OzoneDynInst::setMiscReg(int misc_reg, const MiscReg &val) #if FULL_SYSTEM -template -Fault -OzoneDynInst::hwrei() -{ - if (!(this->readPC() & 0x3)) - return new AlphaISA::UnimplementedOpcodeFault; - - this->setNextPC(this->thread->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR)); - - this->cpu->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - template void OzoneDynInst::trap(Fault fault) diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index b7fcf1708..b28a690bb 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -413,7 +413,6 @@ class BaseSimpleCPU : public BaseCPU //Fault CacheOp(uint8_t Op, Addr EA); #if FULL_SYSTEM - Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 377bfcd79..89d5ba99f 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -185,8 +185,6 @@ class SimpleThread : public ThreadState void dumpFuncProfile(); - Fault hwrei(); - bool simPalCheck(int palFunc); #endif -- cgit v1.2.3 From f621b7b81f0913612381d5dc4993f52bb2116902 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 11 Oct 2008 12:17:24 -0700 Subject: CPU: Eliminate the simPalCheck funciton. --- src/cpu/checker/cpu.hh | 1 - src/cpu/exec_context.hh | 8 +------- src/cpu/o3/cpu.cc | 30 ------------------------------ src/cpu/o3/cpu.hh | 2 -- src/cpu/o3/dyn_inst.hh | 1 - src/cpu/o3/dyn_inst_impl.hh | 10 ---------- src/cpu/ozone/cpu.hh | 1 - src/cpu/ozone/cpu_impl.hh | 25 ------------------------- src/cpu/ozone/dyn_inst.hh | 1 - src/cpu/ozone/dyn_inst_impl.hh | 7 ------- src/cpu/simple/base.hh | 1 - src/cpu/simple_thread.hh | 2 -- 12 files changed, 1 insertion(+), 88 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index b234bf23f..0f01f17c5 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -337,7 +337,6 @@ class CheckerCPU : public BaseCPU #if FULL_SYSTEM void ev5_trap(Fault fault) { fault->invoke(tc); } - bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else // Assume that the normal CPU's call to syscall was successful. // The checker's state would have already been updated by the syscall. diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh index 93192246c..836cf4352 100644 --- a/src/cpu/exec_context.hh +++ b/src/cpu/exec_context.hh @@ -143,13 +143,7 @@ class ExecContext { * given flags. */ void writeHint(Addr addr, int size, unsigned flags); -#if FULL_SYSTEM - /** - * Check for special simulator handling of specific PAL calls. If - * return value is false, actual PAL call will be suppressed. - */ - bool simPalCheck(int palFunc); -#else +#if !FULL_SYSTEM /** Executes a syscall specified by the callnum. */ void syscall(int64_t callnum); #endif diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 174f4a98d..ac816fc18 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -53,10 +53,6 @@ #include "cpu/checker/cpu.hh" #endif -#if THE_ISA == ALPHA_ISA -#include "arch/alpha/osfpal.hh" -#endif - class BaseCPUParams; using namespace TheISA; @@ -905,32 +901,6 @@ FullO3CPU::post_interrupt(int int_num, int index) } } -template -bool -FullO3CPU::simPalCheck(int palFunc, unsigned tid) -{ -#if THE_ISA == ALPHA_ISA - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->threadContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - exitSimLoop("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } -#endif - return true; -} - template Fault FullO3CPU::getInterrupts() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index cdc1d2e58..07ba8d701 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -414,8 +414,6 @@ class FullO3CPU : public BaseO3CPU /** Posts an interrupt. */ void post_interrupt(int int_num, int index); - bool simPalCheck(int palFunc, unsigned tid); - /** Returns the Fault for any valid interrupt. */ Fault getInterrupts(); diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index ce59d802b..28dd60f5f 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -170,7 +170,6 @@ class BaseO3DynInst : public BaseDynInst #if FULL_SYSTEM /** Traps to handle specified fault. */ void trap(Fault fault); - bool simPalCheck(int palFunc); #else /** Calls a syscall. */ void syscall(int64_t callnum); diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index f85527f22..3b713ea8f 100644 --- a/src/cpu/o3/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -130,16 +130,6 @@ BaseO3DynInst::trap(Fault fault) { this->cpu->trap(fault, this->threadNumber); } - -template -bool -BaseO3DynInst::simPalCheck(int palFunc) -{ -#if THE_ISA != ALPHA_ISA - panic("simPalCheck called, but PAL only exists in Alpha!\n"); -#endif - return this->cpu->simPalCheck(palFunc, this->threadNumber); -} #else template void diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index e95accdfd..aeafb603a 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -510,7 +510,6 @@ class OzoneCPU : public BaseCPU void dumpInsts() { frontEnd->dumpInsts(); } #if FULL_SYSTEM - bool simPalCheck(int palFunc); void processInterrupts(); #else void syscall(uint64_t &callnum); diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index eb7b1a13f..9c0b95a1a 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -685,31 +685,6 @@ OzoneCPU::processInterrupts() interrupt->invoke(thread.getTC()); } } - -template -bool -OzoneCPU::simPalCheck(int palFunc) -{ - // Need to move this to ISA code - // May also need to make this per thread - thread.kernelStats->callpal(palFunc, tc); - - switch (palFunc) { - case PAL::halt: - haltContext(thread.readTid()); - if (--System::numSystemsRunning == 0) - exitSimLoop("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (system->breakpoint()) - return false; - break; - } - - return true; -} #endif template diff --git a/src/cpu/ozone/dyn_inst.hh b/src/cpu/ozone/dyn_inst.hh index deade9397..12a19e70d 100644 --- a/src/cpu/ozone/dyn_inst.hh +++ b/src/cpu/ozone/dyn_inst.hh @@ -241,7 +241,6 @@ class OzoneDynInst : public BaseDynInst #if FULL_SYSTEM void trap(Fault fault); - bool simPalCheck(int palFunc); #else void syscall(uint64_t &callnum); #endif diff --git a/src/cpu/ozone/dyn_inst_impl.hh b/src/cpu/ozone/dyn_inst_impl.hh index 8fc5077a6..396007687 100644 --- a/src/cpu/ozone/dyn_inst_impl.hh +++ b/src/cpu/ozone/dyn_inst_impl.hh @@ -254,13 +254,6 @@ OzoneDynInst::trap(Fault fault) { fault->invoke(this->thread->getTC()); } - -template -bool -OzoneDynInst::simPalCheck(int palFunc) -{ - return this->cpu->simPalCheck(palFunc); -} #else template void diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index b28a690bb..03c20a6f2 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -414,7 +414,6 @@ class BaseSimpleCPU : public BaseCPU #if FULL_SYSTEM void ev5_trap(Fault fault) { fault->invoke(tc); } - bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else void syscall(int64_t callnum) { thread->syscall(callnum); } #endif diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 89d5ba99f..69d7b2548 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -185,8 +185,6 @@ class SimpleThread : public ThreadState void dumpFuncProfile(); - bool simPalCheck(int palFunc); - #endif /******************************************* -- cgit v1.2.3 From 0c3848732ee33cf14a80129f6cf7ee84d51c8bfb Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 11 Oct 2008 16:13:58 -0700 Subject: CPU: Add a getInterruptController function --- src/cpu/base.hh | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/base.hh b/src/cpu/base.hh index c2b78a675..7b7ad9be0 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -110,6 +110,12 @@ class BaseCPU : public MemObject TheISA::Interrupts interrupts; public: + TheISA::Interrupts * + getInterruptController() + { + return &interrupts; + } + virtual void post_interrupt(int int_num, int index); virtual void clear_interrupt(int int_num, int index); virtual void clear_interrupts(); -- cgit v1.2.3 From c4f1cc3b482311f878be44259125c9a5b90c0569 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 08:24:09 -0700 Subject: CPU: Eliminate the get_vec function. --- src/cpu/base.cc | 6 ------ src/cpu/base.hh | 1 - 2 files changed, 7 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 5a0359e53..1ca0dc14b 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -396,12 +396,6 @@ BaseCPU::clear_interrupts() interrupts.clear_all(); } -uint64_t -BaseCPU::get_interrupts(int int_num) -{ - return interrupts.get_vec(int_num); -} - void BaseCPU::serialize(std::ostream &os) { diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 7b7ad9be0..c99efa834 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -119,7 +119,6 @@ class BaseCPU : public MemObject virtual void post_interrupt(int int_num, int index); virtual void clear_interrupt(int int_num, int index); virtual void clear_interrupts(); - virtual uint64_t get_interrupts(int int_num); bool check_interrupts(ThreadContext * tc) const { return interrupts.check_interrupts(tc); } -- cgit v1.2.3 From d9f9c967fbe651e09d444e460a9b1c5a450b1cd2 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 09:09:56 -0700 Subject: Turn Interrupts objects into SimObjects. Also, move local APIC state into x86's Interrupts object. --- src/cpu/BaseCPU.py | 25 +++++++++++++++++++++++++ src/cpu/base.cc | 12 ++++++------ src/cpu/base.hh | 6 +++--- src/cpu/o3/cpu.cc | 4 ++-- src/cpu/ozone/cpu_impl.hh | 4 ++-- src/cpu/simple/base.cc | 4 ++-- 6 files changed, 40 insertions(+), 15 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 1e3f0dbbc..c2385f6d0 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -39,14 +39,24 @@ default_tracer = ExeTracer() if build_env['TARGET_ISA'] == 'alpha': from AlphaTLB import AlphaDTB, AlphaITB + if build_env['FULL_SYSTEM']: + from AlphaInterrupts import AlphaInterrupts elif build_env['TARGET_ISA'] == 'sparc': from SparcTLB import SparcDTB, SparcITB + if build_env['FULL_SYSTEM']: + from SparcInterrupts import SparcInterrupts elif build_env['TARGET_ISA'] == 'x86': from X86TLB import X86DTB, X86ITB + if build_env['FULL_SYSTEM']: + from X86LocalApic import X86LocalApic elif build_env['TARGET_ISA'] == 'mips': from MipsTLB import MipsTLB,MipsDTB, MipsITB, MipsUTB + if build_env['FULL_SYSTEM']: + from MipsInterrupts import MipsInterrupts elif build_env['TARGET_ISA'] == 'arm': from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB + if build_env['FULL_SYSTEM']: + from ArmInterrupts import ArmInterrupts class BaseCPU(MemObject): type = 'BaseCPU' @@ -74,22 +84,37 @@ class BaseCPU(MemObject): if build_env['TARGET_ISA'] == 'sparc': dtb = Param.SparcDTB(SparcDTB(), "Data TLB") itb = Param.SparcITB(SparcITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.SparcInterrupts( + SparcInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'alpha': dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB") itb = Param.AlphaITB(AlphaITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.AlphaInterrupts( + AlphaInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'x86': dtb = Param.X86DTB(X86DTB(), "Data TLB") itb = Param.X86ITB(X86ITB(), "Instruction TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.X86LocalApic( + X86LocalApic(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'mips': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.MipsDTB(MipsDTB(), "Data TLB") itb = Param.MipsITB(MipsITB(), "Instruction TLB") tlb = Param.MipsUTB(MipsUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.MipsInterrupts( + MipsInterrupts(), "Interrupt Controller") elif build_env['TARGET_ISA'] == 'arm': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.ArmDTB(ArmDTB(), "Data TLB") itb = Param.ArmITB(ArmITB(), "Instruction TLB") tlb = Param.ArmUTB(ArmUTB(), "Unified TLB") + if build_env['FULL_SYSTEM']: + interrupts = Param.ArmInterrupts( + ArmInterrupts(), "Interrupt Controller") else: print "Don't know what TLB to use for ISA %s" % \ build_env['TARGET_ISA'] diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 1ca0dc14b..def1e9920 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -94,7 +94,7 @@ CPUProgressEvent::description() const #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(p), clock(p->clock), instCnt(0), + : MemObject(p), clock(p->clock), instCnt(0), interrupts(p->interrupts), number_of_threads(p->numThreads), system(p->system), phase(p->phase) #else @@ -381,33 +381,33 @@ BaseCPU::ProfileEvent::process() void BaseCPU::post_interrupt(int int_num, int index) { - interrupts.post(int_num, index); + interrupts->post(int_num, index); } void BaseCPU::clear_interrupt(int int_num, int index) { - interrupts.clear(int_num, index); + interrupts->clear(int_num, index); } void BaseCPU::clear_interrupts() { - interrupts.clear_all(); + interrupts->clear_all(); } void BaseCPU::serialize(std::ostream &os) { SERIALIZE_SCALAR(instCnt); - interrupts.serialize(os); + interrupts->serialize(os); } void BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(instCnt); - interrupts.unserialize(cp, section); + interrupts->unserialize(cp, section); } #endif // FULL_SYSTEM diff --git a/src/cpu/base.hh b/src/cpu/base.hh index c99efa834..a12c98ab0 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -107,13 +107,13 @@ class BaseCPU : public MemObject protected: // uint64_t interrupts[TheISA::NumInterruptLevels]; // uint64_t intstatus; - TheISA::Interrupts interrupts; + TheISA::Interrupts * interrupts; public: TheISA::Interrupts * getInterruptController() { - return &interrupts; + return interrupts; } virtual void post_interrupt(int int_num, int index); @@ -121,7 +121,7 @@ class BaseCPU : public MemObject virtual void clear_interrupts(); bool check_interrupts(ThreadContext * tc) const - { return interrupts.check_interrupts(tc); } + { return interrupts->check_interrupts(tc); } class ProfileEvent : public Event { diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index ac816fc18..c110bbd50 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -906,7 +906,7 @@ Fault FullO3CPU::getInterrupts() { // Check if there are any outstanding interrupts - return this->interrupts.getInterrupt(this->threadContexts[0]); + return this->interrupts->getInterrupt(this->threadContexts[0]); } template @@ -920,7 +920,7 @@ FullO3CPU::processInterrupts(Fault interrupt) // @todo: Allow other threads to handle interrupts. assert(interrupt != NoFault); - this->interrupts.updateIntrInfo(this->threadContexts[0]); + this->interrupts->updateIntrInfo(this->threadContexts[0]); DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); this->trap(interrupt, 0); diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 9c0b95a1a..94af07525 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -678,10 +678,10 @@ OzoneCPU::processInterrupts() // Check if there are any outstanding interrupts //Handle the interrupts - Fault interrupt = this->interrupts.getInterrupt(thread.getTC()); + Fault interrupt = this->interrupts->getInterrupt(thread.getTC()); if (interrupt != NoFault) { - this->interrupts.updateIntrInfo(thread.getTC()); + this->interrupts->updateIntrInfo(thread.getTC()); interrupt->invoke(thread.getTC()); } } diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 3fd699868..48e5db347 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -319,10 +319,10 @@ BaseSimpleCPU::checkForInterrupts() { #if FULL_SYSTEM if (check_interrupts(tc)) { - Fault interrupt = interrupts.getInterrupt(tc); + Fault interrupt = interrupts->getInterrupt(tc); if (interrupt != NoFault) { - interrupts.updateIntrInfo(tc); + interrupts->updateIntrInfo(tc); interrupt->invoke(tc); } } -- cgit v1.2.3 From 42ebebf99a7d6ce2358b152f643b52c7946f9202 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 11:08:00 -0700 Subject: X86: Make the local APIC accessible through the memory system directly, and make the timer work. --- src/cpu/BaseCPU.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index c2385f6d0..78b9ae944 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -97,8 +97,9 @@ class BaseCPU(MemObject): dtb = Param.X86DTB(X86DTB(), "Data TLB") itb = Param.X86ITB(X86ITB(), "Instruction TLB") if build_env['FULL_SYSTEM']: - interrupts = Param.X86LocalApic( - X86LocalApic(), "Interrupt Controller") + _localApic = X86LocalApic(pio_addr=0xa000000000000000) + interrupts = \ + Param.X86LocalApic(_localApic, "Interrupt Controller") elif build_env['TARGET_ISA'] == 'mips': UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") dtb = Param.MipsDTB(MipsDTB(), "Data TLB") @@ -141,7 +142,9 @@ class BaseCPU(MemObject): _mem_ports = [] if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']: - _mem_ports = ["itb.walker.port", "dtb.walker.port"] + _mem_ports = ["itb.walker.port", + "dtb.walker.port", + "interrupts.pio"] def connectMemPorts(self, bus): for p in self._mem_ports: -- cgit v1.2.3 From 557bde43c331024eb5cecf4093a24a5b7a9cc266 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 13:28:54 -0700 Subject: X86: Make APICs communicate through the memory system. --- src/cpu/BaseCPU.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 78b9ae944..51d447f0b 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -144,7 +144,8 @@ class BaseCPU(MemObject): if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']: _mem_ports = ["itb.walker.port", "dtb.walker.port", - "interrupts.pio"] + "interrupts.pio", + "interrupts.int_port"] def connectMemPorts(self, bus): for p in self._mem_ports: -- cgit v1.2.3 From d0a43ce2b29da1640248a756dcd07f0f28561df0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 14:01:06 -0700 Subject: X86: Fix the ordering of special physical address ranges. --- src/cpu/BaseCPU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 51d447f0b..ef9b54f3f 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -97,7 +97,7 @@ class BaseCPU(MemObject): dtb = Param.X86DTB(X86DTB(), "Data TLB") itb = Param.X86ITB(X86ITB(), "Instruction TLB") if build_env['FULL_SYSTEM']: - _localApic = X86LocalApic(pio_addr=0xa000000000000000) + _localApic = X86LocalApic(pio_addr=0x2000000000000000) interrupts = \ Param.X86LocalApic(_localApic, "Interrupt Controller") elif build_env['TARGET_ISA'] == 'mips': -- cgit v1.2.3 From 2736086d7c67a24d9eb87827a22a2b352e342ba2 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 15:59:21 -0700 Subject: CPU: Create a microcode ROM object in the CPU which is defined by the ISA. --- src/cpu/base.hh | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/base.hh b/src/cpu/base.hh index a12c98ab0..b0eece2a1 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -35,6 +35,7 @@ #include #include "arch/isa_traits.hh" +#include "arch/microcode_rom.hh" #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" @@ -103,6 +104,8 @@ class BaseCPU : public MemObject */ Tick nextCycle(Tick begin_tick); + TheISA::MicrocodeRom microcodeRom; + #if FULL_SYSTEM protected: // uint64_t interrupts[TheISA::NumInterruptLevels]; -- cgit v1.2.3 From c9ea0b73492bf116c836c54199898f29d9664bc0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 16:59:55 -0700 Subject: CPU: Make the highest order bit in the micro pc determine if it's combinational or from the ROM. --- src/cpu/simple/base.cc | 29 ++++++++++++++++------------- src/cpu/static_inst.hh | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 48e5db347..d207bda14 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -368,9 +368,13 @@ BaseSimpleCPU::preExecute() // decode the instruction inst = gtoh(inst); - //If we're not in the middle of a macro instruction - if (!curMacroStaticInst) { + MicroPC upc = thread->readMicroPC(); + if (isRomMicroPC(upc)) { + stayAtPC = false; + curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst); + } else if (!curMacroStaticInst) { + //We're not in the middle of a macro instruction StaticInstPtr instPtr = NULL; //Predecode, ie bundle up an ExtMachInst @@ -401,15 +405,13 @@ BaseSimpleCPU::preExecute() //out micro ops if (instPtr && instPtr->isMacroop()) { curMacroStaticInst = instPtr; - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } else { curStaticInst = instPtr; } } else { //Read the next micro op from the macro op - curStaticInst = curMacroStaticInst-> - fetchMicroop(thread->readMicroPC()); + curStaticInst = curMacroStaticInst->fetchMicroop(upc); } //If we decoded an instruction this "tick", record information about it. @@ -469,22 +471,23 @@ BaseSimpleCPU::advancePC(Fault fault) if (fault != NoFault) { curMacroStaticInst = StaticInst::nullStaticInstPtr; predecoder.reset(); - thread->setMicroPC(0); - thread->setNextMicroPC(1); + thread->setMicroPC(normalMicroPC(0)); + thread->setNextMicroPC(normalMicroPC(1)); fault->invoke(tc); } else { //If we're at the last micro op for this instruction if (curStaticInst && curStaticInst->isLastMicroop()) { - //We should be working with a macro op - assert(curMacroStaticInst); + //We should be working with a macro op or be in the ROM + assert(curMacroStaticInst || + isRomMicroPC(thread->readMicroPC())); //Close out this macro op, and clean up the //microcode state curMacroStaticInst = StaticInst::nullStaticInstPtr; - thread->setMicroPC(0); - thread->setNextMicroPC(1); + thread->setMicroPC(normalMicroPC(0)); + thread->setNextMicroPC(normalMicroPC(1)); } //If we're still in a macro op - if (curMacroStaticInst) { + if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) { //Advance the micro pc thread->setMicroPC(thread->readNextMicroPC()); //Advance the "next" micro pc. Note that there are no delay diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index 8a1b3e749..c9eb6ff24 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -74,6 +74,26 @@ namespace Trace { typedef uint32_t MicroPC; +static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1); + +static inline MicroPC +romMicroPC(MicroPC upc) +{ + return upc | MicroPCRomBit; +} + +static inline MicroPC +normalMicroPC(MicroPC upc) +{ + return upc & ~MicroPCRomBit; +} + +static inline bool +isRomMicroPC(MicroPC upc) +{ + return MicroPCRomBit & upc; +} + /** * Base, ISA-independent static instruction class. * -- cgit v1.2.3 From f245358343fb26ac976d15b8f2a023caa0f9ba0d Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 17:57:46 -0700 Subject: Get rid of old RegContext code. --- src/cpu/checker/thread_context.hh | 6 ------ src/cpu/o3/thread_context.hh | 9 --------- src/cpu/ozone/cpu.hh | 3 --- src/cpu/simple_thread.hh | 6 ------ src/cpu/thread_context.hh | 9 --------- 5 files changed, 33 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 4ede74c64..75ac959db 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -294,12 +294,6 @@ class CheckerThreadContext : public ThreadContext Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - checkerTC->changeRegFileContext(param, val); - } }; #endif // __CPU_CHECKER_EXEC_CONTEXT_HH__ diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index d92f85317..c529b002b 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -281,15 +281,6 @@ class O3ThreadContext : public ThreadContext this->cpu->setNextNPC(val, this->thread->readTid()); } - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { -#if THE_ISA != SPARC_ISA - panic("changeRegFileContext not implemented."); -#endif - } - - /** This function exits the thread context in the CPU and returns * 1 if the CPU has no more active threads (meaning it's OK to exit); * Used in syscall-emulation mode when a thread executes the 'exit' diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index aeafb603a..ee5e9e668 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -271,9 +271,6 @@ class OzoneCPU : public BaseCPU void setFuncExeInst(Counter new_val) { thread->funcExeInst = new_val; } #endif - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { panic("Not supported on Alpha!"); } }; // Ozone specific thread context diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 69d7b2548..d26e984a3 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -405,12 +405,6 @@ class SimpleThread : public ThreadState process->syscall(callnum, tc); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - regs.changeContext(param, val); - } }; diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 9dffbd8c6..2b9f41b70 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -272,9 +272,6 @@ class ThreadContext virtual int exit() { return 1; }; #endif - virtual void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) = 0; - /** function to compare two thread contexts (for debugging) */ static void compare(ThreadContext *one, ThreadContext *two); }; @@ -467,12 +464,6 @@ class ProxyThreadContext : public ThreadContext Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif - - void changeRegFileContext(TheISA::RegContextParam param, - TheISA::RegContextVal val) - { - actualTC->changeRegFileContext(param, val); - } }; #endif -- cgit v1.2.3 From 0756dbb37a432b895b019e49862fcd7f42e1bd00 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 19:32:06 -0700 Subject: X86: Don't fetch in the simple CPU if you're in the ROM. --- src/cpu/simple/atomic.cc | 40 +++++++++++++++++++--------------- src/cpu/simple/timing.cc | 56 +++++++++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 39 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 154a66162..878f69f0c 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -718,31 +718,37 @@ AtomicSimpleCPU::tick() checkPcEventQueue(); - Fault fault = setupFetchRequest(&ifetch_req); + Fault fault = NoFault; + + bool fromRom = isRomMicroPC(thread->readMicroPC()); + if (!fromRom) + fault = setupFetchRequest(&ifetch_req); if (fault == NoFault) { Tick icache_latency = 0; bool icache_access = false; dcache_access = false; // assume no dcache access - //Fetch more instruction memory if necessary - //if(predecoder.needMoreBytes()) - //{ - icache_access = true; - Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, - Packet::Broadcast); - ifetch_pkt.dataStatic(&inst); - - if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) - icache_latency = physmemPort.sendAtomic(&ifetch_pkt); - else - icache_latency = icachePort.sendAtomic(&ifetch_pkt); + if (!fromRom) { + //Fetch more instruction memory if necessary + //if(predecoder.needMoreBytes()) + //{ + icache_access = true; + Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, + Packet::Broadcast); + ifetch_pkt.dataStatic(&inst); + + if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) + icache_latency = physmemPort.sendAtomic(&ifetch_pkt); + else + icache_latency = icachePort.sendAtomic(&ifetch_pkt); - assert(!ifetch_pkt.isError()); + assert(!ifetch_pkt.isError()); - // ifetch_req is initialized to read the instruction directly - // into the CPU object's inst field. - //} + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + //} + } preExecute(); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index c4635d6a3..0cda9a0a3 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -531,28 +531,35 @@ TimingSimpleCPU::fetch() checkPcEventQueue(); - Request *ifetch_req = new Request(); - ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); - Fault fault = setupFetchRequest(ifetch_req); + bool fromRom = isRomMicroPC(thread->readMicroPC()); - ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); - ifetch_pkt->dataStatic(&inst); + if (!fromRom) { + Request *ifetch_req = new Request(); + ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); + Fault fault = setupFetchRequest(ifetch_req); - if (fault == NoFault) { - if (!icachePort.sendTiming(ifetch_pkt)) { - // Need to wait for retry - _status = IcacheRetry; + ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + + if (fault == NoFault) { + if (!icachePort.sendTiming(ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; + } } else { - // Need to wait for cache to respond - _status = IcacheWaitResponse; - // ownership of packet transferred to memory system - ifetch_pkt = NULL; + delete ifetch_req; + delete ifetch_pkt; + // fetch fault: advance directly to next instruction (fault handler) + advanceInst(fault); } } else { - delete ifetch_req; - delete ifetch_pkt; - // fetch fault: advance directly to next instruction (fault handler) - advanceInst(fault); + _status = IcacheWaitResponse; + completeIfetch(NULL); } numCycles += tickToCycles(curTick - previousTick); @@ -581,7 +588,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) // received a response from the icache: execute the received // instruction - assert(!pkt->isError()); + + assert(!pkt || !pkt->isError()); assert(_status == IcacheWaitResponse); _status = Running; @@ -590,8 +598,10 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) previousTick = curTick; if (getState() == SimObject::Draining) { - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } completeDrain(); return; @@ -658,8 +668,10 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) advanceInst(fault); } - delete pkt->req; - delete pkt; + if (pkt) { + delete pkt->req; + delete pkt; + } } void -- cgit v1.2.3 From 989fa4fc0fa95906f2986deec99cfb8e6e49cc1a Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 20:48:24 -0700 Subject: X86: Make the MicroPC type 16 bit. --- src/cpu/static_inst.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index c9eb6ff24..032a304ad 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -72,7 +72,7 @@ namespace Trace { class InstRecord; } -typedef uint32_t MicroPC; +typedef uint16_t MicroPC; static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1); -- cgit v1.2.3 From 809f6cb6d1c199563664305fe3b0b286c54dbea7 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 23:52:02 -0700 Subject: CPU: Explain why some code is commented out. --- src/cpu/simple/atomic.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 878f69f0c..30f4a5c5e 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -730,6 +730,10 @@ AtomicSimpleCPU::tick() dcache_access = false; // assume no dcache access if (!fromRom) { + // 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 + // this code should be uncommented. //Fetch more instruction memory if necessary //if(predecoder.needMoreBytes()) //{ -- cgit v1.2.3 From b760b99f4d9f5469d88c67ae8a06e5f9543a43e7 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Mon, 20 Oct 2008 16:22:59 -0400 Subject: O3CPU: Undo Gabe's changes to remove hwrei and simpalcheck from O3 CPU. Removing hwrei causes the instruction after the hwrei to be fetched before the ITB/DTB_CM register is updated in a call pal call sys and thus the translation fails because the user is attempting to access a super page address. Minimally, it seems as though some sort of fetch stall or refetch after a hwrei is required. I think this works currently because the hwrei uses the exec context interface, and the o3 stalls when that occurs. Additionally, these changes don't update the LOCK register and probably break ll/sc. Both o3 changes were removed since a great deal of manual patching would be required to only remove the hwrei change. --- src/cpu/checker/cpu.hh | 2 ++ src/cpu/exec_context.hh | 12 ++++++++++- src/cpu/o3/cpu.cc | 45 ++++++++++++++++++++++++++++++++++++++++++ src/cpu/o3/cpu.hh | 5 +++++ src/cpu/o3/dyn_inst.hh | 3 +++ src/cpu/o3/dyn_inst_impl.hh | 32 ++++++++++++++++++++++++++++++ src/cpu/ozone/cpu.hh | 2 ++ src/cpu/ozone/cpu_impl.hh | 40 +++++++++++++++++++++++++++++++++++++ src/cpu/ozone/dyn_inst.hh | 2 ++ src/cpu/ozone/dyn_inst_impl.hh | 22 +++++++++++++++++++++ src/cpu/simple/base.hh | 2 ++ src/cpu/simple_thread.hh | 4 ++++ 12 files changed, 170 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 0f01f17c5..5b3c4582c 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -336,7 +336,9 @@ class CheckerCPU : public BaseCPU void translateDataReadReq(Request *req); #if FULL_SYSTEM + Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } + bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else // Assume that the normal CPU's call to syscall was successful. // The checker's state would have already been updated by the syscall. diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh index 836cf4352..2b9fe4bcf 100644 --- a/src/cpu/exec_context.hh +++ b/src/cpu/exec_context.hh @@ -143,7 +143,17 @@ class ExecContext { * given flags. */ void writeHint(Addr addr, int size, unsigned flags); -#if !FULL_SYSTEM +#if FULL_SYSTEM + /** Somewhat Alpha-specific function that handles returning from + * an error or interrupt. */ + Fault hwrei(); + + /** + * Check for special simulator handling of specific PAL calls. If + * return value is false, actual PAL call will be suppressed. + */ + bool simPalCheck(int palFunc); +#else /** Executes a syscall specified by the callnum. */ void syscall(int64_t callnum); #endif diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index c110bbd50..41b7e8b14 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -53,6 +53,10 @@ #include "cpu/checker/cpu.hh" #endif +#if THE_ISA == ALPHA_ISA +#include "arch/alpha/osfpal.hh" +#endif + class BaseCPUParams; using namespace TheISA; @@ -901,6 +905,47 @@ FullO3CPU::post_interrupt(int int_num, int index) } } +template +Fault +FullO3CPU::hwrei(unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + // Need to clear the lock flag upon returning from an interrupt. + this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid); + + this->thread[tid]->kernelStats->hwrei(); + + // FIXME: XXX check for interrupts? XXX +#endif + return NoFault; +} + +template +bool +FullO3CPU::simPalCheck(int palFunc, unsigned tid) +{ +#if THE_ISA == ALPHA_ISA + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->threadContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } +#endif + return true; +} + template Fault FullO3CPU::getInterrupts() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 07ba8d701..406d965be 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -414,6 +414,11 @@ class FullO3CPU : public BaseO3CPU /** Posts an interrupt. */ void post_interrupt(int int_num, int index); + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + /** Returns the Fault for any valid interrupt. */ Fault getInterrupts(); diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index 28dd60f5f..292547b6b 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -168,8 +168,11 @@ class BaseO3DynInst : public BaseDynInst } #if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); /** Traps to handle specified fault. */ void trap(Fault fault); + bool simPalCheck(int palFunc); #else /** Calls a syscall. */ void syscall(int64_t callnum); diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 3b713ea8f..6398a3afe 100644 --- a/src/cpu/o3/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -124,12 +124,44 @@ BaseO3DynInst::completeAcc(PacketPtr pkt) } #if FULL_SYSTEM +template +Fault +BaseO3DynInst::hwrei() +{ +#if THE_ISA == ALPHA_ISA + // Can only do a hwrei when in pal mode. + if (!(this->readPC() & 0x3)) + return new AlphaISA::UnimplementedOpcodeFault; + + // Set the next PC based on the value of the EXC_ADDR IPR. + this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, + this->threadNumber)); + + // Tell CPU to clear any state it needs to if a hwrei is taken. + this->cpu->hwrei(this->threadNumber); +#else + +#endif + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + template void BaseO3DynInst::trap(Fault fault) { this->cpu->trap(fault, this->threadNumber); } + +template +bool +BaseO3DynInst::simPalCheck(int palFunc) +{ +#if THE_ISA != ALPHA_ISA + panic("simPalCheck called, but PAL only exists in Alpha!\n"); +#endif + return this->cpu->simPalCheck(palFunc, this->threadNumber); +} #else template void diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index ee5e9e668..845cbbd95 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -507,6 +507,8 @@ class OzoneCPU : public BaseCPU void dumpInsts() { frontEnd->dumpInsts(); } #if FULL_SYSTEM + Fault hwrei(); + bool simPalCheck(int palFunc); void processInterrupts(); #else void syscall(uint64_t &callnum); diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 94af07525..c8e0dfe3d 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -668,6 +668,21 @@ OzoneCPU::setSyscallReturn(SyscallReturn return_value, int tid) } } #else +template +Fault +OzoneCPU::hwrei() +{ + // Need to move this to ISA code + // May also need to make this per thread + + lockFlag = false; + lockAddrList.clear(); + thread.kernelStats->hwrei(); + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + template void OzoneCPU::processInterrupts() @@ -685,6 +700,31 @@ OzoneCPU::processInterrupts() interrupt->invoke(thread.getTC()); } } + +template +bool +OzoneCPU::simPalCheck(int palFunc) +{ + // Need to move this to ISA code + // May also need to make this per thread + thread.kernelStats->callpal(palFunc, tc); + + switch (palFunc) { + case PAL::halt: + haltContext(thread.readTid()); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (system->breakpoint()) + return false; + break; + } + + return true; +} #endif template diff --git a/src/cpu/ozone/dyn_inst.hh b/src/cpu/ozone/dyn_inst.hh index 12a19e70d..e138cbe13 100644 --- a/src/cpu/ozone/dyn_inst.hh +++ b/src/cpu/ozone/dyn_inst.hh @@ -240,7 +240,9 @@ class OzoneDynInst : public BaseDynInst void setMiscReg(int misc_reg, const MiscReg &val); #if FULL_SYSTEM + Fault hwrei(); void trap(Fault fault); + bool simPalCheck(int palFunc); #else void syscall(uint64_t &callnum); #endif diff --git a/src/cpu/ozone/dyn_inst_impl.hh b/src/cpu/ozone/dyn_inst_impl.hh index 396007687..8519917f5 100644 --- a/src/cpu/ozone/dyn_inst_impl.hh +++ b/src/cpu/ozone/dyn_inst_impl.hh @@ -248,12 +248,34 @@ OzoneDynInst::setMiscReg(int misc_reg, const MiscReg &val) #if FULL_SYSTEM +template +Fault +OzoneDynInst::hwrei() +{ + if (!(this->readPC() & 0x3)) + return new AlphaISA::UnimplementedOpcodeFault; + + this->setNextPC(this->thread->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR)); + + this->cpu->hwrei(); + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + template void OzoneDynInst::trap(Fault fault) { fault->invoke(this->thread->getTC()); } + +template +bool +OzoneDynInst::simPalCheck(int palFunc) +{ + return this->cpu->simPalCheck(palFunc); +} #else template void diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 03c20a6f2..b7fcf1708 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -413,7 +413,9 @@ class BaseSimpleCPU : public BaseCPU //Fault CacheOp(uint8_t Op, Addr EA); #if FULL_SYSTEM + Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } + bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } #else void syscall(int64_t callnum) { thread->syscall(callnum); } #endif diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index d26e984a3..189cbeec5 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -185,6 +185,10 @@ class SimpleThread : public ThreadState void dumpFuncProfile(); + Fault hwrei(); + + bool simPalCheck(int palFunc); + #endif /******************************************* -- cgit v1.2.3 From 9836d81c2bba97e36c43ca22feee1d51a12ce6ac Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 21 Oct 2008 07:12:53 -0700 Subject: style: Use the correct m5 style for things relating to interrupts. --- src/cpu/base.cc | 8 ++++---- src/cpu/base.hh | 17 +++++++++-------- src/cpu/intr_control.cc | 4 ++-- src/cpu/o3/commit_impl.hh | 4 ++-- src/cpu/o3/cpu.cc | 4 ++-- src/cpu/o3/cpu.hh | 2 +- src/cpu/o3/thread_context_impl.hh | 2 +- src/cpu/ozone/cpu.hh | 2 +- src/cpu/ozone/cpu_impl.hh | 4 ++-- src/cpu/ozone/inorder_back_end_impl.hh | 3 +-- src/cpu/ozone/lw_back_end_impl.hh | 5 +---- src/cpu/simple/base.cc | 6 +++--- src/cpu/simple/base.hh | 2 +- src/cpu/simple_thread.cc | 2 +- 14 files changed, 31 insertions(+), 34 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index def1e9920..8c461cccb 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -379,21 +379,21 @@ BaseCPU::ProfileEvent::process() } void -BaseCPU::post_interrupt(int int_num, int index) +BaseCPU::postInterrupt(int int_num, int index) { interrupts->post(int_num, index); } void -BaseCPU::clear_interrupt(int int_num, int index) +BaseCPU::clearInterrupt(int int_num, int index) { interrupts->clear(int_num, index); } void -BaseCPU::clear_interrupts() +BaseCPU::clearInterrupts() { - interrupts->clear_all(); + interrupts->clearAll(); } void diff --git a/src/cpu/base.hh b/src/cpu/base.hh index b0eece2a1..2d25c9e56 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -108,9 +108,7 @@ class BaseCPU : public MemObject #if FULL_SYSTEM protected: -// uint64_t interrupts[TheISA::NumInterruptLevels]; -// uint64_t intstatus; - TheISA::Interrupts * interrupts; + TheISA::Interrupts *interrupts; public: TheISA::Interrupts * @@ -119,12 +117,15 @@ class BaseCPU : public MemObject return interrupts; } - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); + virtual void postInterrupt(int int_num, int index); + virtual void clearInterrupt(int int_num, int index); + virtual void clearInterrupts(); - bool check_interrupts(ThreadContext * tc) const - { return interrupts->check_interrupts(tc); } + bool + checkInterrupts(ThreadContext *tc) const + { + return interrupts->checkInterrupts(tc); + } class ProfileEvent : public Event { diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc index c3a11ad91..de7f9245e 100644 --- a/src/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc @@ -50,7 +50,7 @@ IntrControl::post(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->post_interrupt(int_num, index); + cpu->postInterrupt(int_num, index); } void @@ -59,7 +59,7 @@ IntrControl::clear(int cpu_id, int int_num, int index) DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id); std::vector &tcvec = sys->threadContexts; BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); - cpu->clear_interrupt(int_num, index); + cpu->clearInterrupt(int_num, index); } IntrControl * diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 68fc6ef3b..46c4158f6 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -665,7 +665,7 @@ DefaultCommit::handleInterrupt() DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); } } else if (commitStatus[0] != TrapPending && - cpu->check_interrupts(cpu->tcBase(0)) && + cpu->checkInterrupts(cpu->tcBase(0)) && !trapSquash[0] && !tcSquash[0]) { // Process interrupts if interrupts are enabled, not in PAL @@ -695,7 +695,7 @@ DefaultCommit::commit() // Check for any interrupt, and start processing it. Or if we // have an outstanding interrupt and are at a point when it is // valid to take an interrupt, process it. - if (cpu->check_interrupts(cpu->tcBase(0))) { + if (cpu->checkInterrupts(cpu->tcBase(0))) { handleInterrupt(); } #endif // FULL_SYSTEM diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 41b7e8b14..04f344930 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -895,9 +895,9 @@ FullO3CPU::activateWhenReady(int tid) #if FULL_SYSTEM template void -FullO3CPU::post_interrupt(int int_num, int index) +FullO3CPU::postInterrupt(int int_num, int index) { - BaseCPU::post_interrupt(int_num, index); + BaseCPU::postInterrupt(int_num, index); if (this->thread[0]->status() == ThreadContext::Suspended) { DPRINTF(IPI,"Suspended Processor awoke\n"); diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 406d965be..8cfc9affa 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -412,7 +412,7 @@ class FullO3CPU : public BaseO3CPU #if FULL_SYSTEM /** Posts an interrupt. */ - void post_interrupt(int int_num, int index); + void postInterrupt(int int_num, int index); /** HW return from error interrupt. */ Fault hwrei(unsigned tid); diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index a521c3636..d8ec70bb8 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -132,7 +132,7 @@ O3ThreadContext::suspend(int delay) /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 845cbbd95..491e6ba93 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -332,7 +332,7 @@ class OzoneCPU : public BaseCPU Status _status; public: - void post_interrupt(int int_num, int index); + void postInterrupt(int int_num, int index); void zero_fill_64(Addr addr) { static int warned = 0; diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index c8e0dfe3d..a7efa3596 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -579,9 +579,9 @@ OzoneCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM template void -OzoneCPU::post_interrupt(int int_num, int index) +OzoneCPU::postInterrupt(int int_num, int index) { - BaseCPU::post_interrupt(int_num, index); + BaseCPU::postInterrupt(int_num, index); if (_status == Idle) { DPRINTF(IPI,"Suspended Processor awoke\n"); diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh index cf8634a42..798b628d6 100644 --- a/src/cpu/ozone/inorder_back_end_impl.hh +++ b/src/cpu/ozone/inorder_back_end_impl.hh @@ -149,8 +149,7 @@ InorderBackEnd::tick() // if (interrupt) then set thread PC, stall front end, record that // I'm waiting for it to drain. (for now just squash) #if FULL_SYSTEM - if (interruptBlocked || - cpu->check_interrupts(tc)) { + if (interruptBlocked || cpu->checkInterrupts(tc)) { if (!robEmpty()) { interruptBlocked = true; //AlphaDep diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh index a5d79a789..60c42edd3 100644 --- a/src/cpu/ozone/lw_back_end_impl.hh +++ b/src/cpu/ozone/lw_back_end_impl.hh @@ -525,10 +525,7 @@ template void LWBackEnd::checkInterrupts() { - if (cpu->checkInterrupts && - cpu->check_interrupts(tc) && - !trapSquash && - !tcSquash) { + if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) { frontEnd->interruptPending = true; if (robEmpty() && !LSQ.hasStoresToWB()) { // Will need to squash all instructions currently in flight and have diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index d207bda14..b3379cddb 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -303,9 +303,9 @@ BaseSimpleCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM void -BaseSimpleCPU::post_interrupt(int int_num, int index) +BaseSimpleCPU::postInterrupt(int int_num, int index) { - BaseCPU::post_interrupt(int_num, index); + BaseCPU::postInterrupt(int_num, index); if (thread->status() == ThreadContext::Suspended) { DPRINTF(Quiesce,"Suspended Processor awoke\n"); @@ -318,7 +318,7 @@ void BaseSimpleCPU::checkForInterrupts() { #if FULL_SYSTEM - if (check_interrupts(tc)) { + if (checkInterrupts(tc)) { Fault interrupt = interrupts->getInterrupt(tc); if (interrupt != NoFault) { diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index b7fcf1708..dc736c22e 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -98,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU } public: - void post_interrupt(int int_num, int index); + void postInterrupt(int int_num, int index); void zero_fill_64(Addr addr) { static int warned = 0; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 42da659f2..68683e568 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -241,7 +241,7 @@ SimpleThread::suspend() /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { + if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } -- cgit v1.2.3 From 8788d703f81cef20916ffd2c7e0d28031cf65df8 Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Thu, 23 Oct 2008 16:49:17 -0400 Subject: s/cpu_id/cpuId in o3 (to be consistent and match style), also fix some typos in comments. --- src/cpu/o3/cpu.cc | 2 +- src/cpu/o3/cpu.hh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 04f344930..1b7a3a17c 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -62,7 +62,7 @@ class BaseCPUParams; using namespace TheISA; BaseO3CPU::BaseO3CPU(BaseCPUParams *params) - : BaseCPU(params), cpu_id(0) + : BaseCPU(params), cpuId(0) { } diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 8cfc9affa..d1cc8bea5 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -76,13 +76,13 @@ class BaseO3CPU : public BaseCPU void regStats(); /** Sets this CPU's ID. */ - void setCpuId(int id) { cpu_id = id; } + void setCpuId(int id) { cpuId = id; } /** Reads this CPU's ID. */ - int readCpuId() { return cpu_id; } + int readCpuId() { return cpuId; } protected: - int cpu_id; + int cpuId; }; /** -- cgit v1.2.3 From 95af120e601671e6819ca97b78a1879d4ab0d853 Mon Sep 17 00:00:00 2001 From: Clint Smullen Date: Mon, 27 Oct 2008 18:18:04 -0400 Subject: CPU: The API change to EventWrapper did not get propagated to the entirety of TimingSimpleCPU. The constructor no-longer schedules an event at construction and the implict conversion between int and bool was allowing the old code to compile without warning. Signed-off By: Ali Saidi --- src/cpu/simple/timing.cc | 17 +++++------------ src/cpu/simple/timing.hh | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 0cda9a0a3..a6059f55f 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -105,7 +105,7 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) } TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) - : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) + : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), fetchEvent(this) { _status = Idle; @@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) ifetch_pkt = dcache_pkt = NULL; drainEvent = NULL; - fetchEvent = NULL; previousTick = 0; changeState(SimObject::Running); } @@ -162,15 +161,10 @@ TimingSimpleCPU::resume() if (_status != SwitchedOut && _status != Idle) { assert(system->getMemoryMode() == Enums::timing); - // Delete the old event if it existed. - if (fetchEvent) { - if (fetchEvent->scheduled()) - deschedule(fetchEvent); + if (fetchEvent.scheduled()) + deschedule(fetchEvent); - delete fetchEvent; - } - - fetchEvent = new FetchEvent(this, nextCycle()); + schedule(fetchEvent, nextCycle()); } changeState(SimObject::Running); @@ -185,7 +179,7 @@ TimingSimpleCPU::switchOut() // If we've been scheduled to resume but are then told to switch out, // we'll need to cancel it. - if (fetchEvent && fetchEvent->scheduled()) + if (fetchEvent.scheduled()) deschedule(fetchEvent); } @@ -228,7 +222,6 @@ TimingSimpleCPU::activateContext(int thread_num, int delay) _status = Running; // kick things off by initiating the fetch of the next instruction - fetchEvent = new FetchEvent(this); schedule(fetchEvent, nextCycle(curTick + ticks(delay))); } diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 081051ea7..0fc9b3152 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -192,7 +192,7 @@ class TimingSimpleCPU : public BaseSimpleCPU private: typedef EventWrapper FetchEvent; - FetchEvent *fetchEvent; + FetchEvent fetchEvent; struct IprEvent : Event { Packet *pkt; -- cgit v1.2.3 From c55a467a06eaa59c47c52a2adddc266b8e545589 Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Sun, 2 Nov 2008 21:56:57 -0500 Subject: make BaseCPU the provider of _cpuId, and cpuId() instead of being scattered across the subclasses. generally make it so that member data is _cpuId and accessor functions are cpuId(). The ID val comes from the python (default -1 if none provided), and if it is -1, the index of cpuList will be given. this has passed util/regress quick and se.py -n4 and fs.py -n4 as well as standard switch. --- src/cpu/BaseCPU.py | 2 +- src/cpu/base.cc | 28 +++++++++++++++++----------- src/cpu/base.hh | 8 ++++++++ src/cpu/base_dyn_inst.hh | 10 +++++----- src/cpu/checker/cpu_impl.hh | 2 +- src/cpu/checker/thread_context.hh | 2 +- src/cpu/o3/cpu.cc | 5 ++--- src/cpu/o3/cpu.hh | 9 --------- src/cpu/o3/fetch_impl.hh | 2 +- src/cpu/o3/thread_context.hh | 5 +---- src/cpu/o3/thread_context_impl.hh | 1 - src/cpu/o3/thread_state.hh | 4 ++-- src/cpu/ozone/cpu.hh | 10 ---------- src/cpu/ozone/cpu_impl.hh | 4 ++-- src/cpu/ozone/front_end_impl.hh | 2 +- src/cpu/simple/atomic.cc | 16 +++++++--------- src/cpu/simple/base.hh | 1 - src/cpu/simple/timing.cc | 15 +++++++-------- src/cpu/simple_thread.cc | 9 ++++----- src/cpu/thread_context.cc | 4 ++-- src/cpu/thread_context.hh | 8 ++------ src/cpu/thread_state.cc | 8 ++++---- src/cpu/thread_state.hh | 14 ++++---------- 23 files changed, 72 insertions(+), 97 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index ef9b54f3f..f98c6af8e 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -63,7 +63,7 @@ class BaseCPU(MemObject): abstract = True system = Param.System(Parent.any, "system object") - cpu_id = Param.Int("CPU identifier") + cpu_id = Param.Int(-1, "CPU identifier") numThreads = Param.Unsigned(1, "number of HW thread contexts") function_trace = Param.Bool(False, "Enable function trace") diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 8c461cccb..3e899d993 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -94,21 +94,29 @@ CPUProgressEvent::description() const #if FULL_SYSTEM BaseCPU::BaseCPU(Params *p) - : MemObject(p), clock(p->clock), instCnt(0), interrupts(p->interrupts), + : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id), + interrupts(p->interrupts), number_of_threads(p->numThreads), system(p->system), phase(p->phase) #else BaseCPU::BaseCPU(Params *p) - : MemObject(p), clock(p->clock), + : MemObject(p), clock(p->clock), _cpuId(p->cpu_id), number_of_threads(p->numThreads), system(p->system), phase(p->phase) #endif { // currentTick = curTick; + // if Python did not provide a valid ID, do it here + if (_cpuId == -1 ) { + _cpuId = cpuList.size(); + } + // add self to global list of CPUs cpuList.push_back(this); + DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId); + if (number_of_threads > maxThreadsPerCPU) maxThreadsPerCPU = number_of_threads; @@ -278,13 +286,9 @@ BaseCPU::registerThreadContexts() ThreadContext *tc = threadContexts[i]; #if FULL_SYSTEM - int id = params()->cpu_id; - if (id != -1) - id += i; - - tc->setCpuId(system->registerThreadContext(tc, id)); + system->registerThreadContext(tc); #else - tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc)); + tc->getProcessPtr()->registerThreadContext(tc); #endif } } @@ -315,6 +319,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) { assert(threadContexts.size() == oldCPU->threadContexts.size()); + _cpuId = oldCPU->cpuId(); + for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *newTC = threadContexts[i]; ThreadContext *oldTC = oldCPU->threadContexts[i]; @@ -323,12 +329,12 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); - assert(newTC->readCpuId() == oldTC->readCpuId()); + assert(newTC->cpuId() == oldTC->cpuId()); #if FULL_SYSTEM - system->replaceThreadContext(newTC, newTC->readCpuId()); + system->replaceThreadContext(newTC, newTC->cpuId()); #else assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); - newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId()); + newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->cpuId()); #endif if (DTRACE(Context)) diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 2d25c9e56..f39759605 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -80,8 +80,16 @@ class BaseCPU : public MemObject Tick clock; // @todo remove me after debugging with legion done Tick instCnt; + // every cpu has an id, put it in the base cpu + // Set at initialization, only time a cpuId might change is during a + // takeover (which should be done from within the BaseCPU anyway, + // therefore no setCpuId() method is provided + int _cpuId; public: + /** Reads this CPU's ID. */ + int cpuId() { return _cpuId; } + // Tick currentTick; inline Tick frequency() const { return Clock::Frequency / clock; } inline Tick ticks(int numCycles) const { return clock * numCycles; } diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index b03a2f63e..e0de3a372 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -412,7 +412,7 @@ class BaseDynInst : public FastAlloc, public RefCounted void dump(std::string &outstring); /** Read this CPU's ID. */ - int readCpuId() { return cpu->readCpuId(); } + int cpuId() { return cpu->cpuId(); } /** Returns the fault type. */ Fault getFault() { return fault; } @@ -868,7 +868,7 @@ BaseDynInst::translateDataReadAddr(Addr vaddr, Addr &paddr, reqMade = true; Request *req = new Request(); req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->cpuId(), threadNumber); fault = cpu->translateDataReadReq(req, thread); @@ -887,7 +887,7 @@ BaseDynInst::read(Addr addr, T &data, unsigned flags) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->cpuId(), threadNumber); fault = cpu->translateDataReadReq(req, thread); @@ -942,7 +942,7 @@ BaseDynInst::translateDataWriteAddr(Addr vaddr, Addr &paddr, reqMade = true; Request *req = new Request(); req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->cpuId(), threadNumber); fault = cpu->translateDataWriteReq(req, thread); @@ -966,7 +966,7 @@ BaseDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->readCpuId(), threadNumber); + req->setThreadContext(thread->cpuId(), threadNumber); fault = cpu->translateDataWriteReq(req, thread); diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index 33c70569a..9f6fa2b6d 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -152,7 +152,7 @@ Checker::verify(DynInstPtr &completed_inst) memReq = new Request(inst->threadNumber, fetch_PC, sizeof(uint32_t), IFETCH_FLAGS(thread->readPC()), - fetch_PC, thread->readCpuId(), inst->threadNumber); + fetch_PC, thread->cpuId(), inst->threadNumber); bool succeeded = translateInstReq(memReq); diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 75ac959db..a74de20b9 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -82,7 +82,7 @@ class CheckerThreadContext : public ThreadContext checkerTC->setCpuId(id); } - int readCpuId() { return actualTC->readCpuId(); } + int cpuId() { return actualTC->cpuId(); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 1b7a3a17c..b7cf4f1c0 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -62,7 +62,7 @@ class BaseCPUParams; using namespace TheISA; BaseO3CPU::BaseO3CPU(BaseCPUParams *params) - : BaseCPU(params), cpuId(0) + : BaseCPU(params) { } @@ -404,7 +404,6 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) #endif // Give the thread the TC. this->thread[i]->tc = tc; - this->thread[i]->setCpuId(params->cpu_id); // Add the TC to the CPU's list of TC's. this->threadContexts.push_back(tc); @@ -611,7 +610,7 @@ FullO3CPU::init() } #if FULL_SYSTEM - TheISA::initCPU(src_tc, src_tc->readCpuId()); + TheISA::initCPU(src_tc, src_tc->cpuId()); #endif } diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index d1cc8bea5..c60c20d55 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -74,15 +74,6 @@ class BaseO3CPU : public BaseCPU BaseO3CPU(BaseCPUParams *params); void regStats(); - - /** Sets this CPU's ID. */ - void setCpuId(int id) { cpuId = id; } - - /** Reads this CPU's ID. */ - int readCpuId() { return cpuId; } - - protected: - int cpuId; }; /** diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 0b5ce9380..35031663e 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -593,7 +593,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid // Set the appropriate read size and flags as well. // Build request here. RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0, - fetch_PC, cpu->readCpuId(), tid); + fetch_PC, cpu->cpuId(), tid); memReq[tid] = mem_req; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index c529b002b..d571d25db 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -75,11 +75,8 @@ class O3ThreadContext : public ThreadContext /** Returns a pointer to this CPU. */ virtual BaseCPU *getCpuPtr() { return cpu; } - /** Sets this CPU's ID. */ - virtual void setCpuId(int id) { cpu->setCpuId(id); } - /** Reads this CPU's ID. */ - virtual int readCpuId() { return cpu->readCpuId(); } + virtual int cpuId() { return cpu->cpuId(); } #if FULL_SYSTEM /** Returns a pointer to the system. */ diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index d8ec70bb8..853ee2c63 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -63,7 +63,6 @@ O3ThreadContext::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh index 8c634f67e..1f0e7a3bb 100644 --- a/src/cpu/o3/thread_state.hh +++ b/src/cpu/o3/thread_state.hh @@ -77,7 +77,7 @@ struct O3ThreadState : public ThreadState { #if FULL_SYSTEM O3ThreadState(O3CPU *_cpu, int _thread_num) - : ThreadState(_cpu, -1, _thread_num), + : ThreadState(_cpu, _thread_num), cpu(_cpu), inSyscall(0), trapPending(0) { if (cpu->params()->profile) { @@ -96,7 +96,7 @@ struct O3ThreadState : public ThreadState { } #else O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), inSyscall(0), trapPending(0) { } #endif diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 491e6ba93..8fce61d4f 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -116,10 +116,6 @@ class OzoneCPU : public BaseCPU BaseCPU *getCpuPtr(); - void setCpuId(int id); - - int readCpuId() { return thread->readCpuId(); } - TheISA::ITB *getITBPtr() { return cpu->itb; } TheISA::DTB * getDTBPtr() { return cpu->dtb; } @@ -353,12 +349,6 @@ class OzoneCPU : public BaseCPU public: BaseCPU *getCpuPtr() { return this; } - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } - - int cpuId; - void switchOut(); void signalSwitched(); void takeOverFrom(BaseCPU *oldCPU); diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index a7efa3596..52376afd8 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -417,7 +417,7 @@ OzoneCPU::init() ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, tc->readCpuId()); + TheISA::initCPU(tc, tc->cpuId()); } #endif frontEnd->renameTable.copyFrom(thread.renameTable); @@ -803,7 +803,7 @@ OzoneCPU::OzoneTC::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); + setCpuId(old_context->cpuId()); thread->setInst(old_context->getInst()); #if !FULL_SYSTEM diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index 198ce0308..df3609e27 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -477,7 +477,7 @@ FrontEnd::fetchCacheLine() // Setup the memReq to do a read of the first isntruction's address. // Set the appropriate read size and flags as well. memReq = new Request(0, fetch_PC, cacheBlkSize, 0, - PC, cpu->readCpuId(), 0); + PC, cpu->cpuId(), 0); // Translate the instruction request. fault = cpu->translateInstReq(memReq, thread); diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 30f4a5c5e..5e8ab9443 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -79,13 +79,12 @@ void AtomicSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, _cpuId); } #endif if (hasPhysMemPort) { @@ -94,9 +93,9 @@ AtomicSimpleCPU::init() 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 + 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 @@ -237,10 +236,9 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _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 } diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index dc736c22e..6e72b8f6c 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -121,7 +121,6 @@ class BaseSimpleCPU : public BaseCPU */ ThreadContext *tc; protected: - int cpuId; enum Status { Idle, diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index a6059f55f..247899ca8 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -57,13 +57,12 @@ void TimingSimpleCPU::init() { BaseCPU::init(); - cpuId = tc->readCpuId(); #if FULL_SYSTEM for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, cpuId); + TheISA::initCPU(tc, _cpuId); } #endif } @@ -203,7 +202,7 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - cpuId = tc->readCpuId(); + _cpuId = tc->cpuId(); previousTick = curTick; } @@ -250,7 +249,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) { Request *req = new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + _cpuId, /* thread ID */ 0); if (traceData) { traceData->setAddr(req->getVaddr()); @@ -301,7 +300,7 @@ TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, int size, unsigned flags) { Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); + new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); if (traceData) { traceData->setAddr(vaddr); @@ -373,7 +372,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { Request *req = new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - cpuId, /* thread ID */ 0); + _cpuId, /* thread ID */ 0); if (traceData) { traceData->setAddr(req->getVaddr()); @@ -442,7 +441,7 @@ TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, int size, unsigned flags) { Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); + new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); if (traceData) { traceData->setAddr(vaddr); @@ -528,7 +527,7 @@ TimingSimpleCPU::fetch() if (!fromRom) { Request *ifetch_req = new Request(); - ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); + ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); Fault fault = setupFetchRequest(ifetch_req); ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 68683e568..6034ca120 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -63,7 +63,7 @@ using namespace std; SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, TheISA::ITB *_itb, TheISA::DTB *_dtb, bool use_kernel_stats) - : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), system(_sys), itb(_itb), + : ThreadState(_cpu, _thread_num), cpu(_cpu), system(_sys), itb(_itb), dtb(_dtb) { @@ -93,7 +93,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, #else SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, TheISA::ITB *_itb, TheISA::DTB *_dtb, int _asid) - : ThreadState(_cpu, -1, _thread_num, _process, _asid), + : ThreadState(_cpu, _thread_num, _process, _asid), cpu(_cpu), itb(_itb), dtb(_dtb) { regs.clear(); @@ -104,9 +104,9 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, SimpleThread::SimpleThread() #if FULL_SYSTEM - : ThreadState(NULL, -1, -1) + : ThreadState(NULL, -1) #else - : ThreadState(NULL, -1, -1, NULL, -1) + : ThreadState(NULL, -1, NULL, -1) #endif { tc = new ProxyThreadContext(this); @@ -178,7 +178,6 @@ SimpleThread::copyState(ThreadContext *oldContext) // copy over functional state _status = oldContext->status(); copyArchRegs(oldContext); - cpuId = oldContext->readCpuId(); #if !FULL_SYSTEM funcExeInst = oldContext->readFuncExeInst(); #endif diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc index 10c94027d..58912c564 100644 --- a/src/cpu/thread_context.cc +++ b/src/cpu/thread_context.cc @@ -74,8 +74,8 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two) if (npc1 != npc2) panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2); - int id1 = one->readCpuId(); - int id2 = two->readCpuId(); + int id1 = one->cpuId(); + int id2 = two->cpuId(); if (id1 != id2) panic("CPU ids don't match, one: %d, two: %d", id1, id2); } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 2b9f41b70..d06194012 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -115,9 +115,7 @@ class ThreadContext virtual BaseCPU *getCpuPtr() = 0; - virtual void setCpuId(int id) = 0; - - virtual int readCpuId() = 0; + virtual int cpuId() = 0; virtual TheISA::ITB *getITBPtr() = 0; @@ -300,9 +298,7 @@ class ProxyThreadContext : public ThreadContext BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); } - void setCpuId(int id) { actualTC->setCpuId(id); } - - int readCpuId() { return actualTC->readCpuId(); } + int cpuId() { return actualTC->cpuId(); } TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 8d519c563..47841922e 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -43,15 +43,15 @@ #endif #if FULL_SYSTEM -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), +ThreadState::ThreadState(BaseCPU *cpu, int _tid) + : baseCpu(cpu), tid(_tid), lastActivate(0), lastSuspend(0), profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), kernelStats(NULL), physPort(NULL), virtPort(NULL), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #else -ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, +ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid) - : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), + : baseCpu(cpu), tid(_tid), lastActivate(0), lastSuspend(0), port(NULL), process(_process), asid(_asid), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #endif diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 1b667f72a..f3f154de3 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -34,6 +34,7 @@ #include "arch/types.hh" #include "cpu/profile.hh" #include "cpu/thread_context.hh" +#include "cpu/base.hh" #if !FULL_SYSTEM #include "mem/mem_object.hh" @@ -51,7 +52,6 @@ namespace TheISA { }; #endif -class BaseCPU; class Checkpoint; class Port; class TranslatingPort; @@ -66,9 +66,9 @@ struct ThreadState { typedef ThreadContext::Status Status; #if FULL_SYSTEM - ThreadState(BaseCPU *cpu, int _cpuId, int _tid); + ThreadState(BaseCPU *cpu, int _tid); #else - ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process, + ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid); #endif @@ -78,9 +78,7 @@ struct ThreadState { void unserialize(Checkpoint *cp, const std::string §ion); - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } + int cpuId() { return baseCpu->cpuId(); } void setTid(int id) { tid = id; } @@ -171,10 +169,6 @@ struct ThreadState { // Pointer to the base CPU. BaseCPU *baseCpu; - // ID of this context w.r.t. the System or Process object to which - // it belongs. For full-system mode, this is the system CPU ID. - int cpuId; - // Index of hardware thread context on the CPU that this represents. int tid; -- cgit v1.2.3 From 67fda02dda290d614de233846fee434b3713b1dc Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Sun, 2 Nov 2008 21:57:06 -0500 Subject: Make it so that all thread contexts are registered with the System, even in SE. Process still keeps track of the tc's it owns, but registration occurs with the System, this eases the way for system-wide context Ids based on registration. --- src/cpu/base.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 3e899d993..4845cbfaf 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -285,10 +285,9 @@ BaseCPU::registerThreadContexts() for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; -#if FULL_SYSTEM system->registerThreadContext(tc); -#else - tc->getProcessPtr()->registerThreadContext(tc); +#if !FULL_SYSTEM + tc->getProcessPtr()->assignThreadContext(tc->cpuId()); #endif } } @@ -330,12 +329,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); assert(newTC->cpuId() == oldTC->cpuId()); -#if FULL_SYSTEM system->replaceThreadContext(newTC, newTC->cpuId()); -#else - assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); - newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->cpuId()); -#endif if (DTRACE(Context)) ThreadContext::compare(oldTC, newTC); -- cgit v1.2.3 From d857faf073895dcfde97141bd6346fe5d4317f8e Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Sun, 2 Nov 2008 21:57:07 -0500 Subject: Add in Context IDs to the simulator. From now on, cpuId is almost never used, the primary identifier for a hardware context should be contextId(). The concept of threads within a CPU remains, in the form of threadId() because sometimes you need to know which context within a cpu to manipulate. --- src/cpu/base.cc | 8 ++++---- src/cpu/base_dyn_inst.hh | 11 +++++++---- src/cpu/checker/cpu_impl.hh | 3 ++- src/cpu/o3/cpu.cc | 6 ++---- src/cpu/o3/fetch_impl.hh | 5 +++-- src/cpu/o3/lsq.hh | 4 ++-- src/cpu/o3/lsq_impl.hh | 2 +- src/cpu/o3/thread_context.hh | 4 ++++ src/cpu/o3/thread_context_impl.hh | 1 + src/cpu/ozone/cpu_impl.hh | 11 ++--------- src/cpu/ozone/front_end_impl.hh | 2 +- src/cpu/simple/atomic.cc | 3 ++- src/cpu/simple/timing.cc | 1 - src/cpu/simple_thread.cc | 2 ++ src/cpu/thread_context.cc | 7 +++++++ src/cpu/thread_context.hh | 17 ++++++++++++----- src/cpu/thread_state.hh | 7 +++++++ 17 files changed, 59 insertions(+), 35 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 4845cbfaf..6409255f6 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -285,9 +285,9 @@ BaseCPU::registerThreadContexts() for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; - system->registerThreadContext(tc); + tc->setContextId(system->registerThreadContext(tc)); #if !FULL_SYSTEM - tc->getProcessPtr()->assignThreadContext(tc->cpuId()); + tc->getProcessPtr()->assignThreadContext(tc->contextId()); #endif } } @@ -328,8 +328,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); - assert(newTC->cpuId() == oldTC->cpuId()); - system->replaceThreadContext(newTC, newTC->cpuId()); + assert(newTC->contextId() == oldTC->contextId()); + system->replaceThreadContext(newTC, newTC->contextId()); if (DTRACE(Context)) ThreadContext::compare(oldTC, newTC); diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index e0de3a372..3520fafaa 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -414,6 +414,9 @@ class BaseDynInst : public FastAlloc, public RefCounted /** Read this CPU's ID. */ int cpuId() { return cpu->cpuId(); } + /** Read this context's system-wide ID **/ + int contextId() { return thread->contextId(); } + /** Returns the fault type. */ Fault getFault() { return fault; } @@ -868,7 +871,7 @@ BaseDynInst::translateDataReadAddr(Addr vaddr, Addr &paddr, reqMade = true; Request *req = new Request(); req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->cpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); fault = cpu->translateDataReadReq(req, thread); @@ -887,7 +890,7 @@ BaseDynInst::read(Addr addr, T &data, unsigned flags) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->cpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); fault = cpu->translateDataReadReq(req, thread); @@ -942,7 +945,7 @@ BaseDynInst::translateDataWriteAddr(Addr vaddr, Addr &paddr, reqMade = true; Request *req = new Request(); req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->cpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); fault = cpu->translateDataWriteReq(req, thread); @@ -966,7 +969,7 @@ BaseDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) reqMade = true; Request *req = new Request(); req->setVirt(asid, addr, sizeof(T), flags, this->PC); - req->setThreadContext(thread->cpuId(), threadNumber); + req->setThreadContext(thread->contextId(), threadNumber); fault = cpu->translateDataWriteReq(req, thread); diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index 9f6fa2b6d..0428e8806 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -152,7 +152,8 @@ Checker::verify(DynInstPtr &completed_inst) memReq = new Request(inst->threadNumber, fetch_PC, sizeof(uint32_t), IFETCH_FLAGS(thread->readPC()), - fetch_PC, thread->cpuId(), inst->threadNumber); + fetch_PC, thread->contextId(), + inst->threadNumber); bool succeeded = translateInstReq(memReq); diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index b7cf4f1c0..26c155262 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -589,9 +589,7 @@ template void FullO3CPU::init() { - if (!deferRegistration) { - registerThreadContexts(); - } + BaseCPU::init(); // Set inSyscall so that the CPU doesn't squash when initially // setting up registers. @@ -610,7 +608,7 @@ FullO3CPU::init() } #if FULL_SYSTEM - TheISA::initCPU(src_tc, src_tc->cpuId()); + TheISA::initCPU(src_tc, src_tc->contextId()); #endif } diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 35031663e..cff6db299 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -362,7 +362,7 @@ template void DefaultFetch::processCacheCompletion(PacketPtr pkt) { - unsigned tid = pkt->req->getThreadNum(); + unsigned tid = pkt->req->threadId(); DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); @@ -593,7 +593,8 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid // Set the appropriate read size and flags as well. // Build request here. RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0, - fetch_PC, cpu->cpuId(), tid); + fetch_PC, cpu->thread[tid]->contextId(), + tid); memReq[tid] = mem_req; diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index f8a825726..cf27552d4 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -371,7 +371,7 @@ template Fault LSQ::read(RequestPtr req, T &data, int load_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].read(req, data, load_idx); } @@ -381,7 +381,7 @@ template Fault LSQ::write(RequestPtr req, T &data, int store_idx) { - unsigned tid = req->getThreadNum(); + unsigned tid = req->threadId(); return thread[tid].write(req, data, store_idx); } diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 5aea020a9..8f9f63081 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -85,7 +85,7 @@ LSQ::DcachePort::recvTiming(PacketPtr pkt) if (pkt->isError()) DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr()); if (pkt->isResponse()) { - lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt); + lsq->thread[pkt->req->threadId()].completeDataAccess(pkt); } else { // must be a snoop diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index d571d25db..c237b9587 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -78,6 +78,10 @@ class O3ThreadContext : public ThreadContext /** Reads this CPU's ID. */ virtual int cpuId() { return cpu->cpuId(); } + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + #if FULL_SYSTEM /** Returns a pointer to the system. */ virtual System *getSystemPtr() { return cpu->system; } diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 853ee2c63..50f6e58b3 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -63,6 +63,7 @@ O3ThreadContext::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); + setContextId(old_context->contextId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 52376afd8..eef1a7b2f 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -417,7 +417,7 @@ OzoneCPU::init() ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, tc->cpuId()); + TheISA::initCPU(tc, tc->contextId()); } #endif frontEnd->renameTable.copyFrom(thread.renameTable); @@ -734,14 +734,6 @@ OzoneCPU::OzoneTC::getCpuPtr() return cpu; } -template -void -OzoneCPU::OzoneTC::setCpuId(int id) -{ - cpu->cpuId = id; - thread->setCpuId(id); -} - template void OzoneCPU::OzoneTC::setStatus(Status new_status) @@ -804,6 +796,7 @@ OzoneCPU::OzoneTC::takeOverFrom(ThreadContext *old_context) setStatus(old_context->status()); copyArchRegs(old_context); setCpuId(old_context->cpuId()); + setContextId(old_context->contextId()); thread->setInst(old_context->getInst()); #if !FULL_SYSTEM diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index df3609e27..b1e131115 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -477,7 +477,7 @@ FrontEnd::fetchCacheLine() // Setup the memReq to do a read of the first isntruction's address. // Set the appropriate read size and flags as well. memReq = new Request(0, fetch_PC, cacheBlkSize, 0, - PC, cpu->cpuId(), 0); + PC, cpu->thread->contextId()); // Translate the instruction request. fault = cpu->translateInstReq(memReq, thread); diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 5e8ab9443..feb8a7fc5 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -84,7 +84,7 @@ AtomicSimpleCPU::init() ThreadContext *tc = threadContexts[i]; // initialize CPU, including PC - TheISA::initCPU(tc, _cpuId); + TheISA::initCPU(tc, tc->contextId()); } #endif if (hasPhysMemPort) { @@ -93,6 +93,7 @@ AtomicSimpleCPU::init() physmemPort.getPeerAddressRanges(pmAddrList, snoop); physMemAddr = *pmAddrList.begin(); } + // 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 diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 247899ca8..ca1f0283e 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -202,7 +202,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) _status = Idle; } assert(threadContexts.size() == 1); - _cpuId = tc->cpuId(); previousTick = curTick; } diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 6034ca120..5c6b729b6 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -182,6 +182,8 @@ SimpleThread::copyState(ThreadContext *oldContext) funcExeInst = oldContext->readFuncExeInst(); #endif inst = oldContext->getInst(); + + _contextId = oldContext->contextId(); } void diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc index 58912c564..ab105a435 100644 --- a/src/cpu/thread_context.cc +++ b/src/cpu/thread_context.cc @@ -78,4 +78,11 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two) int id2 = two->cpuId(); if (id1 != id2) panic("CPU ids don't match, one: %d, two: %d", id1, id2); + + id1 = one->contextId(); + id2 = two->contextId(); + if (id1 != id2) + panic("Context ids don't match, one: %d, two: %d", id1, id2); + + } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index d06194012..a94be7024 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -117,6 +117,12 @@ class ThreadContext virtual int cpuId() = 0; + virtual int getThreadNum() = 0; + + virtual int contextId() = 0; + + virtual void setContextId(int id) = 0; + virtual TheISA::ITB *getITBPtr() = 0; virtual TheISA::DTB *getDTBPtr() = 0; @@ -177,8 +183,6 @@ class ThreadContext virtual void profileSample() = 0; #endif - virtual int getThreadNum() = 0; - // Also somewhat obnoxious. Really only used for the TLB fault. // However, may be quite useful in SPARC. virtual TheISA::MachInst getInst() = 0; @@ -300,6 +304,12 @@ class ProxyThreadContext : public ThreadContext int cpuId() { return actualTC->cpuId(); } + int getThreadNum() { return actualTC->getThreadNum(); } + + int contextId() { return actualTC->contextId(); } + + void setContextId(int id) { actualTC->setContextId(id); } + TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); } TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); } @@ -360,9 +370,6 @@ class ProxyThreadContext : public ThreadContext void profileClear() { return actualTC->profileClear(); } void profileSample() { return actualTC->profileSample(); } #endif - - int getThreadNum() { return actualTC->getThreadNum(); } - // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index f3f154de3..fdb2ab0ab 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -80,6 +80,10 @@ struct ThreadState { int cpuId() { return baseCpu->cpuId(); } + int contextId() { return _contextId; } + + void setContextId(int id) { _contextId = id; } + void setTid(int id) { tid = id; } int readTid() { return tid; } @@ -169,6 +173,9 @@ struct ThreadState { // Pointer to the base CPU. BaseCPU *baseCpu; + // system wide HW context id + int _contextId; + // Index of hardware thread context on the CPU that this represents. int tid; -- cgit v1.2.3 From dd99ff23c6a71f7173014b5008d0cf12b7ef223a Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Tue, 4 Nov 2008 11:35:42 -0500 Subject: get rid of all instances of readTid() and getThreadNum(). Unify and eliminate redundancies with threadId() as their replacement. --- src/cpu/base.cc | 1 + src/cpu/base.hh | 2 +- src/cpu/checker/thread_context.hh | 2 +- src/cpu/exetrace.cc | 2 +- src/cpu/o3/thread_context.hh | 25 ++++++------ src/cpu/o3/thread_context_impl.hh | 85 ++++++++++++++++++++------------------- src/cpu/ozone/cpu.hh | 4 +- src/cpu/ozone/cpu_impl.hh | 16 ++++---- src/cpu/simple_thread.cc | 11 ++--- src/cpu/simple_thread.hh | 2 - src/cpu/thread_context.hh | 8 +++- src/cpu/thread_state.cc | 10 ++--- src/cpu/thread_state.hh | 6 +-- 13 files changed, 90 insertions(+), 84 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 6409255f6..1fa7add65 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -329,6 +329,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) CpuEvent::replaceThreadContext(oldTC, newTC); assert(newTC->contextId() == oldTC->contextId()); + assert(newTC->threadId() == oldTC->threadId()); system->replaceThreadContext(newTC, newTC->contextId()); if (DTRACE(Context)) diff --git a/src/cpu/base.hh b/src/cpu/base.hh index f39759605..83d73ede0 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -82,7 +82,7 @@ class BaseCPU : public MemObject Tick instCnt; // every cpu has an id, put it in the base cpu // Set at initialization, only time a cpuId might change is during a - // takeover (which should be done from within the BaseCPU anyway, + // takeover (which should be done from within the BaseCPU anyway, // therefore no setCpuId() method is provided int _cpuId; diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index a74de20b9..524e87cd4 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -153,7 +153,7 @@ class CheckerThreadContext : public ThreadContext void profileSample() { return actualTC->profileSample(); } #endif - int getThreadNum() { return actualTC->getThreadNum(); } + int threadId() { return actualTC->threadId(); } // @todo: Do I need this? MachInst getInst() { return actualTC->getInst(); } diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 0118dbde1..824fbb5f6 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -59,7 +59,7 @@ Trace::ExeTracerRecord::dump() outs << (misspeculating ? "-" : "+") << " "; if (IsOn(ExecThread)) - outs << "T" << thread->getThreadNum() << " : "; + outs << "T" << thread->threadId() << " : "; std::string sym_str; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index c237b9587..8682e071e 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -82,6 +82,10 @@ class O3ThreadContext : public ThreadContext virtual void setContextId(int id) { thread->setContextId(id); } + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } + #if FULL_SYSTEM /** Returns a pointer to the system. */ virtual System *getSystemPtr() { return cpu->system; } @@ -152,9 +156,6 @@ class O3ThreadContext : public ThreadContext /** Samples the function profiling information. */ virtual void profileSample(); #endif - /** Returns this thread's ID number. */ - virtual int getThreadNum() { return thread->readTid(); } - /** Returns the instruction this thread is currently committing. * Only used when an instruction faults. */ @@ -190,36 +191,36 @@ class O3ThreadContext : public ThreadContext /** Reads this thread's PC. */ virtual uint64_t readPC() - { return cpu->readPC(thread->readTid()); } + { return cpu->readPC(thread->threadId()); } /** Sets this thread's PC. */ virtual void setPC(uint64_t val); /** Reads this thread's next PC. */ virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->readTid()); } + { return cpu->readNextPC(thread->threadId()); } /** Sets this thread's next PC. */ virtual void setNextPC(uint64_t val); virtual uint64_t readMicroPC() - { return cpu->readMicroPC(thread->readTid()); } + { return cpu->readMicroPC(thread->threadId()); } virtual void setMicroPC(uint64_t val); virtual uint64_t readNextMicroPC() - { return cpu->readNextMicroPC(thread->readTid()); } + { return cpu->readNextMicroPC(thread->threadId()); } virtual void setNextMicroPC(uint64_t val); /** Reads a miscellaneous register. */ virtual MiscReg readMiscRegNoEffect(int misc_reg) - { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + { return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); } /** Reads a misc. register, including any side-effects the * read might have as defined by the architecture. */ virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->readTid()); } + { return cpu->readMiscReg(misc_reg, thread->threadId()); } /** Sets a misc. register. */ virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); @@ -257,7 +258,7 @@ class O3ThreadContext : public ThreadContext /** Executes a syscall in SE mode. */ virtual void syscall(int64_t callnum) - { return cpu->syscall(callnum, thread->readTid()); } + { return cpu->syscall(callnum, thread->threadId()); } /** Reads the funcExeInst counter. */ virtual Counter readFuncExeInst() { return thread->funcExeInst; } @@ -271,7 +272,7 @@ class O3ThreadContext : public ThreadContext virtual uint64_t readNextNPC() { - return this->cpu->readNextNPC(this->thread->readTid()); + return this->cpu->readNextNPC(this->thread->threadId()); } virtual void setNextNPC(uint64_t val) @@ -279,7 +280,7 @@ class O3ThreadContext : public ThreadContext #if THE_ISA == ALPHA_ISA panic("Not supported on Alpha!"); #endif - this->cpu->setNextNPC(val, this->thread->readTid()); + this->cpu->setNextNPC(val, this->thread->threadId()); } /** This function exits the thread context in the CPU and returns diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 50f6e58b3..735827ebc 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -64,6 +64,7 @@ O3ThreadContext::takeOverFrom(ThreadContext *old_context) setStatus(old_context->status()); copyArchRegs(old_context); setContextId(old_context->contextId()); + setThreadId(old_context->threadId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); @@ -95,7 +96,7 @@ void O3ThreadContext::activate(int delay) { DPRINTF(O3CPU, "Calling activate on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Active) return; @@ -105,14 +106,14 @@ O3ThreadContext::activate(int delay) #endif if (thread->status() == ThreadContext::Unallocated) { - cpu->activateWhenReady(thread->readTid()); + cpu->activateWhenReady(thread->threadId()); return; } thread->setStatus(ThreadContext::Active); // status() == Suspended - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } template @@ -120,7 +121,7 @@ void O3ThreadContext::suspend(int delay) { DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Suspended) return; @@ -139,7 +140,7 @@ O3ThreadContext::suspend(int delay) #endif */ thread->setStatus(ThreadContext::Suspended); - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } template @@ -147,13 +148,13 @@ void O3ThreadContext::deallocate(int delay) { DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n", - getThreadNum(), delay); + threadId(), delay); if (thread->status() == ThreadContext::Unallocated) return; thread->setStatus(ThreadContext::Unallocated); - cpu->deallocateContext(thread->readTid(), true, delay); + cpu->deallocateContext(thread->threadId(), true, delay); } template @@ -161,13 +162,13 @@ void O3ThreadContext::halt(int delay) { DPRINTF(O3CPU, "Calling halt on Thread Context %d\n", - getThreadNum()); + threadId()); if (thread->status() == ThreadContext::Halted) return; thread->setStatus(ThreadContext::Halted); - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } template @@ -245,7 +246,7 @@ O3ThreadContext::copyArchRegs(ThreadContext *tc) { // This function will mess things up unless the ROB is empty and // there are no instructions in the pipeline. - unsigned tid = thread->readTid(); + unsigned tid = thread->threadId(); PhysRegIndex renamed_reg; // First loop through the integer registers. @@ -292,7 +293,7 @@ uint64_t O3ThreadContext::readIntReg(int reg_idx) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - return cpu->readArchIntReg(reg_idx, thread->readTid()); + return cpu->readArchIntReg(reg_idx, thread->threadId()); } template @@ -302,9 +303,9 @@ O3ThreadContext::readFloatReg(int reg_idx, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); case 64: - return cpu->readArchFloatRegDouble(reg_idx, thread->readTid()); + return cpu->readArchFloatRegDouble(reg_idx, thread->threadId()); default: panic("Unsupported width!"); return 0; @@ -316,7 +317,7 @@ TheISA::FloatReg O3ThreadContext::readFloatReg(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); } template @@ -325,7 +326,7 @@ O3ThreadContext::readFloatRegBits(int reg_idx, int width) { DPRINTF(Fault, "Reading floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template @@ -333,7 +334,7 @@ TheISA::FloatRegBits O3ThreadContext::readFloatRegBits(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); + return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template @@ -341,11 +342,11 @@ void O3ThreadContext::setIntReg(int reg_idx, uint64_t val) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); - cpu->setArchIntReg(reg_idx, val, thread->readTid()); + cpu->setArchIntReg(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -356,16 +357,16 @@ O3ThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); break; case 64: - cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId()); break; } // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -374,10 +375,10 @@ void O3ThreadContext::setFloatReg(int reg_idx, FloatReg val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -388,11 +389,11 @@ O3ThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, { DPRINTF(Fault, "Setting floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -401,11 +402,11 @@ void O3ThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); - cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -413,11 +414,11 @@ template void O3ThreadContext::setPC(uint64_t val) { - cpu->setPC(val, thread->readTid()); + cpu->setPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -425,11 +426,11 @@ template void O3ThreadContext::setNextPC(uint64_t val) { - cpu->setNextPC(val, thread->readTid()); + cpu->setNextPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -437,11 +438,11 @@ template void O3ThreadContext::setMicroPC(uint64_t val) { - cpu->setMicroPC(val, thread->readTid()); + cpu->setMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -449,11 +450,11 @@ template void O3ThreadContext::setNextMicroPC(uint64_t val) { - cpu->setNextMicroPC(val, thread->readTid()); + cpu->setNextMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -461,11 +462,11 @@ template void O3ThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { - cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); + cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -474,11 +475,11 @@ void O3ThreadContext::setMiscReg(int misc_reg, const MiscReg &val) { - cpu->setMiscReg(misc_reg, val, thread->readTid()); + cpu->setMiscReg(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromTC(thread->readTid()); + cpu->squashFromTC(thread->threadId()); } } @@ -488,21 +489,21 @@ template TheISA::IntReg O3ThreadContext::getSyscallArg(int i) { - return cpu->getSyscallArg(i, thread->readTid()); + return cpu->getSyscallArg(i, thread->threadId()); } template void O3ThreadContext::setSyscallArg(int i, IntReg val) { - cpu->setSyscallArg(i, val, thread->readTid()); + cpu->setSyscallArg(i, val, thread->threadId()); } template void O3ThreadContext::setSyscallReturn(SyscallReturn return_value) { - cpu->setSyscallReturn(return_value, thread->readTid()); + cpu->setSyscallReturn(return_value, thread->threadId()); } #endif // FULL_SYSTEM diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 8fce61d4f..cc371ed93 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -176,7 +176,7 @@ class OzoneCPU : public BaseCPU void profileSample(); #endif - int getThreadNum(); + int threadId(); // Also somewhat obnoxious. Really only used for the TLB fault. TheISA::MachInst getInst(); @@ -260,7 +260,7 @@ class OzoneCPU : public BaseCPU } void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->readTid()); } + { cpu->setSyscallReturn(return_value, thread->threadId()); } Counter readFuncExeInst() { return thread->funcExeInst; } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index eef1a7b2f..93848c03f 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -588,7 +588,7 @@ OzoneCPU::postInterrupt(int int_num, int index) // thread.activate(); // Hack for now. Otherwise might have to go through the tc, or // I need to figure out what's the right thing to call. - activateContext(thread.readTid(), 1); + activateContext(thread.threadId(), 1); } } #endif // FULL_SYSTEM @@ -711,7 +711,7 @@ OzoneCPU::simPalCheck(int palFunc) switch (palFunc) { case PAL::halt: - haltContext(thread.readTid()); + haltContext(thread.threadId()); if (--System::numSystemsRunning == 0) exitSimLoop("all cpus halted"); break; @@ -745,7 +745,7 @@ template void OzoneCPU::OzoneTC::activate(int delay) { - cpu->activateContext(thread->readTid(), delay); + cpu->activateContext(thread->threadId(), delay); } /// Set the status to Suspended. @@ -753,7 +753,7 @@ template void OzoneCPU::OzoneTC::suspend() { - cpu->suspendContext(thread->readTid()); + cpu->suspendContext(thread->threadId()); } /// Set the status to Unallocated. @@ -761,7 +761,7 @@ template void OzoneCPU::OzoneTC::deallocate(int delay) { - cpu->deallocateContext(thread->readTid(), delay); + cpu->deallocateContext(thread->threadId(), delay); } /// Set the status to Halted. @@ -769,7 +769,7 @@ template void OzoneCPU::OzoneTC::halt() { - cpu->haltContext(thread->readTid()); + cpu->haltContext(thread->threadId()); } #if FULL_SYSTEM @@ -884,9 +884,9 @@ OzoneCPU::OzoneTC::profileSample() template int -OzoneCPU::OzoneTC::getThreadNum() +OzoneCPU::OzoneTC::threadId() { - return thread->readTid(); + return thread->threadId(); } template diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 5c6b729b6..af0bb4490 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -183,6 +183,7 @@ SimpleThread::copyState(ThreadContext *oldContext) #endif inst = oldContext->getInst(); + _threadId = oldContext->threadId(); _contextId = oldContext->contextId(); } @@ -221,14 +222,14 @@ SimpleThread::activate(int delay) lastActivate = curTick; // if (status() == ThreadContext::Unallocated) { -// cpu->activateWhenReady(tid); +// cpu->activateWhenReady(_threadId); // return; // } _status = ThreadContext::Active; // status() == Suspended - cpu->activateContext(tid, delay); + cpu->activateContext(_threadId, delay); } void @@ -249,7 +250,7 @@ SimpleThread::suspend() #endif */ _status = ThreadContext::Suspended; - cpu->suspendContext(tid); + cpu->suspendContext(_threadId); } void @@ -259,7 +260,7 @@ SimpleThread::deallocate() return; _status = ThreadContext::Unallocated; - cpu->deallocateContext(tid); + cpu->deallocateContext(_threadId); } void @@ -269,7 +270,7 @@ SimpleThread::halt() return; _status = ThreadContext::Halted; - cpu->haltContext(tid); + cpu->haltContext(_threadId); } diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 189cbeec5..a503ab600 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -197,8 +197,6 @@ class SimpleThread : public ThreadState BaseCPU *getCpuPtr() { return cpu; } - int getThreadNum() { return tid; } - TheISA::ITB *getITBPtr() { return itb; } TheISA::DTB *getDTBPtr() { return dtb; } diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index a94be7024..9ee5250a3 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -117,7 +117,9 @@ class ThreadContext virtual int cpuId() = 0; - virtual int getThreadNum() = 0; + virtual int threadId() = 0; + + virtual void setThreadId(int id) = 0; virtual int contextId() = 0; @@ -304,7 +306,9 @@ class ProxyThreadContext : public ThreadContext int cpuId() { return actualTC->cpuId(); } - int getThreadNum() { return actualTC->getThreadNum(); } + int threadId() { return actualTC->threadId(); } + + void setThreadId(int id) { return actualTC->setThreadId(id); } int contextId() { return actualTC->contextId(); } diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 47841922e..b0e719ddf 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -44,14 +44,14 @@ #if FULL_SYSTEM ThreadState::ThreadState(BaseCPU *cpu, int _tid) - : baseCpu(cpu), tid(_tid), lastActivate(0), lastSuspend(0), + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), kernelStats(NULL), physPort(NULL), virtPort(NULL), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #else ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process, short _asid) - : baseCpu(cpu), tid(_tid), lastActivate(0), lastSuspend(0), + : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0), port(NULL), process(_process), asid(_asid), microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0) #endif @@ -129,7 +129,7 @@ ThreadState::connectPhysPort() physPort->removeConn(); else physPort = new FunctionalPort(csprintf("%s-%d-funcport", - baseCpu->name(), tid)); + baseCpu->name(), _threadId)); connectToMemFunc(physPort); } @@ -143,7 +143,7 @@ ThreadState::connectVirtPort(ThreadContext *tc) virtPort->removeConn(); else virtPort = new VirtualPort(csprintf("%s-%d-vport", - baseCpu->name(), tid), tc); + baseCpu->name(), _threadId), tc); connectToMemFunc(virtPort); } @@ -169,7 +169,7 @@ ThreadState::getMemPort() return port; /* Use this port to for syscall emulation writes to memory. */ - port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid), + port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), _threadId), process, TranslatingPort::NextPage); connectToMemFunc(port); diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index fdb2ab0ab..4465ce635 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -84,9 +84,9 @@ struct ThreadState { void setContextId(int id) { _contextId = id; } - void setTid(int id) { tid = id; } + void setThreadId(int id) { _threadId = id; } - int readTid() { return tid; } + int threadId() { return _threadId; } Tick readLastActivate() { return lastActivate; } @@ -177,7 +177,7 @@ struct ThreadState { int _contextId; // Index of hardware thread context on the CPU that this represents. - int tid; + int _threadId; public: /** Last time activate was called on this thread. */ -- cgit v1.2.3 From 07969dbbf1a737e666b5ba6d34cd7cf2b403a9ad Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Wed, 5 Nov 2008 15:30:49 -0500 Subject: Right now a single thread cpu 1 could get assigned context Id != 1, depending on the order in which it's registered with the system. To make them match, here is a little change. --- src/cpu/base.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 1fa7add65..167606135 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -285,7 +285,17 @@ BaseCPU::registerThreadContexts() for (int i = 0; i < threadContexts.size(); ++i) { ThreadContext *tc = threadContexts[i]; - tc->setContextId(system->registerThreadContext(tc)); + /** This is so that contextId and cpuId match where there is a + * 1cpu:1context relationship. Otherwise, the order of registration + * could affect the assignment and cpu 1 could have context id 3, for + * example. We may even want to do something like this for SMT so that + * cpu 0 has the lowest thread contexts and cpu N has the highest, but + * I'll just do this for now + */ + if (number_of_threads == 1) + tc->setContextId(system->registerThreadContext(tc, _cpuId)); + else + tc->setContextId(system->registerThreadContext(tc)); #if !FULL_SYSTEM tc->getProcessPtr()->assignThreadContext(tc->contextId()); #endif -- cgit v1.2.3 From 909380f3ee576f915f52c6245c59d41050a46f49 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 9 Nov 2008 21:55:01 -0800 Subject: X86: Make the timing simple CPU handle variable length instructions. --- src/cpu/simple/timing.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index ca1f0283e..f5eeeba60 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -561,7 +561,8 @@ TimingSimpleCPU::fetch() void TimingSimpleCPU::advanceInst(Fault fault) { - advancePC(fault); + if (fault != NoFault || !stayAtPC) + advancePC(fault); if (_status == Running) { // kick off fetch of next instruction... callback from icache @@ -599,7 +600,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) } preExecute(); - if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { + if (curStaticInst && + curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { // load or store: just send to dcache Fault fault = curStaticInst->initiateAcc(this, traceData); if (_status != Running) { @@ -638,7 +640,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) instCnt++; advanceInst(fault); } - } else { + } else if (curStaticInst) { // non-memory instruction: execute completely now Fault fault = curStaticInst->execute(this, traceData); @@ -657,6 +659,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) curStaticInst->isFirstMicroop())) instCnt++; advanceInst(fault); + } else { + advanceInst(NoFault); } if (pkt) { -- cgit v1.2.3 From 846cb450f985eb249a5fc50e97f9e643cb1ebfc5 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 9 Nov 2008 21:56:28 -0800 Subject: CPU: Make unaligned accesses work in the timing simple CPU. --- src/cpu/simple/timing.cc | 366 +++++++++++++++++++++++++++++++++++++---------- src/cpu/simple/timing.hh | 57 ++++++++ 2 files changed, 347 insertions(+), 76 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index f5eeeba60..5d37fa620 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -241,57 +241,135 @@ TimingSimpleCPU::suspendContext(int thread_num) _status = Idle; } +bool +TimingSimpleCPU::handleReadPacket(PacketPtr pkt) +{ + RequestPtr req = pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprRead(thread->getTC(), pkt); + new IprEvent(pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(pkt)) { + _status = DcacheRetry; + dcache_pkt = pkt; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} template Fault TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - _cpuId, /* thread ID */ 0); - - if (traceData) { - traceData->setAddr(req->getVaddr()); - } + Fault fault; + const int asid = 0; + const int thread_id = 0; + const Addr pc = thread->readPC(); + + PacketPtr pkt; + RequestPtr req; + + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + Addr second_addr = roundDown(addr + data_size - 1, block_size); + + if (second_addr > addr) { + Addr first_size = second_addr - addr; + Addr second_size = data_size - first_size; + // Make sure we'll only need two accesses. + assert(roundDown(second_addr + second_size - 1, block_size) == + second_addr); + + /* + * Do the translations. If something isn't going to work, find out + * before we waste time setting up anything else. + */ + req = new Request(asid, addr, first_size, + flags, pc, _cpuId, thread_id); + fault = thread->translateDataReadReq(req); + if (fault != NoFault) { + delete req; + return fault; + } + Request *second_req = + new Request(asid, second_addr, second_size, + flags, pc, _cpuId, thread_id); + fault = thread->translateDataReadReq(second_req); + if (fault != NoFault) { + delete req; + delete second_req; + return fault; + } - // translate to physical address - Fault fault = thread->translateDataReadReq(req); + T * data_ptr = new T; + + /* + * This is the big packet that will hold the data we've gotten so far, + * if any, and also act as the response we actually give to the + * instruction. + */ + Request *orig_req = + new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); + orig_req->setPhys(req->getPaddr(), data_size, flags); + PacketPtr big_pkt = + new Packet(orig_req, MemCmd::ReadResp, Packet::Broadcast); + big_pkt->dataDynamic(data_ptr); + SplitMainSenderState * main_send_state = new SplitMainSenderState; + big_pkt->senderState = main_send_state; + main_send_state->outstanding = 2; + + // This is the packet we'll process now. + pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); + pkt->dataStatic((uint8_t *)data_ptr); + pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); + + // This is the second half of the access we'll deal with later. + PacketPtr second_pkt = + new Packet(second_req, MemCmd::ReadReq, Packet::Broadcast); + second_pkt->dataStatic((uint8_t *)data_ptr + first_size); + second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); + if (!handleReadPacket(pkt)) { + main_send_state->fragments[1] = second_pkt; + } else { + handleReadPacket(second_pkt); + } + } else { + req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); - // Now do the access. - if (fault == NoFault) { - PacketPtr pkt = - new Packet(req, - (req->isLocked() ? - MemCmd::LoadLockedReq : MemCmd::ReadReq), - Packet::Broadcast); - pkt->dataDynamic(new T); + // translate to physical address + Fault fault = thread->translateDataReadReq(req); - if (req->isMmapedIpr()) { - Tick delay; - delay = TheISA::handleIprRead(thread->getTC(), pkt); - new IprEvent(pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(pkt)) { - _status = DcacheRetry; - dcache_pkt = pkt; - } else { - _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; + if (fault != NoFault) { + delete req; + return fault; } - // This will need a new way to tell if it has a dcache attached. - if (req->isUncacheable()) - recordEvent("Uncached Read"); - } else { - delete req; + pkt = new Packet(req, + (req->isLocked() ? + MemCmd::LoadLockedReq : MemCmd::ReadReq), + Packet::Broadcast); + pkt->dataDynamic(new T); + + handleReadPacket(pkt); } if (traceData) { traceData->setData(data); + traceData->setAddr(addr); } - return fault; + + // This will need a new way to tell if it has a dcache attached. + if (req->isUncacheable()) + recordEvent("Uncached Read"); + + return NoFault; } Fault @@ -364,26 +442,117 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) return read(addr, (uint32_t&)data, flags); } +bool +TimingSimpleCPU::handleWritePacket() +{ + RequestPtr req = dcache_pkt->req; + if (req->isMmapedIpr()) { + Tick delay; + delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); + new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } else if (!dcachePort.sendTiming(dcache_pkt)) { + _status = DcacheRetry; + } else { + _status = DcacheWaitResponse; + // memory system takes ownership of packet + dcache_pkt = NULL; + } + return dcache_pkt == NULL; +} template Fault TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { - Request *req = - new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), - _cpuId, /* thread ID */ 0); + const int asid = 0; + const int thread_id = 0; + bool do_access = true; // flag to suppress cache access + const Addr pc = thread->readPC(); + + RequestPtr req; + + int block_size = dcachePort.peerBlockSize(); + int data_size = sizeof(T); + + Addr second_addr = roundDown(addr + data_size - 1, block_size); + + if (second_addr > addr) { + Fault fault; + Addr first_size = second_addr - addr; + Addr second_size = data_size - first_size; + // Make sure we'll only need two accesses. + assert(roundDown(second_addr + second_size - 1, block_size) == + second_addr); + + req = new Request(asid, addr, first_size, + flags, pc, _cpuId, thread_id); + fault = thread->translateDataWriteReq(req); + if (fault != NoFault) { + delete req; + return fault; + } + RequestPtr second_req = new Request(asid, second_addr, second_size, + flags, pc, _cpuId, thread_id); + fault = thread->translateDataWriteReq(second_req); + if (fault != NoFault) { + delete req; + delete second_req; + return fault; + } - if (traceData) { - traceData->setAddr(req->getVaddr()); - } + if (req->isLocked() || req->isSwap() || + second_req->isLocked() || second_req->isSwap()) { + panic("LL/SCs and swaps can't be split."); + } - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); + T * data_ptr = new T; + + /* + * This is the big packet that will hold the data we've gotten so far, + * if any, and also act as the response we actually give to the + * instruction. + */ + RequestPtr orig_req = + new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); + orig_req->setPhys(req->getPaddr(), data_size, flags); + PacketPtr big_pkt = + new Packet(orig_req, MemCmd::WriteResp, Packet::Broadcast); + big_pkt->dataDynamic(data_ptr); + big_pkt->set(data); + SplitMainSenderState * main_send_state = new SplitMainSenderState; + big_pkt->senderState = main_send_state; + main_send_state->outstanding = 2; + + assert(dcache_pkt == NULL); + // This is the packet we'll process now. + dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); + dcache_pkt->dataStatic((uint8_t *)data_ptr); + dcache_pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); + + // This is the second half of the access we'll deal with later. + PacketPtr second_pkt = + new Packet(second_req, MemCmd::WriteReq, Packet::Broadcast); + second_pkt->dataStatic((uint8_t *)data_ptr + first_size); + second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); + if (!handleWritePacket()) { + main_send_state->fragments[1] = second_pkt; + } else { + dcache_pkt = second_pkt; + handleWritePacket(); + } + } else { + req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); + + // translate to physical address + Fault fault = thread->translateDataWriteReq(req); + if (fault != NoFault) { + delete req; + return fault; + } - // Now do the access. - if (fault == NoFault) { MemCmd cmd = MemCmd::WriteReq; // default - bool do_access = true; // flag to suppress cache access if (req->isLocked()) { cmd = MemCmd::StoreCondReq; @@ -401,38 +570,27 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) assert(dcache_pkt == NULL); dcache_pkt = new Packet(req, cmd, Packet::Broadcast); dcache_pkt->allocate(); - dcache_pkt->set(data); - - if (do_access) { - if (req->isMmapedIpr()) { - Tick delay; - dcache_pkt->set(htog(data)); - delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); - new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); - _status = DcacheWaitResponse; - dcache_pkt = NULL; - } else if (!dcachePort.sendTiming(dcache_pkt)) { - _status = DcacheRetry; - } else { - _status = DcacheWaitResponse; - // memory system takes ownership of packet - dcache_pkt = NULL; - } - } - // This will need a new way to tell if it's hooked up to a cache or not. - if (req->isUncacheable()) - recordEvent("Uncached Write"); - } else { - delete req; + if (req->isMmapedIpr()) + dcache_pkt->set(htog(data)); + else + dcache_pkt->set(data); + + if (do_access) + handleWritePacket(); } if (traceData) { + traceData->setAddr(req->getVaddr()); traceData->setData(data); } + // This will need a new way to tell if it's hooked up to a cache or not. + if (req->isUncacheable()) + recordEvent("Uncached Write"); + // If the write needs to have a fault on the access, consider calling // changeStatus() and changing it to "bad addr write" or something. - return fault; + return NoFault; } Fault @@ -721,12 +879,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) // received a response from the dcache: complete the load or store // instruction assert(!pkt->isError()); - assert(_status == DcacheWaitResponse); - _status = Running; numCycles += tickToCycles(curTick - previousTick); previousTick = curTick; + if (pkt->senderState) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt->senderState); + assert(send_state); + delete pkt->req; + delete pkt; + PacketPtr big_pkt = send_state->bigPkt; + delete send_state; + + SplitMainSenderState * main_send_state = + dynamic_cast(big_pkt->senderState); + assert(main_send_state); + // Record the fact that this packet is no longer outstanding. + assert(main_send_state->outstanding != 0); + main_send_state->outstanding--; + + if (main_send_state->outstanding) { + return; + } else { + delete main_send_state; + big_pkt->senderState = NULL; + pkt = big_pkt; + } + } + + assert(_status == DcacheWaitResponse); + _status = Running; + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); // keep an instruction count @@ -787,10 +971,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) // delay processing of returned data until next CPU clock edge Tick next_tick = cpu->nextCycle(curTick); - if (next_tick == curTick) + if (next_tick == curTick) { cpu->completeDataAccess(pkt); - else + } else { tickEvent.schedule(pkt, next_tick); + } return true; } @@ -820,7 +1005,36 @@ TimingSimpleCPU::DcachePort::recvRetry() assert(cpu->dcache_pkt != NULL); assert(cpu->_status == DcacheRetry); PacketPtr tmp = cpu->dcache_pkt; - if (sendTiming(tmp)) { + if (tmp->senderState) { + // This is a packet from a split access. + SplitFragmentSenderState * send_state = + dynamic_cast(tmp->senderState); + assert(send_state); + PacketPtr big_pkt = send_state->bigPkt; + + SplitMainSenderState * main_send_state = + dynamic_cast(big_pkt->senderState); + assert(main_send_state); + + if (sendTiming(tmp)) { + // If we were able to send without retrying, record that fact + // and try sending the other fragment. + send_state->clearFromParent(); + int other_index = main_send_state->getPendingFragment(); + if (other_index > 0) { + tmp = main_send_state->fragments[other_index]; + cpu->dcache_pkt = tmp; + if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || + (big_pkt->isWrite() && cpu->handleWritePacket())) { + main_send_state->fragments[other_index] = NULL; + } + } else { + cpu->_status = DcacheWaitResponse; + // memory system takes ownership of packet + cpu->dcache_pkt = NULL; + } + } + } else if (sendTiming(tmp)) { cpu->_status = DcacheWaitResponse; // memory system takes ownership of packet cpu->dcache_pkt = NULL; diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 0fc9b3152..b641b1302 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -49,6 +49,63 @@ class TimingSimpleCPU : public BaseSimpleCPU private: + /* + * If an access needs to be broken into fragments, currently at most two, + * the the following two classes are used as the sender state of the + * packets so the CPU can keep track of everything. In the main packet + * sender state, there's an array with a spot for each fragment. If a + * fragment has already been accepted by the CPU, aka isn't waiting for + * a retry, it's pointer is NULL. After each fragment has successfully + * been processed, the "outstanding" counter is decremented. Once the + * count is zero, the entire larger access is complete. + */ + class SplitMainSenderState : public Packet::SenderState + { + public: + int outstanding; + PacketPtr fragments[2]; + + SplitMainSenderState() + { + fragments[0] = NULL; + fragments[1] = NULL; + } + + int + getPendingFragment() + { + if (fragments[0]) { + return 0; + } else if (fragments[1]) { + return 1; + } else { + return -1; + } + } + }; + + class SplitFragmentSenderState : public Packet::SenderState + { + public: + SplitFragmentSenderState(PacketPtr _bigPkt, int _index) : + bigPkt(_bigPkt), index(_index) + {} + PacketPtr bigPkt; + int index; + + void + clearFromParent() + { + SplitMainSenderState * main_send_state = + dynamic_cast(bigPkt->senderState); + main_send_state->fragments[index] = NULL; + } + }; + + bool handleReadPacket(PacketPtr pkt); + // This function always implicitly uses dcache_pkt. + bool handleWritePacket(); + class CpuPort : public Port { protected: -- cgit v1.2.3 From 9c49bc7b00aa24b0488a83039ae8762d8f8094c5 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 10 Nov 2008 11:51:17 -0800 Subject: mem: update stuff for changes to Packet and Request --- src/cpu/memtest/memtest.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc index 9e5b9d099..3c57f85b7 100644 --- a/src/cpu/memtest/memtest.cc +++ b/src/cpu/memtest/memtest.cc @@ -279,7 +279,7 @@ MemTest::tick() unsigned base = random() % 2; uint64_t data = random(); unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; + bool uncacheable = (random() % 100) < percentUncacheable; //If we aren't doing copies, use id as offset, and do a false sharing //mem tester @@ -290,17 +290,16 @@ MemTest::tick() access_size = 0; Request *req = new Request(); - uint32_t flags = 0; + Request::Flags flags; Addr paddr; - if (cacheable < percentUncacheable) { - flags |= UNCACHEABLE; + if (uncacheable) { + flags.set(Request::UNCACHEABLE); paddr = uncacheAddr + offset; } else { paddr = ((base) ? baseAddr1 : baseAddr2) + offset; } - bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE); - //bool probe = false; + bool probe = (random() % 100 < percentFunctional) && !uncacheable; paddr &= ~((1 << access_size) - 1); req->setPhys(paddr, 1 << access_size, flags); -- cgit v1.2.3 From 1adfe5c7f3368c4225ff685ddcd66b6280c7599f Mon Sep 17 00:00:00 2001 From: Clint Smullen Date: Mon, 10 Nov 2008 11:51:18 -0800 Subject: O3CPU: Make the instcount debugging stuff per-cpu. This is to prevent the assertion from firing if you have a large multicore. Also make sure that it's not compiled in when NDEBUG is defined --- src/cpu/base_dyn_inst.hh | 3 --- src/cpu/base_dyn_inst_impl.hh | 22 ++++++++++++++-------- src/cpu/o3/base_dyn_inst.cc | 4 ---- src/cpu/o3/cpu.cc | 3 +++ src/cpu/o3/cpu.hh | 5 +++++ src/cpu/ozone/base_dyn_inst.cc | 4 ---- src/cpu/ozone/cpu.hh | 5 +++++ src/cpu/ozone/cpu_impl.hh | 3 +++ 8 files changed, 30 insertions(+), 19 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 3520fafaa..f40616e54 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -258,9 +258,6 @@ class BaseDynInst : public FastAlloc, public RefCounted public: - /** Count of total number of dynamic instructions. */ - static int instcount; - #ifdef DEBUG void dumpSNList(); #endif diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 66075c60a..4ee7d2f2c 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -168,18 +168,21 @@ BaseDynInst::initVars() // Initialize the fault to be NoFault. fault = NoFault; - ++instcount; +#ifndef NDEBUG + ++cpu->instcount; - if (instcount > 1500) { + if (cpu->instcount > 1500) { #ifdef DEBUG cpu->dumpInsts(); dumpSNList(); #endif - assert(instcount <= 1500); + assert(cpu->instcount <= 1500); } - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.insert(seqNum); @@ -199,10 +202,13 @@ BaseDynInst::~BaseDynInst() fault = NoFault; - --instcount; +#ifndef NDEBUG + --cpu->instcount; - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", - seqNum, instcount); + DPRINTF(DynInst, + "DynInst: [sn:%lli] Instruction destroyed. Instcount for %s = %i\n", + seqNum, cpu->name(), cpu->instcount); +#endif #ifdef DEBUG cpu->snList.erase(seqNum); #endif diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc index 3cf89e1b6..510109d8a 100644 --- a/src/cpu/o3/base_dyn_inst.cc +++ b/src/cpu/o3/base_dyn_inst.cc @@ -34,7 +34,3 @@ // Explicit instantiation template class BaseDynInst; - -template <> -int -BaseDynInst::instcount = 0; diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 26c155262..7320d5638 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -159,6 +159,9 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) itb(params->itb), dtb(params->dtb), tickEvent(this), +#ifndef NDEBUG + instcount(0), +#endif removeInstsThisCycle(false), fetch(this, params), decode(this, params), diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index c60c20d55..d24e8c383 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -576,6 +576,11 @@ class FullO3CPU : public BaseO3CPU void dumpInsts(); public: +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + /** List of all the instructions in flight. */ std::list instList; diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc index 5a3a69dff..e0570fd16 100644 --- a/src/cpu/ozone/base_dyn_inst.cc +++ b/src/cpu/ozone/base_dyn_inst.cc @@ -33,7 +33,3 @@ // Explicit instantiation template class BaseDynInst; - -template <> -int -BaseDynInst::instcount = 0; diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index cc371ed93..6b5e7282d 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -287,6 +287,11 @@ class OzoneCPU : public BaseCPU // main simulation loop (one cycle) void tick(); +#ifndef NDEBUG + /** Count of total number of dynamic instructions in flight. */ + int instcount; +#endif + std::set snList; std::set lockAddrList; private: diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 93848c03f..1402f4b72 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -94,6 +94,9 @@ OzoneCPU::OzoneCPU(Params *p) #else : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), +#endif +#ifndef NDEBUG + instcount(0), #endif comm(5, 5) { -- cgit v1.2.3 From 7a4d75bae31cfe2064fe0718c7f982f769659b3c Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 13 Nov 2008 23:30:37 -0800 Subject: CPU: Refactor read/write in the simple timing CPU. --- src/cpu/simple/timing.cc | 277 ++++++++++++++++++++--------------------------- src/cpu/simple/timing.hh | 10 +- 2 files changed, 119 insertions(+), 168 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 5d37fa620..5da08db47 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -262,6 +262,72 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt) return dcache_pkt == NULL; } +Fault +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr &req, Addr split_addr, uint8_t *data, bool read) +{ + Fault fault; + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + pkt1 = pkt2 = NULL; + if ((fault = buildPacket(pkt1, req1, read)) != NoFault || + (fault = buildPacket(pkt2, req2, read)) != NoFault) { + delete req; + delete pkt1; + req = NULL; + pkt1 = NULL; + return fault; + } + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic(data); + pkt1->dataStatic(data); + pkt2->dataStatic(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); + return fault; +} + +Fault +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) +{ + Fault fault = read ? thread->translateDataReadReq(req) : + thread->translateDataWriteReq(req); + MemCmd cmd; + if (fault != NoFault) { + delete req; + req = NULL; + pkt = NULL; + return fault; + } else if (read) { + cmd = MemCmd::ReadReq; + if (req->isLocked()) + cmd = MemCmd::LoadLockedReq; + } else { + cmd = MemCmd::WriteReq; + if (req->isLocked()) { + cmd = MemCmd::StoreCondReq; + } else if (req->isSwap()) { + cmd = MemCmd::SwapReq; + } + } + pkt = new Packet(req, cmd, Packet::Broadcast); + return NoFault; +} + template Fault TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) @@ -270,91 +336,35 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) const int asid = 0; const int thread_id = 0; const Addr pc = thread->readPC(); - - PacketPtr pkt; - RequestPtr req; - int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - Addr second_addr = roundDown(addr + data_size - 1, block_size); - - if (second_addr > addr) { - Addr first_size = second_addr - addr; - Addr second_size = data_size - first_size; - // Make sure we'll only need two accesses. - assert(roundDown(second_addr + second_size - 1, block_size) == - second_addr); - - /* - * Do the translations. If something isn't going to work, find out - * before we waste time setting up anything else. - */ - req = new Request(asid, addr, first_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataReadReq(req); - if (fault != NoFault) { - delete req; - return fault; - } - Request *second_req = - new Request(asid, second_addr, second_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataReadReq(second_req); - if (fault != NoFault) { - delete req; - delete second_req; - return fault; - } - - T * data_ptr = new T; - - /* - * This is the big packet that will hold the data we've gotten so far, - * if any, and also act as the response we actually give to the - * instruction. - */ - Request *orig_req = - new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); - orig_req->setPhys(req->getPaddr(), data_size, flags); - PacketPtr big_pkt = - new Packet(orig_req, MemCmd::ReadResp, Packet::Broadcast); - big_pkt->dataDynamic(data_ptr); - SplitMainSenderState * main_send_state = new SplitMainSenderState; - big_pkt->senderState = main_send_state; - main_send_state->outstanding = 2; - - // This is the packet we'll process now. - pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); - pkt->dataStatic((uint8_t *)data_ptr); - pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); - - // This is the second half of the access we'll deal with later. - PacketPtr second_pkt = - new Packet(second_req, MemCmd::ReadReq, Packet::Broadcast); - second_pkt->dataStatic((uint8_t *)data_ptr + first_size); - second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); - if (!handleReadPacket(pkt)) { - main_send_state->fragments[1] = second_pkt; - } else { - handleReadPacket(second_pkt); + PacketPtr pkt; + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + if (split_addr > addr) { + PacketPtr pkt1, pkt2; + this->buildSplitPacket(pkt1, pkt2, req, + split_addr, (uint8_t *)(new T), true); + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + } } } else { - req = new Request(asid, addr, data_size, - flags, pc, _cpuId, thread_id); - - // translate to physical address - Fault fault = thread->translateDataReadReq(req); - + Fault fault = buildPacket(pkt, req, true); if (fault != NoFault) { - delete req; return fault; } - - pkt = new Packet(req, - (req->isLocked() ? - MemCmd::LoadLockedReq : MemCmd::ReadReq), - Packet::Broadcast); pkt->dataDynamic(new T); handleReadPacket(pkt); @@ -468,107 +478,50 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { const int asid = 0; const int thread_id = 0; - bool do_access = true; // flag to suppress cache access const Addr pc = thread->readPC(); - - RequestPtr req; - int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - Addr second_addr = roundDown(addr + data_size - 1, block_size); + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); - if (second_addr > addr) { - Fault fault; - Addr first_size = second_addr - addr; - Addr second_size = data_size - first_size; - // Make sure we'll only need two accesses. - assert(roundDown(second_addr + second_size - 1, block_size) == - second_addr); + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); - req = new Request(asid, addr, first_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataWriteReq(req); - if (fault != NoFault) { - delete req; - return fault; - } - RequestPtr second_req = new Request(asid, second_addr, second_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataWriteReq(second_req); - if (fault != NoFault) { - delete req; - delete second_req; + if (split_addr > addr) { + PacketPtr pkt1, pkt2; + T *dataP = new T; + *dataP = data; + Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr, + (uint8_t *)dataP, false); + if (fault != NoFault) return fault; - } - - if (req->isLocked() || req->isSwap() || - second_req->isLocked() || second_req->isSwap()) { - panic("LL/SCs and swaps can't be split."); - } - - T * data_ptr = new T; - - /* - * This is the big packet that will hold the data we've gotten so far, - * if any, and also act as the response we actually give to the - * instruction. - */ - RequestPtr orig_req = - new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); - orig_req->setPhys(req->getPaddr(), data_size, flags); - PacketPtr big_pkt = - new Packet(orig_req, MemCmd::WriteResp, Packet::Broadcast); - big_pkt->dataDynamic(data_ptr); - big_pkt->set(data); - SplitMainSenderState * main_send_state = new SplitMainSenderState; - big_pkt->senderState = main_send_state; - main_send_state->outstanding = 2; - - assert(dcache_pkt == NULL); - // This is the packet we'll process now. - dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); - dcache_pkt->dataStatic((uint8_t *)data_ptr); - dcache_pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); - - // This is the second half of the access we'll deal with later. - PacketPtr second_pkt = - new Packet(second_req, MemCmd::WriteReq, Packet::Broadcast); - second_pkt->dataStatic((uint8_t *)data_ptr + first_size); - second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); - if (!handleWritePacket()) { - main_send_state->fragments[1] = second_pkt; - } else { - dcache_pkt = second_pkt; - handleWritePacket(); + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleReadPacket(pkt2)) { + send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + } } } else { - req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); + bool do_access = true; // flag to suppress cache access - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - if (fault != NoFault) { - delete req; + Fault fault = buildPacket(dcache_pkt, req, false); + if (fault != NoFault) return fault; - } - - MemCmd cmd = MemCmd::WriteReq; // default if (req->isLocked()) { - cmd = MemCmd::StoreCondReq; do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isSwap()) { - cmd = MemCmd::SwapReq; - if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); } - // Note: need to allocate dcache_pkt even if do_access is - // false, as it's used unconditionally to call completeAcc(). - assert(dcache_pkt == NULL); - dcache_pkt = new Packet(req, cmd, Packet::Broadcast); dcache_pkt->allocate(); if (req->isMmapedIpr()) dcache_pkt->set(htog(data)); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index b641b1302..c305d0361 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -65,12 +65,6 @@ class TimingSimpleCPU : public BaseSimpleCPU int outstanding; PacketPtr fragments[2]; - SplitMainSenderState() - { - fragments[0] = NULL; - fragments[1] = NULL; - } - int getPendingFragment() { @@ -102,6 +96,10 @@ class TimingSimpleCPU : public BaseSimpleCPU } }; + Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req, + Addr split_addr, uint8_t *data, bool read); + Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read); + bool handleReadPacket(PacketPtr pkt); // This function always implicitly uses dcache_pkt. bool handleWritePacket(); -- cgit v1.2.3 From 489e3e7381993e5b34d83a839303cf204c4f53b6 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sat, 6 Dec 2008 14:18:18 -0800 Subject: eventq: use the flags data structure --- src/cpu/o3/commit_impl.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index 46c4158f6..e215fe49e 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -53,7 +53,7 @@ DefaultCommit::TrapEvent::TrapEvent(DefaultCommit *_commit, unsigned _tid) : Event(CPU_Tick_Pri), commit(_commit), tid(_tid) { - this->setFlags(Event::AutoDelete); + this->setFlags(AutoDelete); } template -- cgit v1.2.3 From 02cd18f536544d4b5fa19681b4c9dbd5b2cb87ff Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 16 Dec 2008 23:06:37 -0800 Subject: SPARC: Truncate syscall args and return values appropriately. --- src/cpu/simple_thread.hh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index a503ab600..4831b701a 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -385,8 +385,15 @@ class SimpleThread : public ThreadState TheISA::IntReg getSyscallArg(int i) { assert(i < TheISA::NumArgumentRegs); - return regs.readIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i])); + TheISA::IntReg val = regs.readIntReg( + TheISA::flattenIntIndex(getTC(), TheISA::ArgumentReg[i])); +#if THE_ISA == SPARC_ISA + if (bits(this->readMiscRegNoEffect( + SparcISA::MISCREG_PSTATE), 3, 3)) { + val = bits(val, 31, 0); + } +#endif + return val; } // used to shift args for indirect syscall -- cgit v1.2.3 From 1704ba2273d9623095ddcd269055aedb8e818e03 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Wed, 17 Dec 2008 09:51:18 -0800 Subject: Make Alpha pseudo-insts available from SE mode. --- src/cpu/BaseCPU.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index f98c6af8e..985c415a0 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -71,13 +71,14 @@ class BaseCPU(MemObject): checker = Param.BaseCPU("checker CPU") + do_checkpoint_insts = Param.Bool(True, + "enable checkpoint pseudo instructions") + do_statistics_insts = Param.Bool(True, + "enable statistics pseudo instructions") + if build_env['FULL_SYSTEM']: profile = Param.Latency('0ns', "trace the kernel stack") do_quiesce = Param.Bool(True, "enable quiesce instructions") - do_checkpoint_insts = Param.Bool(True, - "enable checkpoint pseudo instructions") - do_statistics_insts = Param.Bool(True, - "enable statistics pseudo instructions") else: workload = VectorParam.Process("processes to run") -- cgit v1.2.3 From b0ab5c894d84d4522cae3a254158e47ba112909c Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 6 Jan 2009 22:34:18 -0800 Subject: Tracing: Make tracing aware of macro and micro ops. --- src/cpu/SConscript | 4 ++- src/cpu/exetrace.cc | 69 +++++++++++++++++++++++++++++++++++++------------- src/cpu/exetrace.hh | 13 +++++++--- src/cpu/inteltrace.hh | 11 +++++--- src/cpu/legiontrace.hh | 11 +++++--- src/cpu/nativetrace.hh | 12 ++++++--- src/cpu/simple/base.cc | 5 ++-- 7 files changed, 88 insertions(+), 37 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/SConscript b/src/cpu/SConscript index 750e1ee4c..334504660 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -170,10 +170,12 @@ TraceFlag('ExecSpeculative') TraceFlag('ExecSymbol') TraceFlag('ExecThread') TraceFlag('ExecTicks') +TraceFlag('ExecMicro') +TraceFlag('ExecMacro') TraceFlag('Fetch') TraceFlag('IntrControl') TraceFlag('PCEvent') TraceFlag('Quiesce') CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread', - 'ExecEffAddr', 'ExecResult', 'ExecSymbol' ]) + 'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro' ]) diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 824fbb5f6..4c0f83a21 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -46,7 +46,7 @@ using namespace TheISA; namespace Trace { void -Trace::ExeTracerRecord::dump() +Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran) { ostream &outs = Trace::output(); @@ -61,7 +61,6 @@ Trace::ExeTracerRecord::dump() if (IsOn(ExecThread)) outs << "T" << thread->threadId() << " : "; - std::string sym_str; Addr sym_addr; if (debugSymbolTable @@ -69,36 +68,47 @@ Trace::ExeTracerRecord::dump() && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { if (PC != sym_addr) sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; + outs << "@" << sym_str; } else { - outs << "0x" << hex << PC << " : "; + outs << "0x" << hex << PC; } + if (inst->isMicroop()) { + outs << "." << setw(2) << dec << upc; + } else { + outs << " "; + } + + outs << " : "; + // // Print decoded instruction // outs << setw(26) << left; - outs << staticInst->disassemble(PC, debugSymbolTable); - outs << " : "; + outs << inst->disassemble(PC, debugSymbolTable); - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } + if (ran) { + outs << " : "; - if (IsOn(ExecResult) && data_status != DataInvalid) { - ccprintf(outs, " D=%#018x", data.as_int); - } + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[inst->opClass()] << " : "; + } - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } - if (IsOn(ExecFetchSeq) && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; - if (IsOn(ExecCPSeq) && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; + + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + } // // End of line... @@ -106,6 +116,29 @@ Trace::ExeTracerRecord::dump() outs << endl; } +void +Trace::ExeTracerRecord::dump() +{ + /* + * The behavior this check tries to achieve is that if ExecMacro is on, + * the macroop will be printed. If it's on and microops are also on, it's + * printed before the microops start printing to give context. If the + * microops aren't printed, then it's printed only when the final microop + * finishes. Macroops then behave like regular instructions and don't + * complete/print when they fault. + */ + if (IsOn(ExecMacro) && staticInst->isMicroop() && + (IsOn(ExecMicro) && + macroStaticInst && staticInst->isFirstMicroop()) || + (!IsOn(ExecMicro) && + macroStaticInst && staticInst->isLastMicroop())) { + traceInst(macroStaticInst, false); + } + if (IsOn(ExecMicro) || !staticInst->isMicroop()) { + traceInst(staticInst, true); + } +} + /* namespace Trace */ } //////////////////////////////////////////////////////////////////////// diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index 84660432b..e5b22c881 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -47,11 +47,15 @@ class ExeTracerRecord : public InstRecord { public: ExeTracerRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } + void traceInst(StaticInstPtr inst, bool ran); + void dump(); }; @@ -64,7 +68,8 @@ class ExeTracer : public InstTracer InstRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +81,7 @@ class ExeTracer : public InstTracer return NULL; return new ExeTracerRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh index 5d5bcda8e..e34658b58 100644 --- a/src/cpu/inteltrace.hh +++ b/src/cpu/inteltrace.hh @@ -47,8 +47,10 @@ class IntelTraceRecord : public InstRecord { public: IntelTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -64,7 +66,8 @@ class IntelTrace : public InstTracer IntelTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (!IsOn(ExecEnable)) return NULL; @@ -76,7 +79,7 @@ class IntelTrace : public InstTracer return NULL; return new IntelTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh index 97193ff1a..9962063e4 100644 --- a/src/cpu/legiontrace.hh +++ b/src/cpu/legiontrace.hh @@ -46,8 +46,10 @@ class LegionTraceRecord : public InstRecord { public: LegionTraceRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc) { } @@ -63,13 +65,14 @@ class LegionTrace : public InstTracer LegionTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new LegionTraceRecord(when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } }; diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh index ab038c4c3..9e912d92f 100644 --- a/src/cpu/nativetrace.hh +++ b/src/cpu/nativetrace.hh @@ -54,8 +54,11 @@ class NativeTraceRecord : public InstRecord public: NativeTraceRecord(NativeTrace * _parent, Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, Addr _pc, bool spec) - : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent) + const StaticInstPtr _staticInst, Addr _pc, bool spec, + const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) + : InstRecord(_when, _thread, _staticInst, _pc, spec, + _macroStaticInst, _upc), + parent(_parent) { } @@ -192,13 +195,14 @@ class NativeTrace : public InstTracer NativeTraceRecord * getInstRecord(Tick when, ThreadContext *tc, - const StaticInstPtr staticInst, Addr pc) + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0) { if (tc->misspeculating()) return NULL; return new NativeTraceRecord(this, when, tc, - staticInst, pc, tc->misspeculating()); + staticInst, pc, tc->misspeculating(), macroStaticInst, upc); } void diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index b3379cddb..3c154afb6 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -418,8 +418,9 @@ BaseSimpleCPU::preExecute() if(curStaticInst) { #if TRACING_ON - traceData = tracer->getInstRecord(curTick, tc, curStaticInst, - thread->readPC()); + traceData = tracer->getInstRecord(curTick, tc, + curStaticInst, thread->readPC(), + curMacroStaticInst, thread->readMicroPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", curStaticInst->getName(), curStaticInst->machInst); -- cgit v1.2.3 From 81180a3bf005586d7ca1fae77dd7888b99e45864 Mon Sep 17 00:00:00 2001 From: Richard Strong Date: Sun, 11 Jan 2009 22:45:03 -0800 Subject: This fix addresses an ill formed if statement that fails to compile. The fix was the simple addition of another set of parenthesis to ensure the correct condition resolution. --- src/cpu/exetrace.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 4c0f83a21..7227602b5 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -128,10 +128,10 @@ Trace::ExeTracerRecord::dump() * complete/print when they fault. */ if (IsOn(ExecMacro) && staticInst->isMicroop() && - (IsOn(ExecMicro) && + ((IsOn(ExecMicro) && macroStaticInst && staticInst->isFirstMicroop()) || (!IsOn(ExecMicro) && - macroStaticInst && staticInst->isLastMicroop())) { + macroStaticInst && staticInst->isLastMicroop()))) { traceInst(macroStaticInst, false); } if (IsOn(ExecMicro) || !staticInst->isMicroop()) { -- cgit v1.2.3 From 8153790d0004439f8e9d473da97699644234117b Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 13 Jan 2009 14:17:50 -0800 Subject: SCons: centralize the Dir() workaround for newer versions of scons. Scons bug id: 2006 M5 Bug id: 308 --- src/cpu/SConscript | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/SConscript b/src/cpu/SConscript index 334504660..f210cec9b 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -149,10 +149,6 @@ if env['USE_CHECKER']: print i, print ", please set USE_CHECKER=False or use one of those CPU models" Exit(1) -# Workaround for bug in SCons version > 0.97d20071212 -# Scons bug id: 2006 M5 Bug id: 308 -else: - Dir('checker') TraceFlag('Activity') TraceFlag('Commit') -- cgit v1.2.3 From dbac448b088eea12d8b20400c7a770e57e28d771 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 19 Jan 2009 20:36:49 -0800 Subject: thread_context: move getSystemPtr so SE mode can get to it. There was really no reason that it should be FS only. --- src/cpu/o3/thread_context.hh | 2 +- src/cpu/o3/thread_context_impl.hh | 3 +-- src/cpu/simple_thread.hh | 2 +- src/cpu/thread_context.hh | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 8682e071e..6de773ff1 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -86,10 +86,10 @@ class O3ThreadContext : public ThreadContext virtual int threadId() { return thread->threadId(); } virtual void setThreadId(int id) { return thread->setThreadId(id); } -#if FULL_SYSTEM /** Returns a pointer to the system. */ virtual System *getSystemPtr() { return cpu->system; } +#if FULL_SYSTEM /** Returns a pointer to physical memory. */ virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 735827ebc..12b2d1b31 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -54,9 +54,8 @@ void O3ThreadContext::takeOverFrom(ThreadContext *old_context) { // some things should already be set up -#if FULL_SYSTEM assert(getSystemPtr() == old_context->getSystemPtr()); -#else +#if !FULL_SYSTEM assert(getProcessPtr() == old_context->getProcessPtr()); #endif diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 4831b701a..678bb42bb 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -201,9 +201,9 @@ class SimpleThread : public ThreadState TheISA::DTB *getDTBPtr() { return dtb; } -#if FULL_SYSTEM System *getSystemPtr() { return system; } +#if FULL_SYSTEM FunctionalPort *getPhysPort() { return physPort; } /** Return a virtual port. This port cannot be cached locally in an object. diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 9ee5250a3..7c3f11c12 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -129,9 +129,9 @@ class ThreadContext virtual TheISA::DTB *getDTBPtr() = 0; -#if FULL_SYSTEM virtual System *getSystemPtr() = 0; +#if FULL_SYSTEM virtual TheISA::Kernel::Statistics *getKernelStats() = 0; virtual FunctionalPort *getPhysPort() = 0; @@ -318,9 +318,9 @@ class ProxyThreadContext : public ThreadContext TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); } -#if FULL_SYSTEM System *getSystemPtr() { return actualTC->getSystemPtr(); } +#if FULL_SYSTEM TheISA::Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); } -- cgit v1.2.3 From 10fc45da27f0c18c1a8b90af3d76127fc4467391 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 21 Jan 2009 14:56:18 -0800 Subject: o3cpu: give a name to the activity recorder for better tracing --- src/cpu/activity.cc | 13 ++++++++----- src/cpu/activity.hh | 10 ++++++++-- src/cpu/o3/cpu.cc | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc index 15e0556ad..a2a34edf9 100644 --- a/src/cpu/activity.cc +++ b/src/cpu/activity.cc @@ -28,15 +28,18 @@ * Authors: Kevin Lim */ -#include +#include #include "base/timebuf.hh" #include "cpu/activity.hh" -ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency, - int activity) - : activityBuffer(longest_latency, 0), longestLatency(longest_latency), - activityCount(activity), numStages(num_stages) +using namespace std; + +ActivityRecorder::ActivityRecorder(const string &name, int num_stages, + int longest_latency, int activity) + : _name(name), activityBuffer(longest_latency, 0), + longestLatency(longest_latency), activityCount(activity), + numStages(num_stages) { stageActive = new bool[numStages]; std::memset(stageActive, 0, numStages); diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh index e99927339..d75ff150e 100644 --- a/src/cpu/activity.hh +++ b/src/cpu/activity.hh @@ -49,9 +49,11 @@ * idle. If count is zero, then the CPU can safely idle as it has no * more outstanding work to do. */ -class ActivityRecorder { +class ActivityRecorder +{ public: - ActivityRecorder(int num_stages, int longest_latency, int count); + ActivityRecorder(const std::string &name, int num_stages, + int longest_latency, int count); /** Records that there is activity this cycle. */ void activity(); @@ -92,6 +94,10 @@ class ActivityRecorder { void validate(); private: + // provide name() for DPRINTF. + std::string _name; + const std::string &name() { return _name; } + /** Time buffer that tracks if any cycles has active communication * in them. It should be as long as the longest communication * latency in the system. Each time any time buffer is written, diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 7320d5638..f567c1868 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -192,7 +192,7 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) decodeQueue(params->backComSize, params->forwardComSize), renameQueue(params->backComSize, params->forwardComSize), iewQueue(params->backComSize, params->forwardComSize), - activityRec(NumStages, + activityRec(name(), NumStages, params->backComSize + params->forwardComSize, params->activity), -- cgit v1.2.3 From f0fb3ac060234ed5860c8d5bca3e84dbd8d30c36 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sat, 24 Jan 2009 07:27:21 -0800 Subject: cpu: provide a wakeup mechanism that can be used to pull CPUs out of sleep. Make interrupts use the new wakeup method, and pull all of the interrupt stuff into the cpu base class so that only the wakeup code needs to be updated. I tried to make wakeup, wakeCPU, and the various other mechanisms for waking and sleeping a little more sane, but I couldn't understand why the statistics were changing the way they were. Maybe we'll try again some day. --- src/cpu/base.cc | 18 ------------------ src/cpu/base.hh | 23 ++++++++++++++++++++--- src/cpu/o3/cpu.cc | 27 +++++++++++++++------------ src/cpu/o3/cpu.hh | 7 ++++--- src/cpu/ozone/cpu.hh | 2 +- src/cpu/ozone/cpu_impl.hh | 4 +--- src/cpu/simple/base.cc | 11 +++++------ src/cpu/simple/base.hh | 2 +- 8 files changed, 47 insertions(+), 47 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 167606135..29095f12a 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -389,24 +389,6 @@ BaseCPU::ProfileEvent::process() cpu->schedule(this, curTick + interval); } -void -BaseCPU::postInterrupt(int int_num, int index) -{ - interrupts->post(int_num, index); -} - -void -BaseCPU::clearInterrupt(int int_num, int index) -{ - interrupts->clear(int_num, index); -} - -void -BaseCPU::clearInterrupts() -{ - interrupts->clearAll(); -} - void BaseCPU::serialize(std::ostream &os) { diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 83d73ede0..c8215e047 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -125,9 +125,26 @@ class BaseCPU : public MemObject return interrupts; } - virtual void postInterrupt(int int_num, int index); - virtual void clearInterrupt(int int_num, int index); - virtual void clearInterrupts(); + virtual void wakeup() = 0; + + void + postInterrupt(int int_num, int index) + { + interrupts->post(int_num, index); + wakeup(); + } + + void + clearInterrupt(int int_num, int index) + { + interrupts->clear(int_num, index); + } + + void + clearInterrupts() + { + interrupts->clearAll(); + } bool checkInterrupts(ThreadContext *tc) const diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index f567c1868..4f6d5d41c 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -893,18 +893,6 @@ FullO3CPU::activateWhenReady(int tid) } #if FULL_SYSTEM -template -void -FullO3CPU::postInterrupt(int int_num, int index) -{ - BaseCPU::postInterrupt(int_num, index); - - if (this->thread[0]->status() == ThreadContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - this->threadContexts[0]->activate(); - } -} - template Fault FullO3CPU::hwrei(unsigned tid) @@ -1689,6 +1677,21 @@ FullO3CPU::wakeCPU() schedule(tickEvent, nextCycle()); } +#if FULL_SYSTEM +template +void +FullO3CPU::wakeup() +{ + if (this->thread[0]->status() != ThreadContext::Suspended) + return; + + this->wakeCPU(); + + DPRINTF(Quiesce, "Suspended Processor woken\n"); + this->threadContexts[0]->activate(); +} +#endif + template int FullO3CPU::getFreeTid() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index d24e8c383..d14001d0d 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -402,9 +402,6 @@ class FullO3CPU : public BaseO3CPU void trap(Fault fault, unsigned tid); #if FULL_SYSTEM - /** Posts an interrupt. */ - void postInterrupt(int int_num, int index); - /** HW return from error interrupt. */ Fault hwrei(unsigned tid); @@ -701,6 +698,10 @@ class FullO3CPU : public BaseO3CPU /** Wakes the CPU, rescheduling the CPU if it's not already active. */ void wakeCPU(); +#if FULL_SYSTEM + virtual void wakeup(); +#endif + /** Gets a free thread id. Use if thread ids change across system. */ int getFreeTid(); diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 6b5e7282d..55ad7b3fb 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -333,7 +333,7 @@ class OzoneCPU : public BaseCPU Status _status; public: - void postInterrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 1402f4b72..84ee69464 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -582,10 +582,8 @@ OzoneCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM template void -OzoneCPU::postInterrupt(int int_num, int index) +OzoneCPU::wakeup() { - BaseCPU::postInterrupt(int_num, index); - if (_status == Idle) { DPRINTF(IPI,"Suspended Processor awoke\n"); // thread.activate(); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 3c154afb6..89d9ce383 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -303,14 +303,13 @@ BaseSimpleCPU::dbg_vtophys(Addr addr) #if FULL_SYSTEM void -BaseSimpleCPU::postInterrupt(int int_num, int index) +BaseSimpleCPU::wakeup() { - BaseCPU::postInterrupt(int_num, index); + if (thread->status() != ThreadContext::Suspended) + return; - if (thread->status() == ThreadContext::Suspended) { - DPRINTF(Quiesce,"Suspended Processor awoke\n"); - thread->activate(); - } + DPRINTF(Quiesce,"Suspended Processor awoke\n"); + thread->activate(); } #endif // FULL_SYSTEM diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 6e72b8f6c..34d0f5954 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -98,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU } public: - void postInterrupt(int int_num, int index); + void wakeup(); void zero_fill_64(Addr addr) { static int warned = 0; -- cgit v1.2.3 From d9794784bac54483660e438980d592b6ffe5c311 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 25 Jan 2009 20:29:03 -0800 Subject: CPU: Add a setCPU function to the interrupt objects. --- src/cpu/base.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 29095f12a..06fcebad8 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -194,6 +194,8 @@ BaseCPU::BaseCPU(Params *p) } } #if FULL_SYSTEM + interrupts->setCPU(this); + profileEvent = NULL; if (params()->profile) profileEvent = new ProfileEvent(this, params()->profile); @@ -348,6 +350,7 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) #if FULL_SYSTEM interrupts = oldCPU->interrupts; + interrupts->setCPU(this); for (int i = 0; i < threadContexts.size(); ++i) threadContexts[i]->profileClear(); -- cgit v1.2.3 From 35a85a4e86143c5bf23d5b74c14856792a0a624c Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Fri, 30 Jan 2009 19:08:13 -0500 Subject: Config: Cause a fatal() when a parameter without a default value isn't set(FS #315). --- src/cpu/BaseCPU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 985c415a0..f3688e991 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -69,7 +69,7 @@ class BaseCPU(MemObject): function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") - checker = Param.BaseCPU("checker CPU") + checker = Param.BaseCPU(NULL, "checker CPU") do_checkpoint_insts = Param.Bool(True, "enable checkpoint pseudo instructions") -- cgit v1.2.3 From 77209689499f2c843bebd9fca300fdd421277b15 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 1 Feb 2009 00:04:34 -0800 Subject: X86: Make sure the predecoder is cleared out for interrupts. --- src/cpu/simple/base.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/cpu') diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 89d9ce383..9af5d0150 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -321,6 +321,7 @@ BaseSimpleCPU::checkForInterrupts() Fault interrupt = interrupts->getInterrupt(tc); if (interrupt != NoFault) { + predecoder.reset(); interrupts->updateIntrInfo(tc); interrupt->invoke(tc); } -- cgit v1.2.3 From 7b585114704532133c3aed01847fa534167018b3 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 1 Feb 2009 00:30:54 -0800 Subject: CPU: Don't always reset the micro pc on faults. Let the faults handle it. --- src/cpu/simple/base.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 9af5d0150..b1a77247f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -472,8 +472,6 @@ BaseSimpleCPU::advancePC(Fault fault) if (fault != NoFault) { curMacroStaticInst = StaticInst::nullStaticInstPtr; predecoder.reset(); - thread->setMicroPC(normalMicroPC(0)); - thread->setNextMicroPC(normalMicroPC(1)); fault->invoke(tc); } else { //If we're at the last micro op for this instruction -- cgit v1.2.3 From 2d0a66cbc123fc345deb070c323130382518f367 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Tue, 10 Feb 2009 15:49:29 -0800 Subject: CPU: Prepare CPU models for the new in-order CPU model. Some new functions and forward declarations are necessary to make things work --- src/cpu/SConscript | 10 ++++++---- src/cpu/o3/ras.hh | 3 +++ src/cpu/static_inst.hh | 11 ++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/SConscript b/src/cpu/SConscript index f210cec9b..eee8edca4 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -48,12 +48,14 @@ execfile(models_db.srcnode().abspath) # Template for execute() signature. exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const { panic("initiateAcc not defined!"); M5_DUMMY_RETURN }; -virtual Fault completeAcc(Packet *pkt, %s *xc, +virtual Fault completeAcc(Packet *pkt, %(type)s *xc, Trace::InstRecord *traceData) const { panic("completeAcc not defined!"); M5_DUMMY_RETURN }; +virtual int memAccSize(%(type)s *xc) +{ panic("memAccSize not defined!"); M5_DUMMY_RETURN }; ''' mem_ini_sig_template = ''' @@ -82,7 +84,7 @@ def gen_cpu_exec_signatures(target, source, env): ''' for cpu in temp_cpu_list: xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % (xc_type, xc_type, xc_type) + print >> f, exec_sig_template % { 'type' : xc_type } print >> f, ''' #endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ ''' diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh index 97846ed16..f0621c5b5 100644 --- a/src/cpu/o3/ras.hh +++ b/src/cpu/o3/ras.hh @@ -71,6 +71,9 @@ class ReturnAddrStack */ void restore(unsigned top_entry_idx, const Addr &restored_target); + bool empty() { return usedEntries == 0; } + + bool full() { return usedEntries == numEntries; } private: /** Increments the top of stack index. */ inline void incrTos() diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index 032a304ad..f28b53ccf 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -56,9 +56,8 @@ class Packet; class O3CPUImpl; template class BaseO3DynInst; typedef BaseO3DynInst O3DynInst; - -template -class OzoneDynInst; +template class OzoneDynInst; +class InOrderDynInst; class CheckerCPU; class FastCPU; @@ -434,6 +433,12 @@ class StaticInst : public StaticInstBase */ bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const; + virtual Request::Flags memAccFlags() + { + panic("StaticInst::memAccFlags called on non-memory instruction"); + return 0; + }; + /** * Return string representation of disassembled instruction. * The default version of this function will call the internal -- cgit v1.2.3 From 34a5cd887075ff8bee987b87e43ae3818c6ac765 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Tue, 10 Feb 2009 15:49:29 -0800 Subject: ExeTrace: Allow subclasses of the tracer to define their own prefix to dump --- src/cpu/exetrace.cc | 8 +++++++- src/cpu/exetrace.hh | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 7227602b5..5897d1dbc 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -45,13 +45,19 @@ using namespace TheISA; namespace Trace { +void +ExeTracerRecord::dumpTicks(ostream &outs) +{ + ccprintf(outs, "%7d: ", when); +} + void Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran) { ostream &outs = Trace::output(); if (IsOn(ExecTicks)) - ccprintf(outs, "%7d: ", when); + dumpTicks(outs); outs << thread->getCpuPtr()->name() << " "; diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index e5b22c881..e49a2bb59 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -57,6 +57,7 @@ class ExeTracerRecord : public InstRecord void traceInst(StaticInstPtr inst, bool ran); void dump(); + virtual void dumpTicks(std::ostream &outs); }; class ExeTracer : public InstTracer -- cgit v1.2.3 From 973d8b8b13b8e4ea178cafa95aaf6538699b8b15 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Tue, 10 Feb 2009 15:49:29 -0800 Subject: InOrder: Import new inorder CPU model from MIPS. This model currently only works in MIPS_SE mode, so it will take some effort to clean it up and make it generally useful. Hopefully people are willing to help make that happen! --- src/cpu/cpu_models.py | 3 + src/cpu/inorder/InOrderCPU.py | 80 ++ src/cpu/inorder/InOrderTrace.py | 35 + src/cpu/inorder/SConscript | 82 ++ src/cpu/inorder/SConsopts | 33 + src/cpu/inorder/comm.hh | 104 ++ src/cpu/inorder/cpu.cc | 1322 ++++++++++++++++++++++++ src/cpu/inorder/cpu.hh | 730 +++++++++++++ src/cpu/inorder/first_stage.cc | 251 +++++ src/cpu/inorder/first_stage.hh | 97 ++ src/cpu/inorder/inorder_cpu_builder.cc | 61 ++ src/cpu/inorder/inorder_dyn_inst.cc | 780 ++++++++++++++ src/cpu/inorder/inorder_dyn_inst.hh | 975 +++++++++++++++++ src/cpu/inorder/inorder_trace.cc | 94 ++ src/cpu/inorder/inorder_trace.hh | 98 ++ src/cpu/inorder/params.hh | 124 +++ src/cpu/inorder/pipeline_stage.cc | 1033 ++++++++++++++++++ src/cpu/inorder/pipeline_stage.hh | 358 +++++++ src/cpu/inorder/pipeline_traits.5stage.cc | 166 +++ src/cpu/inorder/pipeline_traits.5stage.hh | 147 +++ src/cpu/inorder/pipeline_traits.9stage.cc | 242 +++++ src/cpu/inorder/pipeline_traits.9stage.hh | 155 +++ src/cpu/inorder/pipeline_traits.9stage.smt2.cc | 240 +++++ src/cpu/inorder/pipeline_traits.9stage.smt2.hh | 155 +++ src/cpu/inorder/pipeline_traits.cc | 153 +++ src/cpu/inorder/pipeline_traits.hh | 177 ++++ src/cpu/inorder/reg_dep_map.cc | 236 +++++ src/cpu/inorder/reg_dep_map.hh | 105 ++ src/cpu/inorder/resource.cc | 434 ++++++++ src/cpu/inorder/resource.hh | 404 ++++++++ src/cpu/inorder/resource_pool.9stage.cc | 357 +++++++ src/cpu/inorder/resource_pool.cc | 364 +++++++ src/cpu/inorder/resource_pool.hh | 189 ++++ src/cpu/inorder/resources/agen_unit.cc | 98 ++ src/cpu/inorder/resources/agen_unit.hh | 64 ++ src/cpu/inorder/resources/bpred_unit.cc | 426 ++++++++ src/cpu/inorder/resources/bpred_unit.hh | 258 +++++ src/cpu/inorder/resources/branch_predictor.cc | 149 +++ src/cpu/inorder/resources/branch_predictor.hh | 87 ++ src/cpu/inorder/resources/cache_unit.cc | 609 +++++++++++ src/cpu/inorder/resources/cache_unit.hh | 305 ++++++ src/cpu/inorder/resources/decode_unit.cc | 92 ++ src/cpu/inorder/resources/decode_unit.hh | 68 ++ src/cpu/inorder/resources/execution_unit.cc | 182 ++++ src/cpu/inorder/resources/execution_unit.hh | 77 ++ src/cpu/inorder/resources/fetch_seq_unit.cc | 324 ++++++ src/cpu/inorder/resources/fetch_seq_unit.hh | 119 +++ src/cpu/inorder/resources/graduation_unit.cc | 113 ++ src/cpu/inorder/resources/graduation_unit.hh | 70 ++ src/cpu/inorder/resources/inst_buffer.cc | 222 ++++ src/cpu/inorder/resources/inst_buffer.hh | 93 ++ src/cpu/inorder/resources/inst_buffer_new.cc | 156 +++ src/cpu/inorder/resources/inst_buffer_new.hh | 109 ++ src/cpu/inorder/resources/mem_dep_unit.hh | 66 ++ src/cpu/inorder/resources/mult_div_unit.cc | 291 ++++++ src/cpu/inorder/resources/mult_div_unit.hh | 138 +++ src/cpu/inorder/resources/resource_list.hh | 47 + src/cpu/inorder/resources/tlb_unit.cc | 186 ++++ src/cpu/inorder/resources/tlb_unit.hh | 124 +++ src/cpu/inorder/resources/use_def.cc | 326 ++++++ src/cpu/inorder/resources/use_def.hh | 102 ++ src/cpu/inorder/thread_context.cc | 371 +++++++ src/cpu/inorder/thread_context.hh | 286 +++++ src/cpu/inorder/thread_state.hh | 90 ++ 64 files changed, 15432 insertions(+) create mode 100644 src/cpu/inorder/InOrderCPU.py create mode 100644 src/cpu/inorder/InOrderTrace.py create mode 100644 src/cpu/inorder/SConscript create mode 100644 src/cpu/inorder/SConsopts create mode 100644 src/cpu/inorder/comm.hh create mode 100644 src/cpu/inorder/cpu.cc create mode 100644 src/cpu/inorder/cpu.hh create mode 100644 src/cpu/inorder/first_stage.cc create mode 100644 src/cpu/inorder/first_stage.hh create mode 100644 src/cpu/inorder/inorder_cpu_builder.cc create mode 100644 src/cpu/inorder/inorder_dyn_inst.cc create mode 100644 src/cpu/inorder/inorder_dyn_inst.hh create mode 100644 src/cpu/inorder/inorder_trace.cc create mode 100644 src/cpu/inorder/inorder_trace.hh create mode 100644 src/cpu/inorder/params.hh create mode 100644 src/cpu/inorder/pipeline_stage.cc create mode 100644 src/cpu/inorder/pipeline_stage.hh create mode 100644 src/cpu/inorder/pipeline_traits.5stage.cc create mode 100644 src/cpu/inorder/pipeline_traits.5stage.hh create mode 100644 src/cpu/inorder/pipeline_traits.9stage.cc create mode 100644 src/cpu/inorder/pipeline_traits.9stage.hh create mode 100644 src/cpu/inorder/pipeline_traits.9stage.smt2.cc create mode 100644 src/cpu/inorder/pipeline_traits.9stage.smt2.hh create mode 100644 src/cpu/inorder/pipeline_traits.cc create mode 100644 src/cpu/inorder/pipeline_traits.hh create mode 100644 src/cpu/inorder/reg_dep_map.cc create mode 100644 src/cpu/inorder/reg_dep_map.hh create mode 100644 src/cpu/inorder/resource.cc create mode 100644 src/cpu/inorder/resource.hh create mode 100644 src/cpu/inorder/resource_pool.9stage.cc create mode 100644 src/cpu/inorder/resource_pool.cc create mode 100644 src/cpu/inorder/resource_pool.hh create mode 100644 src/cpu/inorder/resources/agen_unit.cc create mode 100644 src/cpu/inorder/resources/agen_unit.hh create mode 100644 src/cpu/inorder/resources/bpred_unit.cc create mode 100644 src/cpu/inorder/resources/bpred_unit.hh create mode 100644 src/cpu/inorder/resources/branch_predictor.cc create mode 100644 src/cpu/inorder/resources/branch_predictor.hh create mode 100644 src/cpu/inorder/resources/cache_unit.cc create mode 100644 src/cpu/inorder/resources/cache_unit.hh create mode 100644 src/cpu/inorder/resources/decode_unit.cc create mode 100644 src/cpu/inorder/resources/decode_unit.hh create mode 100644 src/cpu/inorder/resources/execution_unit.cc create mode 100644 src/cpu/inorder/resources/execution_unit.hh create mode 100644 src/cpu/inorder/resources/fetch_seq_unit.cc create mode 100644 src/cpu/inorder/resources/fetch_seq_unit.hh create mode 100644 src/cpu/inorder/resources/graduation_unit.cc create mode 100644 src/cpu/inorder/resources/graduation_unit.hh create mode 100644 src/cpu/inorder/resources/inst_buffer.cc create mode 100644 src/cpu/inorder/resources/inst_buffer.hh create mode 100644 src/cpu/inorder/resources/inst_buffer_new.cc create mode 100644 src/cpu/inorder/resources/inst_buffer_new.hh create mode 100644 src/cpu/inorder/resources/mem_dep_unit.hh create mode 100644 src/cpu/inorder/resources/mult_div_unit.cc create mode 100644 src/cpu/inorder/resources/mult_div_unit.hh create mode 100644 src/cpu/inorder/resources/resource_list.hh create mode 100644 src/cpu/inorder/resources/tlb_unit.cc create mode 100644 src/cpu/inorder/resources/tlb_unit.hh create mode 100644 src/cpu/inorder/resources/use_def.cc create mode 100644 src/cpu/inorder/resources/use_def.hh create mode 100644 src/cpu/inorder/thread_context.cc create mode 100644 src/cpu/inorder/thread_context.hh create mode 100644 src/cpu/inorder/thread_state.hh (limited to 'src/cpu') diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py index 5b0c6c4da..793f8c646 100644 --- a/src/cpu/cpu_models.py +++ b/src/cpu/cpu_models.py @@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc', CpuModel('O3CPU', 'o3_cpu_exec.cc', '#include "cpu/o3/isa_specific.hh"', { 'CPU_exec_context': 'O3DynInst' }) +CpuModel('InOrderCPU', 'inorder_cpu_exec.cc', + '#include "cpu/inorder/inorder_dyn_inst.hh"', + { 'CPU_exec_context': 'InOrderDynInst' }) diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py new file mode 100644 index 000000000..a5e81a090 --- /dev/null +++ b/src/cpu/inorder/InOrderCPU.py @@ -0,0 +1,80 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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: Korey Sewell + +from m5.params import * +from m5.proxy import * +from m5 import build_env +from BaseCPU import BaseCPU + +class InOrderCPU(BaseCPU): + type = 'InOrderCPU' + activity = Param.Unsigned(0, "Initial count") + numThreads = Param.Unsigned(1, "number of HW thread contexts") + + cachePorts = Param.Unsigned("Cache Ports") + stageWidth = Param.Unsigned(1, "Stage width") + + fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from") + dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from") + icache_port = Port("Instruction Port") + dcache_port = Port("Data Port") + _mem_ports = ['icache_port', 'dcache_port'] + + predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')") + localPredictorSize = Param.Unsigned(2048, "Size of local predictor") + localCtrBits = Param.Unsigned(2, "Bits per counter") + localHistoryTableSize = Param.Unsigned(2048, "Size of local history table") + localHistoryBits = Param.Unsigned(11, "Bits for the local history") + globalPredictorSize = Param.Unsigned(8192, "Size of global predictor") + globalCtrBits = Param.Unsigned(2, "Bits per counter") + globalHistoryBits = Param.Unsigned(13, "Bits of history") + choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor") + choiceCtrBits = Param.Unsigned(2, "Bits of choice counters") + + BTBEntries = Param.Unsigned(4096, "Number of BTB entries") + BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits") + + RASSize = Param.Unsigned(16, "RAS size") + + instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by") + functionTrace = Param.Bool(False, "Enable function trace") + functionTraceStart = Param.Tick(0, "Cycle to start function trace") + stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU") + + memBlockSize = Param.Unsigned("Memory Block Size") + + multLatency = Param.Unsigned(1, "Latency for Multiply Operations") + multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations") + div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations") + div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations") + div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations") + div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations") + div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations") + div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations") + div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations") + div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations") diff --git a/src/cpu/inorder/InOrderTrace.py b/src/cpu/inorder/InOrderTrace.py new file mode 100644 index 000000000..3453fa675 --- /dev/null +++ b/src/cpu/inorder/InOrderTrace.py @@ -0,0 +1,35 @@ +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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: Korey Sewell + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class InOrderTrace(InstTracer): + type = 'InOrderTrace' + cxx_class = 'Trace::InOrderTrace' diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript new file mode 100644 index 000000000..c7edd1d76 --- /dev/null +++ b/src/cpu/inorder/SConscript @@ -0,0 +1,82 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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: Korey Sewell + +Import('*') + +if 'InOrderCPU' in env['CPU_MODELS']: + SimObject('InOrderCPU.py') + SimObject('InOrderTrace.py') + + TraceFlag('ResReqCount') + TraceFlag('FreeList') + TraceFlag('InOrderCachePort') + TraceFlag('InOrderStage') + TraceFlag('InOrderStall') + TraceFlag('InOrderCPU') + TraceFlag('InOrderMDU') + TraceFlag('RegDepMap') + TraceFlag('Rename') + TraceFlag('InOrderDynInst') + TraceFlag('Resource') + TraceFlag('RefCount') + + CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', + 'InOrderMDU', 'RegDepMap', 'Resource', 'Rename']) + + Source('pipeline_traits.cc') + Source('inorder_dyn_inst.cc') + Source('inorder_cpu_builder.cc') + Source('inorder_trace.cc') + Source('pipeline_stage.cc') + Source('first_stage.cc') + Source('resource.cc') + Source('resources/agen_unit.cc') + Source('resources/execution_unit.cc') + Source('resources/bpred_unit.cc') + Source('resources/branch_predictor.cc') + Source('resources/cache_unit.cc') + Source('resources/use_def.cc') + Source('resources/decode_unit.cc') + Source('resources/inst_buffer.cc') + Source('resources/graduation_unit.cc') + Source('resources/tlb_unit.cc') + Source('resources/fetch_seq_unit.cc') + Source('resources/mult_div_unit.cc') + Source('resource_pool.cc') + Source('reg_dep_map.cc') + Source('../o3/btb.cc') + Source('../o3/tournament_pred.cc') + Source('../o3/2bit_local_pred.cc') + Source('../o3/free_list.cc') + Source('../o3/rename_map.cc') + Source('../o3/ras.cc') + Source('thread_context.cc') + Source('cpu.cc') + diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts new file mode 100644 index 000000000..82ebd18ea --- /dev/null +++ b/src/cpu/inorder/SConsopts @@ -0,0 +1,33 @@ +# -*- mode:python -*- + +# Copyright (c) 2007 MIPS Technologies, Inc. +# 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: Korey Sewell + +Import('*') + +all_cpu_list.append('InOrderCPU') diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh new file mode 100644 index 000000000..c687a9ab4 --- /dev/null +++ b/src/cpu/inorder/comm.hh @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_COMM_HH__ +#define __CPU_INORDER_COMM_HH__ + +#include + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inst_seq.hh" +#include "sim/host.hh" + +/** Struct that defines the information passed from in between stages */ +/** This information mainly goes forward through the pipeline. */ +struct InterStageStruct { + int size; + ThePipeline::DynInstPtr insts[ThePipeline::StageWidth]; + bool squash; + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + InstSeqNum squashedSeqNum; + bool includeSquashInst; +}; + +/** Turn This into a Class */ +/** Struct that defines all backwards communication. */ +struct TimeStruct { + struct stageComm { + bool squash; + bool predIncorrect; + uint64_t branchAddr; + + // @todo: Might want to package this kind of branch stuff into a single + // struct as it is used pretty frequently. + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + + unsigned branchCount; + + // Represents the instruction that has either been retired or + // squashed. Similar to having a single bus that broadcasts the + // retired or squashed sequence number. + InstSeqNum doneSeqNum; + InstSeqNum bdelayDoneSeqNum; + bool squashDelaySlot; + + //Just in case we want to do a commit/squash on a cycle + //(necessary for multiple ROBs?) + bool commitInsts; + InstSeqNum squashSeqNum; + + // Communication specifically to the IQ to tell the IQ that it can + // schedule a non-speculative instruction. + InstSeqNum nonSpecSeqNum; + + bool uncached; + ThePipeline::DynInstPtr uncachedLoad; + + bool interruptPending; + bool clearInterrupt; + }; + + stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads]; + + bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads]; + bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads]; +}; + +#endif //__CPU_INORDER_COMM_HH__ diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc new file mode 100644 index 000000000..adbf645f4 --- /dev/null +++ b/src/cpu/inorder/cpu.cc @@ -0,0 +1,1322 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/activity.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "mem/translating_port.hh" +#include "sim/process.hh" +//#include "sim/root.hh" +#include "sim/stat_control.hh" +#include + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderCPU::TickEvent::TickEvent(InOrderCPU *c) + : Event(CPU_Tick_Pri), cpu(c) +{ } + + +void +InOrderCPU::TickEvent::process() +{ + cpu->tick(); +} + + +const char * +InOrderCPU::TickEvent::description() +{ + return "InOrderCPU tick event"; +} + +InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, + Fault fault, unsigned _tid, unsigned _vpe) + : Event(CPU_Tick_Pri), cpu(_cpu) +{ + setEvent(e_type, fault, _tid, _vpe); +} + +void +InOrderCPU::CPUEvent::process() +{ + switch (cpuEventType) + { + case ActivateThread: + cpu->activateThread(tid); + break; + + //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate + case SuspendThread: // Suspend & Deallocate are same for now. + //cpu->suspendThread(tid); + //break; + case DeallocateThread: + cpu->deallocateThread(tid); + break; + + case EnableVPEs: + cpu->enableVPEs(vpe); + break; + + case DisableVPEs: + cpu->disableVPEs(tid, vpe); + break; + + case EnableThreads: + cpu->enableThreads(vpe); + break; + + case DisableThreads: + cpu->disableThreads(tid, vpe); + break; + + case Trap: + cpu->trapCPU(fault, tid); + break; + + default: + fatal("Unrecognized Event Type %d", cpuEventType); + } + + cpu->cpuEventRemoveList.push(this); +} + +const char * +InOrderCPU::CPUEvent::description() +{ + return "InOrderCPU event"; +} + +void +InOrderCPU::CPUEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + cpu->ticks(delay)); +} + +void +InOrderCPU::CPUEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} + +InOrderCPU::InOrderCPU(Params *params) + : BaseCPU(params), + cpu_id(params->cpu_id), + tickEvent(this), + miscRegFile(this), + timeBuffer(2 , 2), + removeInstsThisCycle(false), + activityRec(params->name, NumStages, 10, params->activity), + switchCount(0), + deferRegistration(false/*params->deferRegistration*/), + stageTracing(params->stageTracing), + numThreads(params->numThreads), + numVirtProcs(1) +{ + cpu_params = params; + + resPool = new ResourcePool(this, params); +// resPool->init(); + + coreType = "default"; // eventually get this from params + + _status = Idle; + + // Resize for Multithreading CPUs + thread.resize(numThreads); + + int active_threads = params->workload.size(); + + if (active_threads > MaxThreads) { + panic("Workload Size too large. Increase the 'MaxThreads'" + "in your InOrder implementation or " + "edit your workload size."); + } + + // Bind the fetch & data ports from the resource pool. + fetchPortIdx = resPool->getPortIdx(params->fetchMemPort); + if (fetchPortIdx == 0) { + warn("Unable to find port to fetch instructions from.\n"); + } + + dataPortIdx = resPool->getPortIdx(params->dataMemPort); + if (dataPortIdx == 0) { + warn("Unable to find port for data.\n"); + } + + + /* Use this port to for syscall emulation writes to memory. */ + //Port *mem_port = NULL; + //TranslatingPort *trans_port = NULL; + + for (int i = 0; i < numThreads; ++i) { + if (i < params->workload.size()) { + DPRINTF(InOrderCPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], + i); + + // Start thread's off in "Suspended" status + this->thread[i]->setStatus(ThreadContext::Suspended); + + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = params->workload[0]; //LiveProcess::createDummy(); + this->thread[i] = new Thread(this, i, dummy_proc, i); + + // Set Up Syscall Emulation Port + //this->thread[i]->setMemPort(trans_port); + } + + // Setup the TC that will serve as the interface to the threads/CPU. + InOrderThreadContext *tc = new InOrderThreadContext; + tc->cpu = this; + tc->thread = this->thread[i]; + + // Give the thread the TC. + thread[i]->tc = tc; + thread[i]->setFuncExeInst(0); + globalSeqNum[i] = 1; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + // Initialize TimeBuffer Stage Queues + // For now just have these time buffers be pretty big. + // @note: This could be statically allocated but changes + // would have to be made to the standard time buffer class. + for (int stNum=0; stNum < NumStages - 1; stNum++) { + stageQueue[stNum] = new StageQueue(NumStages, NumStages); + } + + + // Set Up Pipeline Stages + for (int stNum=0; stNum < NumStages; stNum++) { + if (stNum == 0) + pipelineStage[stNum] = new FirstStage(params, stNum); + else + pipelineStage[stNum] = new PipelineStage(params, stNum); + + pipelineStage[stNum]->setCPU(this); + pipelineStage[stNum]->setActiveThreads(&activeThreads); + pipelineStage[stNum]->setTimeBuffer(&timeBuffer); + + // Take Care of 1st/Nth stages + if (stNum > 0) + pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]); + if (stNum < NumStages - 2) + pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum + 1]); + } + + // Initialize thread specific variables + for (int tid=0; tid < numThreads; tid++) { + archRegDepMap[tid].setCPU(this); + + nonSpecInstActive[tid] = false; + nonSpecSeqNum[tid] = 0; + + squashSeqNum[tid] = MaxAddr; + lastSquashCycle[tid] = 0; + + intRegFile[tid].clear(); + floatRegFile[tid].clear(); + } + + // Update miscRegFile if necessary + if (numThreads > 1) { + miscRegFile.expandForMultithreading(numThreads, numVirtProcs); + } + + miscRegFile.clear(); + + lastRunningCycle = curTick; + contextSwitch = false; + + // Define dummy instructions and resource requests to be used. + DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0); + dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0); + + // Reset CPU to reset state. +#if FULL_SYSTEM + Fault resetFault = new ResetFault(); + resetFault->invoke(tcBase()); +#else + reset(); +#endif + + // Schedule First Tick Event, CPU will reschedule itself from here on out. + scheduleTickEvent(0); +} + + +void +InOrderCPU::regStats() +{ + /* Register the Resource Pool's stats here.*/ + resPool->regStats(); + + /* Register any of the InOrderCPU's stats here.*/ + timesIdled + .name(name() + ".timesIdled") + .desc("Number of times that the entire CPU went into an idle state and" + " unscheduled itself") + .prereq(timesIdled); + + idleCycles + .name(name() + ".idleCycles") + .desc("Total number of cycles that the CPU has spent unscheduled due " + "to idling") + .prereq(idleCycles); + + threadCycles + .init(numThreads) + .name(name() + ".threadCycles") + .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)"); + + smtCycles + .name(name() + ".smtCycles") + .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)"); + + committedInsts + .init(numThreads) + .name(name() + ".committedInsts") + .desc("Number of Instructions Simulated (Per-Thread)"); + + smtCommittedInsts + .init(numThreads) + .name(name() + ".smtCommittedInsts") + .desc("Number of SMT Instructions Simulated (Per-Thread)"); + + totalCommittedInsts + .name(name() + ".committedInsts_total") + .desc("Number of Instructions Simulated (Total)"); + + cpi + .name(name() + ".cpi") + .desc("CPI: Cycles Per Instruction (Per-Thread)") + .precision(6); + cpi = threadCycles / committedInsts; + + smtCpi + .name(name() + ".smt_cpi") + .desc("CPI: Total SMT-CPI") + .precision(6); + smtCpi = smtCycles / smtCommittedInsts; + + totalCpi + .name(name() + ".cpi_total") + .desc("CPI: Total CPI of All Threads") + .precision(6); + totalCpi = simTicks / totalCommittedInsts; + + ipc + .name(name() + ".ipc") + .desc("IPC: Instructions Per Cycle (Per-Thread)") + .precision(6); + ipc = committedInsts / threadCycles; + + smtIpc + .name(name() + ".smt_ipc") + .desc("IPC: Total SMT-IPC") + .precision(6); + smtIpc = smtCommittedInsts / smtCycles; + + totalIpc + .name(name() + ".ipc_total") + .desc("IPC: Total IPC of All Threads") + .precision(6); + totalIpc = totalCommittedInsts / simTicks; + + BaseCPU::regStats(); +} + + +void +InOrderCPU::tick() +{ + DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n"); + + ++numCycles; + + //Tick each of the stages + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->tick(); + } + + // Now advance the time buffers one tick + timeBuffer.advance(); + for (int sqNum=0; sqNum < NumStages - 1; sqNum++) { + stageQueue[sqNum]->advance(); + } + activityRec.advance(); + + // Any squashed requests, events, or insts then remove them now + cleanUpRemovedReqs(); + cleanUpRemovedEvents(); + cleanUpRemovedInsts(); + + // Re-schedule CPU for this cycle + if (!tickEvent.scheduled()) { + if (_status == SwitchedOut) { + // increment stat + lastRunningCycle = curTick; + } else if (!activityRec.active()) { + DPRINTF(InOrderCPU, "sleeping CPU.\n"); + lastRunningCycle = curTick; + timesIdled++; + } else { + //Tick next_tick = curTick + cycles(1); + //tickEvent.schedule(next_tick); + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1)); + DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick); + } + } + + tickThreadStats(); + updateThreadPriority(); +} + + +void +InOrderCPU::init() +{ + if (!deferRegistration) { + registerThreadContexts(); + } + + // Set inSyscall so that the CPU doesn't squash when initially + // setting up registers. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = true; + + for (int tid=0; tid < number_of_threads; tid++) { + + ThreadContext *src_tc = thread[tid]->getTC(); + + // Threads start in the Suspended State + if (src_tc->status() != ThreadContext::Suspended) { + continue; + } + + } + + // Clear inSyscall. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = false; + + // Call Initializiation Routine for Resource Pool + resPool->init(); +} + +void +InOrderCPU::readFunctional(Addr addr, uint32_t &buffer) +{ + tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t)); + buffer = gtoh(buffer); +} + +void +InOrderCPU::reset() +{ + miscRegFile.reset(coreType, numThreads, numVirtProcs, dynamic_cast(this)); +} + +Port* +InOrderCPU::getPort(const std::string &if_name, int idx) +{ + return resPool->getPort(if_name, idx); +} + +void +InOrderCPU::trap(Fault fault, unsigned tid, int delay) +{ + scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::trapCPU(Fault fault, unsigned tid) +{ + fault->invoke(tcBase(tid)); +} + +void +InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault, + unsigned tid, unsigned vpe, unsigned delay) +{ + CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe); + + if (delay >= 0) { + DPRINTF(InOrderCPU, "Scheduling CPU Event Type #%i for cycle %i.\n", + c_event, curTick + delay); + mainEventQueue.schedule(cpu_event,curTick + delay); + } else { + cpu_event->process(); + cpuEventRemoveList.push(cpu_event); + } + + // Broadcast event to the Resource Pool + DynInstPtr dummy_inst = new InOrderDynInst(this, NULL, getNextEventNum(), tid); + resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid); +} + +inline bool +InOrderCPU::isThreadActive(unsigned tid) +{ + list::iterator isActive = std::find( + activeThreads.begin(), activeThreads.end(), tid); + + return (isActive != activeThreads.end()); +} + + +void +InOrderCPU::activateThread(unsigned tid) +{ + if (!isThreadActive(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to active threads list in CPU.\n", + tid); + activeThreads.push_back(tid); + + wakeCPU(); + } +} + +void +InOrderCPU::deactivateThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid); + + if (isThreadActive(tid)) { + DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n", + tid); + list::iterator thread_it = std::find(activeThreads.begin(), + activeThreads.end(), tid); + + removePipelineStalls(*thread_it); + + //@TODO: change stage status' to Idle? + + activeThreads.erase(thread_it); + } +} + +void +InOrderCPU::removePipelineStalls(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n", + tid); + + for (int stNum = 0; stNum < NumStages ; stNum++) { + pipelineStage[stNum]->removeStalls(tid); + } + +} +bool +InOrderCPU::isThreadInCPU(unsigned tid) +{ + list::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + + return (isCurrent != currentThreads.end()); +} + +void +InOrderCPU::addToCurrentThreads(unsigned tid) +{ + if (!isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + currentThreads.push_back(tid); + } +} + +void +InOrderCPU::removeFromCurrentThreads(unsigned tid) +{ + if (isThreadInCPU(tid)) { + DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n", + tid); + list::iterator isCurrent = std::find( + currentThreads.begin(), currentThreads.end(), tid); + currentThreads.erase(isCurrent); + } +} + +bool +InOrderCPU::isThreadSuspended(unsigned tid) +{ + list::iterator isSuspended = std::find( + suspendedThreads.begin(), suspendedThreads.end(), tid); + + return (isSuspended!= suspendedThreads.end()); +} + +void +InOrderCPU::enableVirtProcElement(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Enabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableVPEs(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution " + "virtual processors %i", vpe); + + list::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + thread_it++; + } +} + +void +InOrderCPU::disableVirtProcElement(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling " + "Disabling of concurrent virtual processor execution", + vpe); + + scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::disableVPEs(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of " + "virtual processors %i", vpe); + + unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid)); + + list::iterator thread_it = activeThreads.begin(); + + std::vector::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (base_vpe != vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::enableMultiThreading(unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on " + "virtual processor %i", vpe); + + scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe); +} + +void +InOrderCPU::enableThreads(unsigned vpe) +{ + DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on " + "virtual processor %i", vpe); + + list::iterator thread_it = currentThreads.begin(); + + while (thread_it != currentThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + if (!isThreadSuspended(*thread_it)) { + activateThread(*thread_it); + } + } + thread_it++; + } +} +void +InOrderCPU::disableMultiThreading(unsigned tid, unsigned vpe) +{ + // Schedule event to take place at end of cycle + DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on " + "virtual processor %i", tid, vpe); + + scheduleCpuEvent(DisableThreads, NoFault, tid, vpe); +} + +void +InOrderCPU::disableThreads(unsigned tid, unsigned vpe) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on " + "virtual processor %i", tid, vpe); + + list::iterator thread_it = activeThreads.begin(); + + std::vector::iterator> removeList; + + while (thread_it != activeThreads.end()) { + if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) { + removeList.push_back(thread_it); + } + thread_it++; + } + + for (int i = 0; i < removeList.size(); i++) { + activeThreads.erase(removeList[i]); + } +} + +void +InOrderCPU::updateThreadPriority() +{ + if (activeThreads.size() > 1) + { + //DEFAULT TO ROUND ROBIN SCHEME + //e.g. Move highest priority to end of thread list + list::iterator list_begin = activeThreads.begin(); + list::iterator list_end = activeThreads.end(); + + unsigned high_thread = *list_begin; + + activeThreads.erase(list_begin); + + activeThreads.push_back(high_thread); + } +} + +inline void +InOrderCPU::tickThreadStats() +{ + /** Keep track of cycles that each thread is active */ + list::iterator thread_it = activeThreads.begin(); + while (thread_it != activeThreads.end()) { + threadCycles[*thread_it]++; + thread_it++; + } + + // Keep track of cycles where SMT is active + if (activeThreads.size() > 1) { + smtCycles++; + } +} + +void +InOrderCPU::activateContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid); + + scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay); + + // Be sure to signal that there's some activity so the CPU doesn't + // deschedule itself. + activityRec.activity(); + + _status = Running; +} + + +void +InOrderCPU::suspendContext(unsigned tid, int delay) +{ + scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay); + //_status = Idle; +} + +void +InOrderCPU::suspendThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid); + deactivateThread(tid); +} + +void +InOrderCPU::deallocateContext(unsigned tid, int delay) +{ + scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay); +} + +void +InOrderCPU::deallocateThread(unsigned tid) +{ + DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid); + + //removeThread(tid); + + removeFromCurrentThreads(tid); + + deactivateThread(tid); + + squashThreadInPipeline(tid); +} + +void +InOrderCPU::squashThreadInPipeline(unsigned tid) +{ + //Squash all instructions in each stage + for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) { + pipelineStage[stNum]->squash(0 /*seq_num*/, tid); + } +} + +void +InOrderCPU::haltContext(unsigned tid, int delay) +{ + DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid); + + // Halt is same thing as deallocate for now + // @TODO: Differentiate between halt & deallocate in the CPU + // model + deallocateContext(tid, delay); +} + +void +InOrderCPU::insertThread(unsigned tid) +{ + panic("Unimplemented Function\n."); +} + +void +InOrderCPU::removeThread(unsigned tid) +{ + DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid); + + /** Broadcast to CPU resources*/ +} + +void +InOrderCPU::activateWhenReady(int tid) +{ + panic("Unimplemented Function\n."); +} + + +void +InOrderCPU::signalSwitched() +{ + panic("Unimplemented Function\n."); +} + + +void +InOrderCPU::takeOverFrom(BaseCPU *oldCPU) +{ + panic("Take Over From Another CPU\n."); +} + +uint64_t +InOrderCPU::readPC(unsigned tid) +{ + return PC[tid]; +} + + +void +InOrderCPU::setPC(Addr new_PC, unsigned tid) +{ + PC[tid] = new_PC; +} + + +uint64_t +InOrderCPU::readNextPC(unsigned tid) +{ + return nextPC[tid]; +} + + +void +InOrderCPU::setNextPC(uint64_t new_NPC, unsigned tid) +{ + nextPC[tid] = new_NPC; +} + + +uint64_t +InOrderCPU::readNextNPC(unsigned tid) +{ + return nextNPC[tid]; +} + + +void +InOrderCPU::setNextNPC(uint64_t new_NNPC, unsigned tid) +{ + nextNPC[tid] = new_NNPC; +} + +uint64_t +InOrderCPU::readIntReg(int reg_idx, unsigned tid) +{ + return intRegFile[tid].readReg(reg_idx); +} + +FloatReg +InOrderCPU::readFloatReg(int reg_idx, unsigned tid, int width) +{ + + return floatRegFile[tid].readReg(reg_idx, width); +} + +FloatRegBits +InOrderCPU::readFloatRegBits(int reg_idx, unsigned tid, int width) +{; + return floatRegFile[tid].readRegBits(reg_idx, width); +} + +void +InOrderCPU::setIntReg(int reg_idx, uint64_t val, unsigned tid) +{ + intRegFile[tid].setReg(reg_idx, val); +} + + +void +InOrderCPU::setFloatReg(int reg_idx, FloatReg val, unsigned tid, int width) +{ + floatRegFile[tid].setReg(reg_idx, val, width); +} + + +void +InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, int width) +{ + floatRegFile[tid].setRegBits(reg_idx, val, width); +} + +uint64_t +InOrderCPU::readRegOtherThread(unsigned reg_idx, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return readMiscReg(reg_idx, tid); // Misc. Register File + } +} +void +InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val, unsigned tid) +{ + // If Default value is set, then retrieve target thread + if (tid == -1) { + tid = TheISA::getTargetThread(tcBase(tid)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +MiscReg +InOrderCPU::readMiscRegNoEffect(int misc_reg, unsigned tid) +{ + return miscRegFile.readRegNoEffect(misc_reg, tid); +} + +MiscReg +InOrderCPU::readMiscReg(int misc_reg, unsigned tid) +{ + return miscRegFile.readReg(misc_reg, tcBase(tid), tid); +} + +void +InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setRegNoEffect(misc_reg, val, tid); +} + +void +InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + miscRegFile.setReg(misc_reg, val, tcBase(tid), tid); +} + + +InOrderCPU::ListIt +InOrderCPU::addInst(DynInstPtr &inst) +{ + int tid = inst->readTid(); + + instList[tid].push_back(inst); + + return --(instList[tid].end()); +} + +void +InOrderCPU::instDone(DynInstPtr inst, unsigned tid) +{ + // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used + // when restoring a thread to the CPU after a fork or after an exception + // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not + setPC(inst->readPC(), tid); + setNextPC(inst->readNextPC(), tid); + setNextNPC(inst->readNextNPC(), tid); + + // Finalize Trace Data For Instruction + if (inst->traceData) { + //inst->traceData->setCycle(curTick); + inst->traceData->setFetchSeq(inst->seqNum); + //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst); + inst->traceData->dump(); + delete inst->traceData; + inst->traceData = NULL; + } + + // Set Last Graduated Instruction In Thread State + //thread[tid]->lastGradInst = inst; + + // Increment thread-state's instruction count + thread[tid]->numInst++; + + // Increment thread-state's instruction stats + thread[tid]->numInsts++; + + // Count committed insts per thread stats + committedInsts[tid]++; + + // Count total insts committed stat + totalCommittedInsts++; + + // Count SMT-committed insts per thread stat + if (numActiveThreads() > 1) { + smtCommittedInsts[tid]++; + } + + // Check for instruction-count-based events. + comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); + + // Broadcast to other resources an instruction + // has been completed + resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid); + + // Finally, remove instruction from CPU + removeInst(inst); +} + +void +InOrderCPU::addToRemoveList(DynInstPtr &inst) +{ + removeInstsThisCycle = true; + + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInst(DynInstPtr &inst) +{ + DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x " + "[sn:%lli]\n", + inst->threadNumber, inst->readPC(), inst->seqNum); + + removeInstsThisCycle = true; + + // Remove the instruction. + removeList.push(inst->getInstListIt()); +} + +void +InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num, + unsigned tid) +{ + //assert(!instList[tid].empty()); + + removeInstsThisCycle = true; + + ListIt inst_iter = instList[tid].end(); + + inst_iter--; + + DPRINTF(InOrderCPU, "Deleting instructions from CPU instruction " + "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", + tid, seq_num, (*inst_iter)->seqNum); + + while ((*inst_iter)->seqNum > seq_num) { + + bool break_loop = (inst_iter == instList[tid].begin()); + + squashInstIt(inst_iter, tid); + + inst_iter--; + + if (break_loop) + break; + } +} + + +inline void +InOrderCPU::squashInstIt(const ListIt &instIt, const unsigned &tid) +{ + if ((*instIt)->threadNumber == tid) { + DPRINTF(InOrderCPU, "Squashing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*instIt)->threadNumber, + (*instIt)->seqNum, + (*instIt)->readPC()); + + (*instIt)->setSquashed(); + + removeList.push(instIt); + } +} + + +void +InOrderCPU::cleanUpRemovedInsts() +{ + while (!removeList.empty()) { + DPRINTF(InOrderCPU, "Removing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*removeList.front())->threadNumber, + (*removeList.front())->seqNum, + (*removeList.front())->readPC()); + + DynInstPtr inst = *removeList.front(); + int tid = inst->threadNumber; + + // Make Sure Resource Schedule Is Emptied Out + ThePipeline::ResSchedule *inst_sched = &inst->resSched; + while (!inst_sched->empty()) { + ThePipeline::ScheduleEntry* sch_entry = inst_sched->top(); + inst_sched->pop(); + delete sch_entry; + } + + // Remove From Register Dependency Map, If Necessary + archRegDepMap[(*removeList.front())->threadNumber]. + remove((*removeList.front())); + + + // Clear if Non-Speculative + if (inst->staticInst && + inst->seqNum == nonSpecSeqNum[tid] && + nonSpecInstActive[tid] == true) { + nonSpecInstActive[tid] = false; + } + + instList[tid].erase(removeList.front()); + + removeList.pop(); + + DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n", + inst->seqNum, + 0/*inst->curCount()*/); + + } + + removeInstsThisCycle = false; +} + +void +InOrderCPU::cleanUpRemovedReqs() +{ + while (!reqRemoveList.empty()) { + ResourceRequest *res_req = reqRemoveList.front(); + + DPRINTF(RefCount, "[tid:%i]: Removing Request, " + "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n", + res_req->inst->threadNumber, + res_req->inst->seqNum, + res_req->getSlot(), + res_req->getStageNum(), + res_req->res->name(), + 0/*res_req->inst->curCount()*/); + + reqRemoveList.pop(); + + delete res_req; + + DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n", + res_req->inst->seqNum, + 0/*res_req->inst->curCount()*/); + } +} + +void +InOrderCPU::cleanUpRemovedEvents() +{ + while (!cpuEventRemoveList.empty()) { + Event *cpu_event = cpuEventRemoveList.front(); + cpuEventRemoveList.pop(); + delete cpu_event; + } +} + +/* + +void +InOrderCPU::removeAllInsts() +{ + instList.clear(); +} +*/ + +void +InOrderCPU::dumpInsts() +{ + int num = 0; + + ListIt inst_list_it = instList[0].begin(); + + cprintf("Dumping Instruction List\n"); + + while (inst_list_it != instList[0].end()) { + cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, + (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } +} +/* + +void +InOrderCPU::wakeDependents(DynInstPtr &inst) +{ + iew.wakeDependents(inst); +} +*/ + +void +InOrderCPU::wakeCPU() +{ + if (/*activityRec.active() || */tickEvent.scheduled()) { + DPRINTF(Activity, "CPU already running.\n"); + return; + } + + DPRINTF(Activity, "Waking up CPU\n"); + + //idleCycles += (curTick - 1) - lastRunningCycle; + + mainEventQueue.schedule(&tickEvent, curTick); +} + +void +InOrderCPU::syscall(int64_t callnum, int tid) +{ + DPRINTF(InOrderCPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); + + // Clear Non-Speculative Block Variable + nonSpecInstActive[tid] = false; +} + +IntReg +InOrderCPU::getSyscallArg(int idx, int tid) +{ + return readIntReg(ArgumentReg0 + idx, tid); +} + +void +InOrderCPU::setSyscallArg(int idx, IntReg val, int tid) +{ + setIntReg(ArgumentReg0 + idx, val, tid); +} + +void +InOrderCPU::setSyscallReturn(SyscallReturn return_value, int tid) +{ + if (return_value.successful()) { + // no error + setIntReg(SyscallSuccessReg, 0, tid); + setIntReg(ReturnValueReg, return_value.value(), tid); + } else { + // got an error, return details + setIntReg(SyscallSuccessReg, (IntReg) -1, tid); + setIntReg(ReturnValueReg, -return_value.value(), tid); + } +} + +Fault +InOrderCPU::read(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} + +Fault +InOrderCPU::write(DynInstPtr inst) +{ + Resource *mem_res = resPool->getResource(dataPortIdx); + return mem_res->doDataAccess(inst); +} diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh new file mode 100644 index 000000000..cd1eb6f92 --- /dev/null +++ b/src/cpu/inorder/cpu.hh @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CPU_HH__ +#define __CPU_INORDER_CPU_HH__ + +#include +#include +#include +#include +#include + +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/activity.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/o3/dep_graph.hh" +#include "cpu/o3/rename_map.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" +#include "sim/process.hh" + +class ThreadContext; +class MemInterface; +class MemObject; +class Process; +class ResourcePool; + +class InOrderCPU : public BaseCPU +{ + + protected: + typedef ThePipeline::Params Params; + typedef InOrderThreadState Thread; + + //ISA TypeDefs + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + typedef SimpleRenameMap RenameMap; + + //DynInstPtr TypeDefs + typedef ThePipeline::DynInstPtr DynInstPtr; + typedef std::list::iterator ListIt; + + //TimeBuffer TypeDefs + typedef TimeBuffer StageQueue; + + friend class Resource; + + public: + /** Constructs a CPU with the given parameters. */ + InOrderCPU(Params *params); + + /** CPU ID */ + int cpu_id; + + /** Type of core that this is */ + std::string coreType; + + int readCpuId() { return cpu_id; } + + void setCpuId(int val) { cpu_id = val; } + + Params *cpu_params; + + TheISA::ITB * itb; + TheISA::DTB * dtb; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + /** Define TickEvent for the CPU */ + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(InOrderCPU *c); + + /** Processes a tick event, calling tick() on the CPU. */ + void process(); + + /** Returns the description of the tick event. */ + const char *description(); + }; + + /** The tick event used for scheduling CPU ticks. */ + TickEvent tickEvent; + + /** Schedule tick event, regardless of its current state. */ + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay))); + else if (!tickEvent.scheduled()) + mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay))); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + // List of Events That can be scheduled from + // within the CPU. + // NOTE(1): The Resource Pool also uses this event list + // to schedule events broadcast to all resources interfaces + // NOTE(2): CPU Events usually need to schedule a corresponding resource + // pool event. + enum CPUEventType { + ActivateThread, + DeallocateThread, + SuspendThread, + DisableThreads, + EnableThreads, + DisableVPEs, + EnableVPEs, + Trap, + InstGraduated, + SquashAll, + UpdatePCs, + NumCPUEvents + }; + + /** Define CPU Event */ + class CPUEvent : public Event + { + protected: + InOrderCPU *cpu; + + public: + CPUEventType cpuEventType; + unsigned tid; + unsigned vpe; + Fault fault; + + public: + /** Constructs a CPU event. */ + CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault, + unsigned _tid, unsigned _vpe); + + /** Set Type of Event To Be Scheduled */ + void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe) + { + fault = _fault; + cpuEventType = e_type; + tid = _tid; + vpe = _vpe; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + /** Schedule a CPU Event */ + void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid, + unsigned vpe, unsigned delay = 0); + + public: + /** Interface between the CPU and CPU resources. */ + ResourcePool *resPool; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** Used by resources to signify a denied access to a resource. */ + ResourceRequest *dummyReq; + + /** Identifies the resource id that identifies a fetch + * access unit. + */ + unsigned fetchPortIdx; + + /** Identifies the resource id that identifies a data + * access unit. + */ + unsigned dataPortIdx; + + /** The Pipeline Stages for the CPU */ + PipelineStage *pipelineStage[ThePipeline::NumStages]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** The Register File for the CPU */ + /** @TODO: This regFile wont be a sufficient solution for out-of-order, add register + * files as a resource in order to handle ths problem + */ + TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];; + TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];; + TheISA::MiscRegFile miscRegFile; + + /** Dependency Tracker for Integer & Floating Point Regs */ + RegDepMap archRegDepMap[ThePipeline::MaxThreads]; + + /** Global communication structure */ + TimeBuffer timeBuffer; + + /** Communication structure that sits in between pipeline stages */ + StageQueue *stageQueue[ThePipeline::NumStages-1]; + + public: + + /** Registers statistics. */ + void regStats(); + + /** Ticks CPU, calling tick() on each stage, and checking the overall + * activity to see if the CPU should deschedule itself. + */ + void tick(); + + /** Initialize the CPU */ + void init(); + + /** Reset State in the CPU */ + void reset(); + + /** Get a Memory Port */ + Port* getPort(const std::string &if_name, int idx = 0); + + /** trap() - sets up a trap event on the cpuTraps to handle given fault. + * trapCPU() - Traps to handle given fault + */ + void trap(Fault fault, unsigned tid, int delay = 0); + void trapCPU(Fault fault, unsigned tid); + + /** Setup CPU to insert a thread's context */ + void insertThread(unsigned tid); + + /** Remove all of a thread's context from CPU */ + void removeThread(unsigned tid); + + /** Add Thread to Active Threads List. */ + void activateContext(unsigned tid, int delay = 0); + void activateThread(unsigned tid); + + /** Remove Thread from Active Threads List */ + void suspendContext(unsigned tid, int delay = 0); + void suspendThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(unsigned tid, int delay = 0); + void deallocateThread(unsigned tid); + void deactivateThread(unsigned tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(unsigned tid, int delay = 0); + + void removePipelineStalls(unsigned tid); + + void squashThreadInPipeline(unsigned tid); + + /// Notify the CPU to enable a virtual processor element. + virtual void enableVirtProcElement(unsigned vpe); + void enableVPEs(unsigned vpe); + + /// Notify the CPU to disable a virtual processor element. + virtual void disableVirtProcElement(unsigned tid, unsigned vpe); + void disableVPEs(unsigned tid, unsigned vpe); + + /// Notify the CPU that multithreading is enabled. + virtual void enableMultiThreading(unsigned vpe); + void enableThreads(unsigned vpe); + + /// Notify the CPU that multithreading is disabled. + virtual void disableMultiThreading(unsigned tid, unsigned vpe); + void disableThreads(unsigned tid, unsigned vpe); + + // Sets a thread-rescheduling condition. + void setThreadRescheduleCondition(uint32_t tid) + { + //@TODO: IMPLEMENT ME + } + + /** Activate a Thread When CPU Resources are Available. */ + void activateWhenReady(int tid); + + /** Add or Remove a Thread Context in the CPU. */ + void doContextSwitch(); + + /** Update The Order In Which We Process Threads. */ + void updateThreadPriority(); + + /** Switches a Pipeline Stage to Active. (Unused currently) */ + void switchToActive(int stage_idx) + { /*pipelineStage[stage_idx]->switchToActive();*/ } + + /** Switches out this CPU. (Unused currently) */ + //void switchOut(Sampler *sampler); + + /** Signals to this CPU that a stage has completed switching out. (Unused currently)*/ + void signalSwitched(); + + /** Takes over from another CPU. (Unused currently)*/ + void takeOverFrom(BaseCPU *oldCPU); + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq(unsigned tid) + { return globalSeqNum[tid]++; } + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum nextInstSeqNum(unsigned tid) + { return globalSeqNum[tid]; } + + /** Increment Instruction Sequence Number */ + void incrInstSeqNum(unsigned tid) + { globalSeqNum[tid]++; } + + /** Set Instruction Sequence Number */ + void setInstSeqNum(unsigned tid, InstSeqNum seq_num) + { + globalSeqNum[tid] = seq_num; + } + + InstSeqNum getNextEventNum() + { + return cpuEventNum++; + } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } + + /** Register file accessors */ + uint64_t readIntReg(int reg_idx, unsigned tid); + + FloatReg readFloatReg(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + FloatRegBits readFloatRegBits(int reg_idx, unsigned tid, + int width = TheISA::SingleWidth); + + void setIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setFloatReg(int reg_idx, FloatReg val, unsigned tid, + int width = TheISA::SingleWidth); + + void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, + int width = TheISA::SingleWidth); + + /** Reads a miscellaneous register. */ + MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + + /** Reads a int/fp/misc reg. from another thread depending on ISA-defined + * target thread + */ + uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1); + + /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined + * target thread + */ + void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid); + + /** Reads the commit PC of a specific thread. */ + uint64_t readPC(unsigned tid); + + /** Sets the commit PC of a specific thread. */ + void setPC(Addr new_PC, unsigned tid); + + /** Reads the next PC of a specific thread. */ + uint64_t readNextPC(unsigned tid); + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid); + + /** Reads the next NPC of a specific thread. */ + uint64_t readNextNPC(unsigned tid); + + /** Sets the next NPC of a specific thread. */ + void setNextNPC(uint64_t val, unsigned tid); + + /** Add Destination Register To Dependency Maps */ + //void addToRegDepMap(DynInstPtr &inst); + + /** Function to add instruction onto the head of the list of the + * instructions. Used when new instructions are fetched. + */ + ListIt addInst(DynInstPtr &inst); + + /** Function to tell the CPU that an instruction has completed. */ + void instDone(DynInstPtr inst, unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from CPU */ + void removeInst(DynInstPtr &inst); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + /** Cleans up all instructions on the instruction remove list. */ + void cleanUpRemovedInsts(); + + /** Cleans up all instructions on the request remove list. */ + void cleanUpRemovedReqs(); + + /** Cleans up all instructions on the CPU event remove list. */ + void cleanUpRemovedEvents(); + + /** Debug function to print all instructions on the list. */ + void dumpInsts(); + + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Forwards an instruction read to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault read(DynInstPtr inst); + + /** Forwards an instruction write. to the appropriate data + * resource (indexes into Resource Pool thru "dataPortIdx") + */ + Fault write(DynInstPtr inst); + + /** Executes a syscall.*/ + void syscall(int64_t callnum, int tid); + + /** Gets a syscall argument. */ + IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); + + public: + /** Per-Thread List of all the instructions in flight. */ + std::list instList[ThePipeline::MaxThreads]; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue removeList; + + /** List of all the resource requests that will be removed at the end of this + * cycle. + */ + std::queue reqRemoveList; + + /** List of all the cpu event requests that will be removed at the end of + * the current cycle. + */ + std::queue cpuEventRemoveList; + +#ifdef DEBUG + /** Debug structure to keep track of the sequence numbers still in + * flight. + */ + std::set snList; +#endif + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; + + /** True if there is non-speculative Inst Active In Pipeline. Lets any + * execution unit know, NOT to execute while the instruction is active. + */ + bool nonSpecInstActive[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of current non-speculative instruction. */ + InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** Instruction Seq. Num of last instruction squashed in pipeline */ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Last Cycle that the CPU squashed instruction end. */ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + std::list fetchPriorityList; + + /** Rename Map for architectural-to-physical register mappings. + * In a In-order processor, the mapping is fixed + * (e.g. Thread 1: 0-31, Thread 1: 32-63, etc.) + * In a Out-of-Order processor, this is used to maintain + * sequential consistency (?right word here?). + */ + RenameMap renameMap[ThePipeline::MaxThreads]; + + protected: + /** Active Threads List */ + std::list activeThreads; + + /** Current Threads List */ + std::list currentThreads; + + /** Suspended Threads List */ + std::list suspendedThreads; + + /** Thread Status Functions (Unused Currently) */ + bool isThreadInCPU(unsigned tid); + bool isThreadActive(unsigned tid); + bool isThreadSuspended(unsigned tid); + void addToCurrentThreads(unsigned tid); + void removeFromCurrentThreads(unsigned tid); + + private: + /** The activity recorder; used to tell if the CPU has any + * activity remaining or if it can go to idle and deschedule + * itself. + */ + ActivityRecorder activityRec; + + public: + void readFunctional(Addr addr, uint32_t &buffer); + + /** Number of Active Threads in the CPU */ + int numActiveThreads() { return activeThreads.size(); } + + /** Records that there was time buffer activity this cycle. */ + void activityThisCycle() { activityRec.activity(); } + + /** Changes a stage's status to active within the activity recorder. */ + void activateStage(const int idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const int idx) + { activityRec.deactivateStage(idx); } + + /** Wakes the CPU, rescheduling the CPU if it's not already active. */ + void wakeCPU(); + + /** Gets a free thread id. Use if thread ids change across system. */ + int getFreeTid(); + + // LL/SC debug functionality + unsigned stCondFails; + unsigned readStCondFailures() { return stCondFails; } + unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; } + + public: + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid = 0) + { + return thread[tid]->getTC(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum[ThePipeline::MaxThreads]; + + /** The global event number counter. */ + InstSeqNum cpuEventNum; + + /** Counter of how many stages have completed switching out. */ + int switchCount; + + /** Pointers to all of the threads in the CPU. */ + std::vector thread; + + /** Pointer to the icache interface. */ + MemInterface *icacheInterface; + /** Pointer to the dcache interface. */ + MemInterface *dcacheInterface; + + /** Whether or not the CPU should defer its registration. */ + bool deferRegistration; + + /** Per-Stage Instruction Tracing */ + bool stageTracing; + + /** Is there a context switch pending? */ + bool contextSwitch; + + /** Threads Scheduled to Enter CPU */ + std::list cpuWaitList; + + /** The cycle that the CPU was last running, used for statistics. */ + Tick lastRunningCycle; + + /** Number of Threads the CPU can process */ + unsigned numThreads; + + /** Number of Virtual Processors the CPU can process */ + unsigned numVirtProcs; + + /** Update Thread , used for statistic purposes*/ + inline void tickThreadStats(); + + /** Per-Thread Tick */ + Stats::Vector<> threadCycles; + + /** Tick for SMT */ + Stats::Scalar<> smtCycles; + + /** Stat for total number of times the CPU is descheduled. */ + Stats::Scalar<> timesIdled; + + /** Stat for total number of cycles the CPU spends descheduled. */ + Stats::Scalar<> idleCycles; + + /** Stat for the number of committed instructions per thread. */ + Stats::Vector<> committedInsts; + + /** Stat for the number of committed instructions per thread. */ + Stats::Vector<> smtCommittedInsts; + + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> totalCommittedInsts; + + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + + /** Stat for the SMT-CPI per thread. */ + Stats::Formula smtCpi; + + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + + /** Stat for the total IPC. */ + Stats::Formula smtIpc; + + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc new file mode 100644 index 000000000..ce30f8466 --- /dev/null +++ b/src/cpu/inorder/first_stage.cc @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resources/resource_list.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace ThePipeline; + +FirstStage::FirstStage(Params *params, unsigned stage_num) + : PipelineStage(params, stage_num) +{ + for(int tid=0; tid < this->numThreads; tid++) { + stageStatus[tid] = Running; + } + + numFetchingThreads = 1; + + fetchPolicy = RoundRobin; +} + +void +FirstStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + fetchPriorityList = &cpu->fetchPriorityList; + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); +} + + +void +FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + //stageStatus[tid] = Squashing; + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n"); + while (!insts[tid].empty()) { + if (insts[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= " + "squashing seqNum %i.\n", + tid, + insts[tid].front()->seqNum, + squash_seq_num); + + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + insts[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, insts[tid].front()->seqNum, insts[tid].front()->PC); + insts[tid].pop(); + } + + // Now that squash has propagated to the first stage, + // Alert CPU to remove instructions from the CPU instruction list. + // @todo: Move this to the CPU object. + cpu->removeInstsUntil(squash_seq_num, tid); +} + +void +FirstStage::processStage(bool &status_change) +{ + list::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + status_change = checkSignalsAndUpdate(tid) || status_change; + } + + for (int threadFetched = 0; threadFetched < numFetchingThreads; + threadFetched++) { + int tid = getFetchingThread(fetchPolicy); + + if (tid >= 0) { + DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid); + processThread(status_change, tid); + } else { + DPRINTF(InOrderStage, "No more threads to fetch from.\n"); + } + } +} + +//@TODO: Note in documentation, that when you make a pipeline stage change, then +//make sure you change the first stage too +void +FirstStage::processInsts(unsigned tid) +{ + bool all_reqs_completed = true; + + for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToNextStage(); insts_fetched++) { + DynInstPtr inst; + bool new_inst = false; + + if (!insts[tid].empty()) { + inst = insts[tid].front(); + } else { + // Get new instruction. + new_inst = true; + + inst = new InOrderDynInst(cpu, + cpu->thread[tid], + cpu->nextInstSeqNum(tid), + tid); + +#if TRACING_ON + inst->traceData = + tracer->getInstRecord(ThePipeline::NumStages, + cpu->stageTracing, + cpu->thread[tid]->getTC()); + +#endif // TRACING_ON + + DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Add instruction to the CPU's list of instructions. + inst->setInstListIt(cpu->addInst(inst)); + + DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n", + inst->readTid(), + inst->seqNum, + 0/*inst->curCount()*/); + + // Create Front-End Resource Schedule For Instruction + ThePipeline::createFrontEndSchedule(inst); + } + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + all_reqs_completed = processInstSchedule(inst); + + if (!all_reqs_completed) { + if (new_inst) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all " + "requests for this stage. Keep in stage inst. " + "list.\n", tid, inst->seqNum); + insts[tid].push(inst); + } + break; + } else if (!insts[tid].empty()){ + insts[tid].pop(); + } + + sendInstToNextStage(inst); + //++stageProcessedInsts; + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +int +FirstStage::getFetchingThread(FetchPriority &fetch_priority) +{ + if (numThreads > 1) { + switch (fetch_priority) { + + case SingleThread: + return 0; + + case RoundRobin: + return roundRobin(); + + default: + return -1; + } + } else { + int tid = *((*activeThreads).begin()); + + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + return tid; + } else { + return -1; + } + } + +} + +int +FirstStage::roundRobin() +{ + list::iterator pri_iter = (*fetchPriorityList).begin(); + list::iterator end = (*fetchPriorityList).end(); + + int high_pri; + + while (pri_iter != end) { + high_pri = *pri_iter; + + assert(high_pri <= numThreads); + + if (stageStatus[high_pri] == Running || + stageStatus[high_pri] == Idle) { + + (*fetchPriorityList).erase(pri_iter); + (*fetchPriorityList).push_back(high_pri); + + return high_pri; + } + + pri_iter++; + } + + return -1; +} diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh new file mode 100644 index 000000000..55914c85c --- /dev/null +++ b/src/cpu/inorder/first_stage.hh @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FIRST_STAGE_HH__ +#define __CPU_INORDER_FIRST_STAGE_HH__ + +#include +#include + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "cpu/inorder/params.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/pipeline_stage.hh" + +class InOrderCPU; + +class FirstStage : public PipelineStage { + public: + FirstStage(ThePipeline::Params *params, unsigned stage_num); + + /** Set Pointer to CPU */ + void setCPU(InOrderCPU *cpu_ptr); + + /** Evaluate Stage Info. & Execute Stage */ + void processStage(bool &status_change); + + /** Process All Instructions Available */ + void processInsts(unsigned tid); + + /** Squash Instructions Above a Seq. Num */ + void squash(InstSeqNum squash_seq_num, unsigned tid); + + /** There are no insts. coming from previous stages, so there is + * no need to sort insts here + */ + void sortInsts() {} + + /** There are no skidBuffers for the first stage. So + * just use an empty function. + */ + void skidInsert(unsigned tid) { } + + /** The number of fetching threads in the CPU */ + int numFetchingThreads; + + //@TODO: Add fetch priority information to a resource class... + /** Fetching Policy, Add new policies here.*/ + enum FetchPriority { + SingleThread, + RoundRobin + }; + + /** Fetch policy. */ + FetchPriority fetchPolicy; + + /** List that has the threads organized by priority. */ + std::list *fetchPriorityList; + + /** Return the next fetching thread */ + int getFetchingThread(FetchPriority &fetch_priority); + + /** Return next thred given Round Robin Policy for Thread Fetching */ + int roundRobin(); +}; + +#endif // __CPU_INORDER_FIRST_STAGE_HH__ diff --git a/src/cpu/inorder/inorder_cpu_builder.cc b/src/cpu/inorder/inorder_cpu_builder.cc new file mode 100644 index 000000000..b1b4bea80 --- /dev/null +++ b/src/cpu/inorder/inorder_cpu_builder.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include + +#include "cpu/base.hh" +#include "cpu/inst_seq.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/cpu.hh" +//#include "cpu/inorder/params.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "params/InOrderCPU.hh" + +InOrderCPU * +InOrderCPUParams::create() +{ + int actual_num_threads = + (numThreads >= workload.size()) ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + + numThreads = actual_num_threads; + + instShiftAmt = 2; + + return new InOrderCPU(this); +} + + + diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc new file mode 100644 index 000000000..89362c656 --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include +#include + +#include "base/cprintf.hh" +#include "base/trace.hh" + +#include "arch/faults.hh" +#include "cpu/exetrace.hh" +#include "mem/request.hh" + +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC, + Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu) + : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + + PC = inst_PC; + nextPC = PC + sizeof(MachInst); + nextNPC = nextPC + sizeof(MachInst); + predPC = pred_PC; + + initVars(); +} + +InOrderDynInst::InOrderDynInst(InOrderCPU *cpu, + InOrderThreadState *state, + InstSeqNum seq_num, + unsigned tid) + : traceData(NULL), cpu(cpu) +{ + seqNum = seq_num; + thread = state; + threadNumber = tid; + initVars(); +} + +InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst) + : staticInst(_staticInst), traceData(NULL) +{ + seqNum = 0; + initVars(); +} + +InOrderDynInst::InOrderDynInst() + : traceData(NULL), cpu(cpu) +{ initVars(); } + +int InOrderDynInst::instcount = 0; + + +void +InOrderDynInst::setMachInst(ExtMachInst machInst) +{ + staticInst = StaticInst::decode(machInst, PC); + + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } +} + +void +InOrderDynInst::initVars() +{ + req = NULL; + effAddr = 0; + physEffAddr = 0; + + readyRegs = 0; + + nextStage = 0; + nextInstStageNum = 0; + + for(int i = 0; i < MaxInstDestRegs; i++) + instResult[i].val.integer = 0; + + status.reset(); + + memAddrReady = false; + eaCalcDone = false; + memOpDone = false; + + predictTaken = false; + procDelaySlotOnMispred = false; + + lqIdx = -1; + sqIdx = -1; + + // Also make this a parameter, or perhaps get it from xc or cpu. + asid = 0; + + virtProcNumber = 0; + + // Initialize the fault to be NoFault. + fault = NoFault; + + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + if (this->staticInst) { + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } + } + + // Update Instruction Count for this instruction + ++instcount; + if (instcount > 500) { + fatal("Number of Active Instructions in CPU is too high. " + "(Not Dereferencing Ptrs. Correctly?)\n"); + } + + + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n", + threadNumber, seqNum, instcount); + +#ifdef DEBUG + cpu->snList.insert(seqNum); +#endif +} + + +InOrderDynInst::~InOrderDynInst() +{ + if (req) { + delete req; + } + + if (traceData) { + delete traceData; + } + + fault = NoFault; + + --instcount; + + deleteStages(); + + DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n", + threadNumber, seqNum, instcount); +#ifdef DEBUG + cpu->snList.erase(seqNum); +#endif +} + +void +InOrderDynInst::setStaticInst(StaticInstPtr &static_inst) +{ + this->staticInst = static_inst; + + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + if (this->staticInst) { + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } + } +} + +Fault +InOrderDynInst::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +Fault +InOrderDynInst::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + + +Fault +InOrderDynInst::completeAcc(Packet *pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +InstStage *InOrderDynInst::addStage() +{ + this->currentInstStage = new InstStage(this, nextInstStageNum++); + instStageList.push_back( this->currentInstStage ); + return this->currentInstStage; +} + +InstStage *InOrderDynInst::addStage(int stage_num) +{ + nextInstStageNum = stage_num; + return InOrderDynInst::addStage(); +} + +void InOrderDynInst::deleteStages() { + std::list::iterator list_it = instStageList.begin(); + std::list::iterator list_end = instStageList.end(); + + while(list_it != list_end) { + delete *list_it; + list_it++; + } +} + +Fault +InOrderDynInst::calcEA() +{ + return staticInst->eaCompInst()->execute(this, this->traceData); +} + +Fault +InOrderDynInst::memAccess() +{ + //return staticInst->memAccInst()->execute(this, this->traceData); + return initiateAcc( ); +} + +void +InOrderDynInst::syscall(int64_t callnum) +{ + cpu->syscall(callnum, this->threadNumber); +} + +void +InOrderDynInst::prefetch(Addr addr, unsigned flags) +{ + // This is the "functional" implementation of prefetch. Not much + // happens here since prefetches don't affect the architectural + // state. +/* + // Generate a MemReq so we can translate the effective address. + MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); + req->asid = asid; + + // Prefetches never cause faults. + fault = NoFault; + + // note this is a local, not InOrderDynInst::fault + Fault trans_fault = cpu->translateDataReadReq(req); + + if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { + // It's a valid address to cacheable space. Record key MemReq + // parameters so we can generate another one just like it for + // the timing access without calling translate() again (which + // might mess up the TLB). + effAddr = req->vaddr; + physEffAddr = req->paddr; + memReqFlags = req->flags; + } else { + // Bogus address (invalid or uncacheable space). Mark it by + // setting the eff_addr to InvalidAddr. + effAddr = physEffAddr = MemReq::inval_addr; + } + + if (traceData) { + traceData->setAddr(addr); + } +*/ +} + +void +InOrderDynInst::writeHint(Addr addr, int size, unsigned flags) +{ + // Not currently supported. +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copySrcTranslate(Addr src) +{ + // Not currently supported. + return NoFault; +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +Fault +InOrderDynInst::copy(Addr dest) +{ + // Not currently supported. + return NoFault; +} + +void +InOrderDynInst::releaseReq(ResourceRequest* req) +{ + std::list::iterator list_it = reqList.begin(); + std::list::iterator list_end = reqList.end(); + + while(list_it != list_end) { + if((*list_it)->getResIdx() == req->getResIdx() && + (*list_it)->getSlot() == req->getSlot()) { + DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n", + threadNumber, seqNum, req->res->name()); + reqList.erase(list_it); + return; + } + list_it++; + } + + panic("Releasing Res. Request That Isnt There!\n"); +} + +/** Records an integer source register being set to a value. */ +void +InOrderDynInst::setIntSrc(int idx, uint64_t val) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n", + threadNumber, seqNum, idx, val); + instSrc[idx].integer = val; +} + +/** Records an fp register being set to a value. */ +void +InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width) +{ + if (width == 32) + instSrc[idx].fp = val; + else if (width == 64) + instSrc[idx].dbl = val; + else + panic("Unsupported width!"); +} + +/** Records an fp register being set to an integer value. */ +void +InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val) +{ + instSrc[idx].integer = val; +} + +/** Reads a integer register. */ +IntReg +InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid) +{ + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n", + threadNumber, seqNum, idx, instSrc[idx].integer); + return instSrc[idx].integer; +} + +/** Reads a FP register. */ +FloatReg +InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].fp; +} + + +/** Reads a FP register as a integer. */ +FloatRegBits +InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width) +{ + return instSrc[idx].integer; +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscReg(int misc_reg) +{ + return this->cpu->readMiscReg(misc_reg, threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegNoEffect(int misc_reg) +{ + return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber); +} + +/** Reads a miscellaneous register. */ +MiscReg +InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx) +{ + return this->cpu->readMiscRegNoEffect( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); +} + +/** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ +MiscReg +InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx) +{ + return this->cpu->readMiscReg( + si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + this->threadNumber); +} + +/** Sets a misc. register. */ +void +InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscRegNoEffect( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +void +InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx, + const MiscReg &val) +{ + instResult[si->destRegIdx(idx)].val.integer = val; + instResult[si->destRegIdx(idx)].tick = curTick; + + this->cpu->setMiscReg( + si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag, + val, this->threadNumber); +} + +MiscReg +InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + return this->cpu->readIntReg(reg_idx, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + return this->cpu->readFloatRegBits(reg_idx, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File + } +} + +/** Sets a Integer register. */ +void +InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a FP register. */ +void +InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) +{ + if (width == 32) + instResult[idx].val.fp = val; + else if (width == 64) + instResult[idx].val.dbl = val; + else + panic("Unsupported Floating Point Width!"); + + instResult[idx].tick = curTick; +} + +/** Sets a FP register as a integer. */ +void +InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx, + FloatRegBits val, int width) +{ + instResult[idx].val.integer = val; + instResult[idx].tick = curTick; +} + +/** Sets a misc. register. */ +/* Alter this when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber); +} + +/** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ +/* Alter this if/when wanting to *speculate* on Miscellaneous registers */ +void +InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val) +{ + this->cpu->setMiscReg(misc_reg, val, threadNumber); +} + +void +InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid) +{ + if (tid == -1) { + tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber)); + } + + if (reg_idx < FP_Base_DepTag) { // Integer Register File + this->cpu->setIntReg(reg_idx, val, tid); + } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File + reg_idx -= FP_Base_DepTag; + this->cpu->setFloatRegBits(reg_idx, val, tid); + } else { + reg_idx -= Ctrl_Base_DepTag; + this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File + } +} + +void +InOrderDynInst::deallocateContext(int thread_num) +{ + this->cpu->deallocateContext(thread_num); +} + +void +InOrderDynInst::enableVirtProcElement(unsigned vpe) +{ + this->cpu->enableVirtProcElement(vpe); +} + +void +InOrderDynInst::disableVirtProcElement(unsigned vpe) +{ + this->cpu->disableVirtProcElement(threadNumber, vpe); +} + +void +InOrderDynInst::enableMultiThreading(unsigned vpe) +{ + this->cpu->enableMultiThreading(vpe); +} + +void +InOrderDynInst::disableMultiThreading(unsigned vpe) +{ + this->cpu->disableMultiThreading(threadNumber, vpe); +} + +void +InOrderDynInst::setThreadRescheduleCondition(uint32_t cond) +{ + this->cpu->setThreadRescheduleCondition(cond); +} + +template +inline Fault +InOrderDynInst::read(Addr addr, T &data, unsigned flags) +{ + return cpu->read(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + +template<> +Fault +InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + +template +inline Fault +InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + //memcpy(memData, gtoh(data), sizeof(T)); + storeData = data; + + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n", + threadNumber, seqNum, memData); + return cpu->write(this); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +InOrderDynInst::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +InOrderDynInst::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +InOrderDynInst::dump() +{ + cprintf("T%d : %#08d `", threadNumber, PC); + cout << staticInst->disassemble(PC); + cprintf("'\n"); +} + +void +InOrderDynInst::dump(std::string &outstring) +{ + std::ostringstream s; + s << "T" << threadNumber << " : 0x" << PC << " " + << staticInst->disassemble(PC); + + outstring = s.str(); +} + + +#define NOHASH +#ifndef NOHASH + +#include "base/hashmap.hh" + +unsigned int MyHashFunc(const InOrderDynInst *addr) +{ + unsigned a = (unsigned)addr; + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; +} + +typedef m5::hash_map +my_hash_t; + +my_hash_t thishash; +#endif + +#ifdef DEBUG + +void +InOrderDynInst::dumpSNList() +{ + std::set::iterator sn_it = cpu->snList.begin(); + + int count = 0; + while (sn_it != cpu->snList.end()) { + cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it)); + count++; + sn_it++; + } +} +#endif + diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh new file mode 100644 index 000000000..9f52f954f --- /dev/null +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -0,0 +1,975 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * Copyright (c) 2004-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: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_DYN_INST_HH__ +#define __CPU_INORDER_DYN_INST_HH__ + +#include +#include +#include + +#include "arch/faults.hh" +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/inst_seq.hh" +#include "cpu/op_class.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "mem/packet.hh" +#include "sim/system.hh" + +/** + * @file + * Defines a dynamic instruction context for a inorder CPU model. + */ + +// Forward declaration. +class StaticInstPtr; +class ResourceRequest; + +class InOrderDynInst : public FastAlloc, public RefCounted +{ + public: + // Binary machine instruction type. + typedef TheISA::MachInst MachInst; + // Extended machine instruction type + typedef TheISA::ExtMachInst ExtMachInst; + // Logical register index type. + typedef TheISA::RegIndex RegIndex; + // Integer register type. + typedef TheISA::IntReg IntReg; + // Floating point register type. + typedef TheISA::FloatReg FloatReg; + // Floating point register type. + typedef TheISA::MiscReg MiscReg; + + typedef short int PhysRegIndex; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst*. + */ + typedef RefCountingPtr DynInstPtr; + + // The list of instructions iterator type. + typedef std::list::iterator ListIt; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. + * @param inst The binary instruction. + * @param PC The PC of the instruction. + * @param pred_PC The predicted next PC. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + */ + InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, + InOrderCPU *cpu); + + /** BaseDynInst constructor given a binary instruction. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + * NOTE: Must set Binary Instrution through Member Function + */ + InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num, + unsigned tid); + + /** BaseDynInst constructor given a StaticInst pointer. + * @param _staticInst The StaticInst for this BaseDynInst. + */ + InOrderDynInst(StaticInstPtr &_staticInst); + + /** Skeleton Constructor. */ + InOrderDynInst(); + + /** InOrderDynInst destructor. */ + ~InOrderDynInst(); + + public: + /** The sequence number of the instruction. */ + InstSeqNum seqNum; + + /** The sequence number of the instruction. */ + InstSeqNum bdelaySeqNum; + + enum Status { + RegDepMapEntry, /// Instruction has been entered onto the RegDepMap + IqEntry, /// Instruction is in the IQ + RobEntry, /// Instruction is in the ROB + LsqEntry, /// Instruction is in the LSQ + Completed, /// Instruction has completed + ResultReady, /// Instruction has its result + CanIssue, /// Instruction can issue and execute + Issued, /// Instruction has issued + Executed, /// Instruction has executed + CanCommit, /// Instruction can commit + AtCommit, /// Instruction has reached commit + Committed, /// Instruction has committed + Squashed, /// Instruction is squashed + SquashedInIQ, /// Instruction is squashed in the IQ + SquashedInLSQ, /// Instruction is squashed in the LSQ + SquashedInROB, /// Instruction is squashed in the ROB + RecoverInst, /// Is a recover instruction + BlockingInst, /// Is a blocking instruction + ThreadsyncWait, /// Is a thread synchronization instruction + SerializeBefore, /// Needs to serialize on + /// instructions ahead of it + SerializeAfter, /// Needs to serialize instructions behind it + SerializeHandled, /// Serialization has been handled + NumStatus + }; + + /** The status of this BaseDynInst. Several bits can be set. */ + std::bitset status; + + /** The thread this instruction is from. */ + short threadNumber; + + /** data address space ID, for loads & stores. */ + short asid; + + /** The virtual processor number */ + short virtProcNumber; + + /** The StaticInst used by this BaseDynInst. */ + StaticInstPtr staticInst; + + /** InstRecord that tracks this instructions. */ + Trace::InOrderTraceRecord *traceData; + + /** Pointer to the Impl's CPU object. */ + InOrderCPU *cpu; + + /** Pointer to the thread state. */ + InOrderThreadState *thread; + + /** The kind of fault this instruction has generated. */ + Fault fault; + + /** The memory request. */ + Request *req; + + /** Pointer to the data for the memory access. */ + uint8_t *memData; + + /** Data used for a store for operation. */ + uint64_t loadData; + + /** Data used for a store for operation. */ + uint64_t storeData; + + /** The resource schedule for this inst */ + ThePipeline::ResSchedule resSched; + + /** List of active resource requests for this instruction */ + std::list reqList; + + /** The effective virtual address (lds & stores only). */ + Addr effAddr; + + /** The effective physical address. */ + Addr physEffAddr; + + /** Effective virtual address for a copy source. */ + Addr copySrcEffAddr; + + /** Effective physical address for a copy source. */ + Addr copySrcPhysEffAddr; + + /** The memory request flags (from translation). */ + unsigned memReqFlags; + + /** How many source registers are ready. */ + unsigned readyRegs; + + /** An instruction src/dest has to be one of these types */ + union InstValue { + uint64_t integer; + float fp; + double dbl; + }; + + /** Result of an instruction execution */ + struct InstResult { + InstValue val; + Tick tick; + }; + + /** The source of the instruction; assumes for now that there's only one + * destination register. + */ + InstValue instSrc[MaxInstSrcRegs]; + + /** The result of the instruction; assumes for now that there's only one + * destination register. + */ + InstResult instResult[MaxInstDestRegs]; + + /** PC of this instruction. */ + Addr PC; + + /** Next non-speculative PC. It is not filled in at fetch, but rather + * once the target of the branch is truly known (either decode or + * execute). + */ + Addr nextPC; + + /** Next next non-speculative PC. It is not filled in at fetch, but rather + * once the target of the branch is truly known (either decode or + * execute). + */ + Addr nextNPC; + + /** Predicted next PC. */ + Addr predPC; + + /** Address to fetch from */ + Addr fetchAddr; + + /** Address to get/write data from/to */ + Addr memAddr; + + /** Whether or not the source register is ready. + * @todo: Not sure this should be here vs the derived class. + */ + bool _readySrcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; + + int nextStage; + + /* vars to keep track of InstStage's - used for resource sched defn */ + int nextInstStageNum; + ThePipeline::InstStage *currentInstStage; + std::list instStageList; + + private: + /** Function to initialize variables in the constructors. */ + void initVars(); + + public: + Tick memTime; + + //////////////////////////////////////////////////////////// + // + // BASE INSTRUCTION INFORMATION. + // + //////////////////////////////////////////////////////////// + void setMachInst(ExtMachInst inst); + + /** Sets the StaticInst. */ + void setStaticInst(StaticInstPtr &static_inst); + + /** Sets the sequence number. */ + void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; } + + /** Sets the ASID. */ + void setASID(short addr_space_id) { asid = addr_space_id; } + + /** Reads the thread id. */ + short readTid() { return threadNumber; } + + /** Sets the thread id. */ + void setTid(unsigned tid) { threadNumber = tid; } + + void setVpn(int id) { virtProcNumber = id; } + + int readVpn() { return virtProcNumber; } + + /** Sets the pointer to the thread state. */ + void setThreadState(InOrderThreadState *state) { thread = state; } + + /** Returns the thread context. */ + ThreadContext *tcBase() { return thread->getTC(); } + + /** Returns the fault type. */ + Fault getFault() { return fault; } + + //////////////////////////////////////////////////////////// + // + // INSTRUCTION TYPES - Forward checks to StaticInst object. + // + //////////////////////////////////////////////////////////// + bool isNop() const { return staticInst->isNop(); } + bool isMemRef() const { return staticInst->isMemRef(); } + bool isLoad() const { return staticInst->isLoad(); } + bool isStore() const { return staticInst->isStore(); } + bool isStoreConditional() const + { return staticInst->isStoreConditional(); } + bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } + bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } + bool isCopy() const { return staticInst->isCopy(); } + bool isInteger() const { return staticInst->isInteger(); } + bool isFloating() const { return staticInst->isFloating(); } + bool isControl() const { return staticInst->isControl(); } + bool isCall() const { return staticInst->isCall(); } + bool isReturn() const { return staticInst->isReturn(); } + bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } + bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } + bool isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } + bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); } + + bool isThreadSync() const { return staticInst->isThreadSync(); } + bool isSerializing() const { return staticInst->isSerializing(); } + bool isSerializeBefore() const + { return staticInst->isSerializeBefore() || status[SerializeBefore]; } + bool isSerializeAfter() const + { return staticInst->isSerializeAfter() || status[SerializeAfter]; } + bool isMemBarrier() const { return staticInst->isMemBarrier(); } + bool isWriteBarrier() const { return staticInst->isWriteBarrier(); } + bool isNonSpeculative() const { return staticInst->isNonSpeculative(); } + bool isQuiesce() const { return staticInst->isQuiesce(); } + bool isIprAccess() const { return staticInst->isIprAccess(); } + bool isUnverifiable() const { return staticInst->isUnverifiable(); } + + ///////////////////////////////////////////// + // + // RESOURCE SCHEDULING + // + ///////////////////////////////////////////// + + void setNextStage(int stage_num) { nextStage = stage_num; } + int getNextStage() { return nextStage; } + + ThePipeline::InstStage *addStage(); + ThePipeline::InstStage *addStage(int stage); + ThePipeline::InstStage *currentStage() { return currentInstStage; } + void deleteStages(); + + /** Add A Entry To Reource Schedule */ + void addToSched(ThePipeline::ScheduleEntry* sched_entry) + { resSched.push(sched_entry); } + + + /** Print Resource Schedule */ + void printSched() + { + using namespace ThePipeline; + + ResSchedule tempSched; + std::cerr << "\tInst. Res. Schedule: "; + while (!resSched.empty()) { + std::cerr << '\t' << resSched.top()->stageNum << "-" + << resSched.top()->resNum << ", "; + + tempSched.push(resSched.top()); + resSched.pop(); + } + + std::cerr << std::endl; + resSched = tempSched; + } + + /** Return Next Resource Stage To Be Used */ + int nextResStage() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->stageNum; + } + + + /** Return Next Resource To Be Used */ + int nextResource() + { + if (resSched.empty()) + return -1; + else + return resSched.top()->resNum; + } + + /** Remove & Deallocate a schedule entry */ + void popSchedEntry() + { + if (!resSched.empty()) { + ThePipeline::ScheduleEntry* sked = resSched.top(); + resSched.pop(); + delete sked; + } + } + + /** Release a Resource Request (Currently Unused) */ + void releaseReq(ResourceRequest* req); + + //////////////////////////////////////////// + // + // INSTRUCTION EXECUTION + // + //////////////////////////////////////////// + /** Returns the opclass of this instruction. */ + OpClass opClass() const { return staticInst->opClass(); } + + /** Executes the instruction.*/ + Fault execute(); + + unsigned curResSlot; + + unsigned getCurResSlot() { return curResSlot; } + + void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; } + + /** Calls a syscall. */ + void syscall(int64_t callnum); + void prefetch(Addr addr, unsigned flags); + void writeHint(Addr addr, int size, unsigned flags); + Fault copySrcTranslate(Addr src); + Fault copy(Addr dest); + + //////////////////////////////////////////////////////////// + // + // MULTITHREADING INTERFACE TO CPU MODELS + // + //////////////////////////////////////////////////////////// + virtual void deallocateContext(int thread_num); + + virtual void enableVirtProcElement(unsigned vpe); + virtual void disableVirtProcElement(unsigned vpe); + + virtual void enableMultiThreading(unsigned vpe); + virtual void disableMultiThreading(unsigned vpe); + + virtual void setThreadRescheduleCondition(uint32_t cond); + + //////////////////////////////////////////////////////////// + // + // PROGRAM COUNTERS - PC/NPC/NPC + // + //////////////////////////////////////////////////////////// + /** Read the PC of this instruction. */ + const Addr readPC() const { return PC; } + + /** Sets the PC of this instruction. */ + void setPC(Addr pc) { PC = pc; } + + /** Returns the next PC. This could be the speculative next PC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextPC() { return nextPC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextPC(uint64_t val) { nextPC = val; } + + /** Returns the next NPC. This could be the speculative next NPC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextNPC() { return nextNPC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextNPC(uint64_t val) { nextNPC = val; } + + //////////////////////////////////////////////////////////// + // + // BRANCH PREDICTION + // + //////////////////////////////////////////////////////////// + /** Set the predicted target of this current instruction. */ + void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; } + + /** Returns the predicted target of the branch. */ + Addr readPredTarg() { return predPC; } + + /** Returns whether the instruction was predicted taken or not. */ + bool predTaken() { return predictTaken; } + + /** Returns whether the instruction mispredicted. */ + bool mispredicted() + { + // Special case since a not-taken, cond. delay slot, effectively + // nullifies the delay slot instruction + if (isCondDelaySlot() && !predictTaken) { + return predPC != nextPC; + } else { + return predPC != nextNPC; + } + } + + /** Returns whether the instruction mispredicted. */ + bool mistargeted() { return predPC != nextNPC; } + + /** Returns the branch target address. */ + Addr branchTarget() const { return staticInst->branchTarget(PC); } + + /** Checks whether or not this instruction has had its branch target + * calculated yet. For now it is not utilized and is hacked to be + * always false. + * @todo: Actually use this instruction. + */ + bool doneTargCalc() { return false; } + + void setBranchPred(bool prediction) { predictTaken = prediction; } + + int squashingStage; + + bool predictTaken; + + bool procDelaySlotOnMispred; + + //////////////////////////////////////////// + // + // MEMORY ACCESS + // + //////////////////////////////////////////// + /** + * Does a read to a given address. + * @param addr The address to read. + * @param data The read's data is written into this parameter. + * @param flags The request's flags. + * @return Returns any fault due to the read. + */ + template + Fault read(Addr addr, T &data, unsigned flags); + + /** + * Does a write to a given address. + * @param data The data to be written. + * @param addr The address to write to. + * @param flags The request's flags. + * @param res The result of the write (for load locked/store conditionals). + * @return Returns any fault due to the write. + */ + template + Fault write(T data, Addr addr, unsigned flags, + uint64_t *res); + + /** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access + * Only valid for memory operations. + */ + Fault initiateAcc(); + + /** Completes a memory access - Only valid for memory operations. */ + Fault completeAcc(Packet *pkt); + + /** Calculates Eff. Addr. part of a memory instruction. */ + Fault calcEA(); + + /** Read Effective Address from instruction & do memory access */ + Fault memAccess(); + + RequestPtr memReq; + + bool memAddrReady; + + bool validMemAddr() + { return memAddrReady; } + + void setMemAddr(Addr addr) + { memAddr = addr; memAddrReady = true;} + + void unsetMemAddr() + { memAddrReady = false;} + + Addr getMemAddr() + { return memAddr; } + + int getMemAccSize() { return staticInst->memAccSize(this); } + + int getMemFlags() { return staticInst->memAccFlags(); } + + /** Sets the effective address. */ + void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } + + /** Returns the effective address. */ + const Addr &getEA() const { return instEffAddr; } + + /** Returns whether or not the eff. addr. calculation has been completed. */ + bool doneEACalc() { return eaCalcDone; } + + /** Returns whether or not the eff. addr. source registers are ready. + * Assume that src registers 1..n-1 are the ones that the + * EA calc depends on. (i.e. src reg 0 is the source of the data to be + * stored) + */ + bool eaSrcsReady() + { + for (int i = 1; i < numSrcRegs(); ++i) { + if (!_readySrcRegIdx[i]) + return false; + } + + return true; + } + + ////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER INDEXING + // + ////////////////////////////////////////////////// + /** Returns the number of source registers. */ + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + + /** Returns the number of destination registers. */ + int8_t numDestRegs() const { return staticInst->numDestRegs(); } + + // the following are used to track physical register usage + // for machines with separate int & FP reg files + int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); } + int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); } + + /** Returns the logical register index of the i'th destination register. */ + RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); } + + /** Returns the logical register index of the i'th source register. */ + RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } + + ////////////////////////////////////////////////// + // + // RENAME/PHYSICAL REGISTER FILE SUPPORT + // + ////////////////////////////////////////////////// + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Returns if a source register is ready. */ + bool isReadySrcRegIdx(int idx) const + { + return this->_readySrcRegIdx[idx]; + } + + /** Records that one of the source registers is ready. */ + void markSrcRegReady() + { + if (++readyRegs == numSrcRegs()) { + status.set(CanIssue); + } + } + + /** Marks a specific register as ready. */ + void markSrcRegReady(RegIndex src_idx) + { + _readySrcRegIdx[src_idx] = true; + + markSrcRegReady(); + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + + PhysRegIndex readDestRegIdx(int idx) + { + return _destRegIdx[idx]; + } + + void setDestRegIdx(int idx, PhysRegIndex dest_idx) + { + _destRegIdx[idx] = dest_idx; + } + + int getDestIdxNum(PhysRegIndex dest_idx) + { + for (int i=0; i < staticInst->numDestRegs(); i++) { + if (_destRegIdx[i] == dest_idx) + return i; + } + + return -1; + } + + PhysRegIndex readSrcRegIdx(int idx) + { + return _srcRegIdx[idx]; + } + + void setSrcRegIdx(int idx, PhysRegIndex src_idx) + { + _srcRegIdx[idx] = src_idx; + } + + int getSrcIdxNum(PhysRegIndex src_idx) + { + for (int i=0; i < staticInst->numSrcRegs(); i++) { + if (_srcRegIdx[i] == src_idx) + return i; + } + + return -1; + } + + //////////////////////////////////////////////////// + // + // SOURCE-DESTINATION REGISTER VALUES + // + //////////////////////////////////////////////////// + + /** Functions that sets an integer or floating point + * source register to a value. */ + void setIntSrc(int idx, uint64_t val); + void setFloatSrc(int idx, FloatReg val, int width = 32); + void setFloatRegBitsSrc(int idx, uint64_t val); + + uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; } + uint64_t readIntSrc(int idx) { return instSrc[idx].integer; } + + /** These Instructions read a integer/float/misc. source register + * value in the instruction. The instruction's execute function will + * call these and it is the interface that is used by the ISA descr. + * language (which is why the name isnt readIntSrc(...)) Note: That + * the source reg. value is set using the setSrcReg() function. + */ + IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0); + FloatReg readFloatRegOperand(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, + int width = TheISA::SingleWidth); + MiscReg readMiscReg(int misc_reg); + MiscReg readMiscRegNoEffect(int misc_reg); + MiscReg readMiscRegOperand(const StaticInst *si, int idx); + MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx); + + /** Returns the result value instruction. */ + uint64_t readIntResult(int idx) { return instResult[idx].val.integer; } + float readFloatResult(int idx) { return instResult[idx].val.fp; } + double readDoubleResult(int idx) { return instResult[idx].val.dbl; } + Tick readResultTime(int idx) { return instResult[idx].tick; } + + uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; } + + /** This is the interface that an instruction will use to write + * it's destination register. + */ + void setIntRegOperand(const StaticInst *si, int idx, IntReg val); + void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, + int width = TheISA::SingleWidth); + void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val, + int width = TheISA::SingleWidth); + void setMiscReg(int misc_reg, const MiscReg &val); + void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val); + void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val); + + virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1); + virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1); + + ////////////////////////////////////////////////////////////// + // + // INSTRUCTION STATUS FLAGS (READ/SET) + // + ////////////////////////////////////////////////////////////// + /** Sets this instruction as entered on the CPU Reg Dep Map */ + void setRegDepEntry() { status.set(RegDepMapEntry); } + + /** Returns whether or not the entry is on the CPU Reg Dep Map */ + bool isRegDepEntry() const { return status[RegDepMapEntry]; } + + /** Sets this instruction as completed. */ + void setCompleted() { status.set(Completed); } + + /** Returns whether or not this instruction is completed. */ + bool isCompleted() const { return status[Completed]; } + + /** Marks the result as ready. */ + void setResultReady() { status.set(ResultReady); } + + /** Returns whether or not the result is ready. */ + bool isResultReady() const { return status[ResultReady]; } + + /** Sets this instruction as ready to issue. */ + void setCanIssue() { status.set(CanIssue); } + + /** Returns whether or not this instruction is ready to issue. */ + bool readyToIssue() const { return status[CanIssue]; } + + /** Sets this instruction as issued from the IQ. */ + void setIssued() { status.set(Issued); } + + /** Returns whether or not this instruction has issued. */ + bool isIssued() const { return status[Issued]; } + + /** Sets this instruction as executed. */ + void setExecuted() { status.set(Executed); } + + /** Returns whether or not this instruction has executed. */ + bool isExecuted() const { return status[Executed]; } + + /** Sets this instruction as ready to commit. */ + void setCanCommit() { status.set(CanCommit); } + + /** Clears this instruction as being ready to commit. */ + void clearCanCommit() { status.reset(CanCommit); } + + /** Returns whether or not this instruction is ready to commit. */ + bool readyToCommit() const { return status[CanCommit]; } + + void setAtCommit() { status.set(AtCommit); } + + bool isAtCommit() { return status[AtCommit]; } + + /** Sets this instruction as committed. */ + void setCommitted() { status.set(Committed); } + + /** Returns whether or not this instruction is committed. */ + bool isCommitted() const { return status[Committed]; } + + /** Sets this instruction as squashed. */ + void setSquashed() { status.set(Squashed); } + + /** Returns whether or not this instruction is squashed. */ + bool isSquashed() const { return status[Squashed]; } + + /** Temporarily sets this instruction as a serialize before instruction. */ + void setSerializeBefore() { status.set(SerializeBefore); } + + /** Clears the serializeBefore part of this instruction. */ + void clearSerializeBefore() { status.reset(SerializeBefore); } + + /** Checks if this serializeBefore is only temporarily set. */ + bool isTempSerializeBefore() { return status[SerializeBefore]; } + + /** Temporarily sets this instruction as a serialize after instruction. */ + void setSerializeAfter() { status.set(SerializeAfter); } + + /** Clears the serializeAfter part of this instruction.*/ + void clearSerializeAfter() { status.reset(SerializeAfter); } + + /** Checks if this serializeAfter is only temporarily set. */ + bool isTempSerializeAfter() { return status[SerializeAfter]; } + + /** Sets the serialization part of this instruction as handled. */ + void setSerializeHandled() { status.set(SerializeHandled); } + + /** Checks if the serialization part of this instruction has been + * handled. This does not apply to the temporary serializing + * state; it only applies to this instruction's own permanent + * serializing state. + */ + bool isSerializeHandled() { return status[SerializeHandled]; } + + private: + /** Instruction effective address. + * @todo: Consider if this is necessary or not. + */ + Addr instEffAddr; + + /** Whether or not the effective address calculation is completed. + * @todo: Consider if this is necessary or not. + */ + bool eaCalcDone; + + public: + /** Whether or not the memory operation is done. */ + bool memOpDone; + + public: + /** Load queue index. */ + int16_t lqIdx; + + /** Store queue index. */ + int16_t sqIdx; + + /** Iterator pointing to this BaseDynInst in the list of all insts. */ + ListIt instListIt; + + /** Returns iterator to this instruction in the list of all insts. */ + ListIt &getInstListIt() { return instListIt; } + + /** Sets iterator for this instruction in the list of all insts. */ + void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; } + + /** Count of total number of dynamic instructions. */ + static int instcount; + +#ifdef DEBUG + void dumpSNList(); +#endif + + /** Dumps out contents of this BaseDynInst. */ + void dump(); + + /** Dumps out contents of this BaseDynInst into given string. */ + void dump(std::string &outstring); + + + //inline int curCount() { return curCount(); } +}; + + +#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/inorder/inorder_trace.cc b/src/cpu/inorder/inorder_trace.cc new file mode 100644 index 000000000..f12a1b7a9 --- /dev/null +++ b/src/cpu/inorder/inorder_trace.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * Copyright (c) 2001-2005 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: Korey Sewell + */ + +#include + +#include "cpu/exetrace.hh" +#include "cpu/inorder/inorder_trace.hh" +#include "cpu/static_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/thread_context.hh" +#include "params/InOrderTrace.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +inline void +Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs) +{ + if (!stageTrace) { + ccprintf(outs, "%7d: ", when); + } else { + ccprintf(outs, ""); + for (int i=0; i < stageCycle.size(); i++) { + if (i < stageCycle.size() - 1) + outs << dec << stageCycle[i] << "-"; + else + outs << dec << stageCycle[i] << ":"; + } + } +} + +InOrderTraceRecord * +InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing, + ThreadContext *tc) +{ + if (!IsOn(ExecEnable)) + return NULL; + + if (!Trace::enabled) + return NULL; + + return new InOrderTraceRecord(num_stages, stage_tracing, tc); +} + +InOrderTraceRecord * +InOrderTrace::getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst, MicroPC upc) +{ + return new InOrderTraceRecord(ThePipeline::NumStages, true, tc); +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::InOrderTrace * +InOrderTraceParams::create() +{ + return new Trace::InOrderTrace(this); +}; + diff --git a/src/cpu/inorder/inorder_trace.hh b/src/cpu/inorder/inorder_trace.hh new file mode 100644 index 000000000..4338b438c --- /dev/null +++ b/src/cpu/inorder/inorder_trace.hh @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * Copyright (c) 2001-2005 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: Korey Sewell + */ + +#ifndef __INORDERTRACE_HH__ +#define __INORDERTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" +#include "params/InOrderTrace.hh" +#include "cpu/exetrace.hh" + +class ThreadContext; + + +namespace Trace { + +class InOrderTraceRecord : public ExeTracerRecord +{ + public: + InOrderTraceRecord(unsigned num_stages, bool _stage_tracing, + ThreadContext *_thread, bool spec = false) + : ExeTracerRecord(0, _thread, NULL, 0, spec) + { + stageTrace = _stage_tracing; + stageCycle.resize(num_stages); + } + + // Trace stage-by-stage execution of instructions. + bool stageTrace; + std::vector stageCycle; + + void dumpTicks(std::ostream &outs); + + void + setStageCycle(int num_stage, Tick cur_cycle) + { + if (stageTrace) { + stageCycle[num_stage] = cur_cycle; + } else { + when = cur_cycle; + } + } + + void + setStaticInst(const StaticInstPtr &_staticInst) + { + staticInst = _staticInst; + } + void setPC(Addr _pc) { PC = _pc; } +}; + +class InOrderTrace : public InstTracer +{ + public: + InOrderTrace(const InOrderTraceParams *p) : InstTracer(p) + {} + + InOrderTraceRecord * + getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc); + + virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc, + const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0); +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/inorder/params.hh b/src/cpu/inorder/params.hh new file mode 100644 index 000000000..67f8f47f0 --- /dev/null +++ b/src/cpu/inorder/params.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004-2005 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: Korey Sewell + */ + +#ifndef __CPU_INORDER_PARAMS_HH__ +#define __CPU_INORDER_PARAMS_HH__ + +#include "cpu/base.hh" + +//Forward declarations +class FunctionalMemory; +class Process; +class MemObject; +class MemInterface; + +/** + * This file defines the parameters that will be used for the InOrderCPU. + * This must be defined externally so that the Impl can have a params class + * defined that it can pass to all of the individual stages. + */ + +class InOrderParams : public BaseCPU::Params +{ + public: + + // Workloads +#if !FULL_SYSTEM + std::vector workload; + Process *process; +#endif // FULL_SYSTEM + + // + // Memory System/Caches + // + unsigned cachePorts; + std::string fetchMemPort; + std::string dataMemPort; + + // + // Branch predictor (BP & BTB) + // + std::string predType; + unsigned localPredictorSize; + unsigned localCtrBits; + unsigned localHistoryTableSize; + unsigned localHistoryBits; + unsigned globalPredictorSize; + unsigned globalCtrBits; + unsigned globalHistoryBits; + unsigned choicePredictorSize; + unsigned choiceCtrBits; + unsigned BTBEntries; + unsigned BTBTagSize; + unsigned RASSize; + + // Pipeline Parameters + unsigned stageWidth; + + // InOrderCPU Simulation Parameters + unsigned instShiftAmt; + unsigned activity; + unsigned deferRegistration; + + // + // Memory Parameters + // + unsigned memBlockSize; + + // + // Multiply Divide Unit + // + // @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr, + // then MDU must be defined as its own SimObject so that an arbitrary # can + // be defined with different parameters + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multLatency; + unsigned multRepeatRate; + + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8Latency; + unsigned div8RepeatRate; + + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16Latency; + unsigned div16RepeatRate; + + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24Latency; + unsigned div24RepeatRate; + + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32Latency; + unsigned div32RepeatRate; + + +}; + +#endif // __CPU_O3_CPU_INORDER_PARAMS_HH__ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc new file mode 100644 index 000000000..547b42537 --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.cc @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "base/str.hh" +#include "cpu/inorder/pipeline_stage.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +PipelineStage::PipelineStage(Params *params, unsigned stage_num) + : numThreads(ThePipeline::MaxThreads) +{ + stageNum = stage_num; + stageWidth = ThePipeline::StageWidth; + + _status = Inactive; + + prevStageValid = false; + nextStageValid = false; + + // Init. structures + for(int tid=0; tid < numThreads; tid++) { + stageStatus[tid] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); + + if (stageNum < BackEndStartStage) + lastStallingStage[tid] = BackEndStartStage - 1; + else + lastStallingStage[tid] = NumStages - 1; + } + + stageBufferMax = ThePipeline::interStageBuffSize[stage_num]; +} + + +void +PipelineStage::init(Params *params, unsigned stage_num) +{ + stageNum = stage_num; + stageWidth = ThePipeline::StageWidth; + + _status = Inactive; + + numThreads = ThePipeline::MaxThreads; + + prevStageValid = false; + nextStageValid = false; + + // Init. structures + for(int tid=0; tid < numThreads; tid++) { + stageStatus[tid] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); + + if (stageNum < BackEndStartStage) + lastStallingStage[tid] = BackEndStartStage - 1; + else + lastStallingStage[tid] = NumStages - 1; + } + + stageBufferMax = ThePipeline::interStageBuffSize[stage_num]; +} + + +std::string +PipelineStage::name() const +{ + return cpu->name() + ".stage-" + to_string(stageNum); +} + + +void +PipelineStage::regStats() +{ +/* stageIdleCycles + .name(name() + ".IdleCycles") + .desc("Number of cycles stage is idle") + .prereq(stageIdleCycles); + stageBlockedCycles + .name(name() + ".BlockedCycles") + .desc("Number of cycles stage is blocked") + .prereq(stageBlockedCycles); + stageRunCycles + .name(name() + ".RunCycles") + .desc("Number of cycles stage is running") + .prereq(stageRunCycles); + stageUnblockCycles + .name(name() + ".UnblockCycles") + .desc("Number of cycles stage is unblocking") + .prereq(stageUnblockCycles); + stageSquashCycles + .name(name() + ".SquashCycles") + .desc("Number of cycles stage is squashing") + .prereq(stageSquashCycles); + stageProcessedInsts + .name(name() + ".ProcessedInsts") + .desc("Number of instructions handled by stage") + .prereq(stageProcessedInsts); + stageSquashedInsts + .name(name() + ".SquashedInsts") + .desc("Number of squashed instructions handled by stage") + .prereq(stageSquashedInsts);*/ +} + + +void +PipelineStage::setCPU(InOrderCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + dummyBufferInst = new InOrderDynInst(cpu_ptr, NULL, 0, 0); + + DPRINTF(InOrderStage, "Set CPU pointer.\n"); + + tracer = dynamic_cast(cpu->getTracer()); +} + + +void +PipelineStage::setTimeBuffer(TimeBuffer *tb_ptr) +{ + DPRINTF(InOrderStage, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to write information back to fetch. + toPrevStages = timeBuffer->getWire(0); + + // Create wires to get information from proper places in time buffer. + fromNextStages = timeBuffer->getWire(-1); +} + + +void +PipelineStage::setPrevStageQueue(TimeBuffer *prev_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n"); + prevStageQueue = prev_stage_ptr; + + // Setup wire to read information from fetch queue. + prevStage = prevStageQueue->getWire(-1); + + prevStageValid = true; +} + + + +void +PipelineStage::setNextStageQueue(TimeBuffer *next_stage_ptr) +{ + DPRINTF(InOrderStage, "Setting next stage pointer.\n"); + nextStageQueue = next_stage_ptr; + + // Setup wire to write information to proper place in stage queue. + nextStage = nextStageQueue->getWire(0); + + nextStageValid = true; +} + + + +void +PipelineStage::setActiveThreads(list *at_ptr) +{ + DPRINTF(InOrderStage, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +/*inline void +PipelineStage::switchToActive() +{ + if (_status == Inactive) { + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + + _status = Active; + } +}*/ + +void +PipelineStage::switchOut() +{ + // Stage can immediately switch out. + cpu->signalSwitched(); +} + + +void +PipelineStage::takeOverFrom() +{ + _status = Inactive; + + // Be sure to reset state and clear out any old instructions. + for (int i = 0; i < numThreads; ++i) { + stageStatus[i] = Idle; + + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[i].stage[stNum] = false; + } + + stalls[i].resources.clear(); + + while (!insts[i].empty()) + insts[i].pop(); + + while (!skidBuffer[i].empty()) + skidBuffer[i].pop(); + } + wroteToTimeBuffer = false; +} + + + +bool +PipelineStage::checkStall(unsigned tid) const +{ + bool ret_val = false; + + // Only check pipeline stall from stage directly following this stage + if (stalls[tid].stage[stageNum + 1]) { + DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n", + tid, stageNum + 1); + ret_val = true; + } + + if (!stalls[tid].resources.empty()) { + string stall_src; + + for (int i=0; i < stalls[tid].resources.size(); i++) { + stall_src += stalls[tid].resources[i]->res->name() + ":"; + } + + DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n", + tid, stall_src); + ret_val = true; + } + + return ret_val; +} + + +void +PipelineStage::removeStalls(unsigned tid) +{ + for (int stNum = 0; stNum < NumStages; stNum++) { + stalls[tid].stage[stNum] = false; + } + stalls[tid].resources.clear(); +} + +inline bool +PipelineStage::prevStageInstsValid() +{ + return prevStage->size > 0; +} + +bool +PipelineStage::isBlocked(unsigned tid) +{ + return stageStatus[tid] == Blocked; +} + +bool +PipelineStage::block(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid); + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + // skidInsert(tid); + + // If the stage status is blocked or unblocking then stage has not yet + // signalled fetch to unblock. In that case, there is no need to tell + // fetch to block. + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + if (prevStageValid) + toPrevStages->stageBlock[stageNum][tid] = true; + wroteToTimeBuffer = true; + } + + return true; + } + + + return false; +} + +void +PipelineStage::blockDueToBuffer(unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid); + + if (stageStatus[tid] != Blocked) { + // Set the status to Blocked. + stageStatus[tid] = Blocked; + + if (stageStatus[tid] != Unblocking) { + wroteToTimeBuffer = true; + } + } +} + +bool +PipelineStage::unblock(unsigned tid) +{ + // Stage is done unblocking only if the skid buffer is empty. + if (skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid); + + if (prevStageValid) + toPrevStages->stageUnblock[stageNum][tid] = true; + + wroteToTimeBuffer = true; + + stageStatus[tid] = Running; + + return true; + } + + DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid); + return false; +} + +void +PipelineStage::squashDueToBranch(DynInstPtr &inst, unsigned tid) +{ + if (cpu->squashSeqNum[tid] < inst->seqNum && + cpu->lastSquashCycle[tid] == curTick){ + DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash " + "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]); + } else { + // Send back mispredict information. + toPrevStages->stageInfo[stageNum][tid].branchMispredict = true; + toPrevStages->stageInfo[stageNum][tid].predIncorrect = true; + toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum; + toPrevStages->stageInfo[stageNum][tid].squash = true; + toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg(); + toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() != + (inst->readNextPC() + sizeof(TheISA::MachInst)); + toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg()); + InstSeqNum squash_seq_num = inst->bdelaySeqNum; + + DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] " + "branch.\n", tid, squash_seq_num, inst->seqNum); + + // Save squash num for later stage use + cpu->squashSeqNum[tid] = squash_seq_num; + cpu->lastSquashCycle[tid] = curTick; + } +} + +void +PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, + unsigned tid) +{ + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from " + "incoming stage queue.\n", tid); + + for (int i=0; i < prevStage->size; i++) { + if (prevStage->insts[i]->threadNumber == tid && + prevStage->insts[i]->seqNum > squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, " + "[sn:%i] PC %08p.\n", + tid, + prevStage->insts[i]->seqNum, + prevStage->insts[i]->readPC()); + prevStage->insts[i]->setSquashed(); + } + } +} + +void +PipelineStage::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + // Set status to squashing. + stageStatus[tid] = Squashing; + + squashPrevStageInsts(squash_seq_num, tid); + + DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n", + tid); + while (!skidBuffer[tid].empty()) { + if (skidBuffer[tid].front()->seqNum <= squash_seq_num) { + DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer " + "instructions before delay slot [sn:%i]. %i insts" + "left.\n", tid, squash_seq_num, + skidBuffer[tid].size()); + break; + } + DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n", + tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC); + skidBuffer[tid].pop(); + } + +} + +int +PipelineStage::stageBufferAvail() +{ + unsigned total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + int incoming_insts = (prevStageValid) ? + cpu->pipelineStage[stageNum-1]->nextStage->size : + 0; + + int avail = stageBufferMax - total - incoming_insts; + + assert(avail >= 0); + + return avail; +} + +bool +PipelineStage::canSendInstToNextStage() +{ + bool buffer_avail = false; + + if (nextStageValid) { + buffer_avail = (cpu->pipelineStage[stageNum+1]->stageBufferAvail() >= 1); + } + + if (!buffer_avail && nextStageValid) { + DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1); + } + + return buffer_avail; +} + +void +PipelineStage::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop(); + + assert(tid == inst->threadNumber); + + DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n", + tid, inst->seqNum, inst->readPC(), inst->threadNumber); + + skidBuffer[tid].push(inst); + } +} + + + +bool +PipelineStage::skidsEmpty() +{ + list::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + + + +void +PipelineStage::updateStatus() +{ + bool any_unblocking = false; + + list::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (stageStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // Stage will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(stageNum); + } + } else { + // If it's not unblocking, then stage will not have any internal + // activity. Switch it to inactive. + if (_status == Active) { + _status = Inactive; + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(stageNum); + } + } +} + + + +void +PipelineStage::sortInsts() +{ + if (prevStageValid) { + int insts_from_prev_stage = prevStage->size; + + DPRINTF(InOrderStage, "%i insts available from previous stage.\n", + insts_from_prev_stage); + + for (int i = 0; i < insts_from_prev_stage; ++i) { + + if (prevStage->insts[i]->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting " + "into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + continue; + } + + DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n", + prevStage->insts[i]->readTid(), + prevStage->insts[i]->seqNum); + + int tid = prevStage->insts[i]->threadNumber; + + DynInstPtr inst = prevStage->insts[i]; + + skidBuffer[tid].push(prevStage->insts[i]); + + prevStage->insts[i] = dummyBufferInst; + + } + } +} + + + +void +PipelineStage::readStallSignals(unsigned tid) +{ + for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid]; + stage_idx++) { + + // Check for Stage Blocking Signal + if (fromNextStages->stageBlock[stage_idx][tid]) { + stalls[tid].stage[stage_idx] = true; + } + + // Check for Stage Unblocking Signal + if (fromNextStages->stageUnblock[stage_idx][tid]) { + //assert(fromNextStages->stageBlock[stage_idx][tid]); + stalls[tid].stage[stage_idx] = false; + } + } +} + + + +bool +PipelineStage::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is. + // Check stall signals, block if necessary. + // If status was blocked + // Check if stall conditions have passed + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + + // Update the per thread stall statuses. + readStallSignals(tid); + + // Check for squash from later pipeline stages + for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) { + if (fromNextStages->stageInfo[stage_idx][tid].squash) { + DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash " + "from stage %u.\n", tid, stage_idx); + InstSeqNum squash_seq_num = fromNextStages-> + stageInfo[stage_idx][tid].bdelayDoneSeqNum; + squash(squash_seq_num, tid); + break; //return true; + } + } + + if (checkStall(tid)) { + return block(tid); + } + + if (stageStatus[tid] == Blocked) { + DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + + unblock(tid); + + return true; + } + + if (stageStatus[tid] == Squashing) { + if (!skidBuffer[tid].empty()) { + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n", + tid); + + stageStatus[tid] = Unblocking; + } else { + // Switch status to running if stage isn't being told to block or + // squash this cycle. + DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n", + tid); + + stageStatus[tid] = Running; + } + + return true; + } + + // If we've reached this point, we have not gotten any signals that + // cause stage to change its status. Stage remains the same as before.*/ + return false; +} + + + +void +PipelineStage::tick() +{ + wroteToTimeBuffer = false; + + bool status_change = false; + + toNextStageIndex = 0; + + sortInsts(); + + processStage(status_change); + + if (status_change) { + updateStatus(); + } + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + } + + DPRINTF(InOrderStage, "\n\n"); +} + +bool +PipelineStage::outOfOrderValid() +{ + //@TODO: Define this function when OOO is valid + return false; +} + +void +PipelineStage::setResStall(ResReqPtr res_req, unsigned tid) +{ + DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name()); + stalls[tid].resources.push_back(res_req); +} + +void +PipelineStage::unsetResStall(ResReqPtr res_req, unsigned tid) +{ + // Search through stalls to find stalling request and then + // remove it + vector::iterator req_it = stalls[tid].resources.begin(); + vector::iterator req_end = stalls[tid].resources.end(); + + while (req_it != req_end) { + if( (*req_it)->res == res_req->res && // Same Resource + (*req_it)->inst == res_req->inst && // Same Instruction + (*req_it)->getSlot() == res_req->getSlot()) { + DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n", + tid, res_req->res->name()); + stalls[tid].resources.erase(req_it); + break; + } + + req_it++; + } + + if (stalls[tid].resources.size() == 0) { + DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n", + tid); + } +} + +// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled +// one at a time, but instead first come first serve by instruction? +// Questions are how should a pipeline stage handle thread-specific stalls & +// pipeline squashes +void +PipelineStage::processStage(bool &status_change) +{ + list::iterator threads = (*activeThreads).begin(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid); + status_change = checkSignalsAndUpdate(tid) || status_change; + + processThread(status_change, tid); + } + + if (nextStageValid) { + DPRINTF(InOrderStage, "%i insts now available for stage %i.\n", + nextStage->size, stageNum + 1); + } + + DPRINTF(InOrderStage, "%i insts left in stage buffer.\n", stageBufferMax - stageBufferAvail()); + +} + +void +PipelineStage::processThread(bool &status_change, unsigned tid) +{ + // If status is Running or idle, + // call stageInsts() + // If status is Unblocking, + // buffer any instructions coming from fetch + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (stageStatus[tid] == Blocked) { + ;//++stageBlockedCycles; + } else if (stageStatus[tid] == Squashing) { + ;//++stageSquashCycles; + } + + // Stage should try to stage as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (stageStatus[tid] == Running || + stageStatus[tid] == Idle) { + DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run " + "stage.\n",tid); + + processInsts(tid); + } else if (stageStatus[tid] == Unblocking) { + // Make sure that the skid buffer has something in it if the + // status is unblocking. + assert(!skidsEmpty()); + + // If the status was unblocking, then instructions from the skid + // buffer were used. Remove those instructions and handle + // the rest of unblocking. + processInsts(tid); + + if (prevStageValid && prevStageInstsValid()) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + } + + status_change = unblock(tid) || status_change; + } +} + + +void +PipelineStage::processInsts(unsigned tid) +{ + // Instructions can come either from the skid buffer or the list of + // instructions coming from fetch, depending on stage's status. + int insts_available = skidBuffer[tid].size(); + + std::queue &insts_to_stage = skidBuffer[tid]; + + if (insts_available == 0) { + DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out" + " early.\n",tid); + // Should I change the status to idle? + //++stageIdleCycles; + return; + } + + DynInstPtr inst; + bool last_req_completed = true; + + int insts_processed = 0; + + DPRINTF(InOrderStage, "[tid:%u]: Sending instructions to stage %u.\n", tid, + stageNum+1); + + //Keep processing instructions while ... these ?s are true: + while (insts_available > 0 && //1. are there instructions to process + insts_processed < stageWidth && //2. can the stage still process this + (canSendInstToNextStage() || !nextStageValid) && //3. is there room in next stage + last_req_completed) { //4. was the last instruction completed + assert(!insts_to_stage.empty()); + + inst = insts_to_stage.front(); + + DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x\n", + tid, inst->seqNum, inst->readPC()); + + if (inst->isSquashed()) { + DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->readPC()); + + //++stageSquashedInsts; + + insts_to_stage.pop(); + + --insts_available; + + continue; + } + + + last_req_completed = processInstSchedule(inst); + + + insts_processed++; + + // Don't let instruction pass to next stage if it hasnt completed + // all of it's requests for this stage. + if (!last_req_completed && !outOfOrderValid()) + continue; + + insts_to_stage.pop(); + + DPRINTF(InOrderStage, "Marking [tid:%i] [sn:%i] for insertion into next stage buffer.\n", + tid, inst->seqNum); + + // Send to Next Stage or Break Loop + if (!sendInstToNextStage(inst)) + break;; + + + //++stageProcessedInsts; + --insts_available; + } + + // If we didn't process all instructions, then we will need to block + // and put all those instructions into the skid buffer. + // @TODO:-IN-PROGRESS-:Evaluating when stages should block/unblock + // for stage stalls... + if (!insts_to_stage.empty()) { + blockDueToBuffer(tid); + } + + // Record that stage has written to the time buffer for activity + // tracking. + if (toNextStageIndex) { + wroteToTimeBuffer = true; + } +} + +bool +PipelineStage::processInstSchedule(DynInstPtr inst) +{ + bool last_req_completed = true; + int tid; + + tid = inst->readTid(); + + if (inst->nextResStage() == stageNum) { + int res_stage_num = inst->nextResStage(); + + while (res_stage_num == stageNum) { + int res_num = inst->nextResource(); + + + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + ResReqPtr req = cpu->resPool->request(res_num, inst); + + if (req->isCompleted()) { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + if (req->fault == NoFault) { + inst->popSchedEntry(); + } else { + panic("%i: encountered %s fault!\n", + curTick, req->fault->name()); + } + } else { + DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n", + tid, inst->seqNum, cpu->resPool->name(res_num)); + + last_req_completed = false; + + break; + } + + res_stage_num = inst->nextResStage(); + } + } else { + DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x " + " needed no resources in stage %i.\n", + tid, inst->seqNum, inst->readPC(), stageNum); + } + + return last_req_completed; +} + +bool +PipelineStage::nextStageQueueValid(int stage_num) +{ + return cpu->pipelineStage[stage_num]->nextStageValid; +} + + +bool +PipelineStage::sendInstToNextStage(DynInstPtr inst) +{ + // Update Next Stage Variable in Instruction + if (inst->nextStage == stageNum) + inst->nextStage++; + + bool success = false; + int tid = inst->readTid(); + int next_stage = inst->nextStage; + int prev_stage = next_stage - 1; + + if (nextStageQueueValid(inst->nextStage - 1)) { + if (inst->seqNum > cpu->squashSeqNum[tid] && + curTick == cpu->lastSquashCycle[tid]) { + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion " + "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage); + } else { + DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", + tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); + + DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " + "index %i stage %i queue.\n", + tid, inst->seqNum, toNextStageIndex, inst->nextStage); + + int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size; + + // Place instructions in inter-stage communication struct for the next + // pipeline stage to read next cycle + cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst; + + ++(cpu->pipelineStage[prev_stage]->nextStage->size); + + ++toNextStageIndex; + + success = true; + + // Take note of trace data for this inst & stage + if (inst->traceData) { + inst->traceData->setStageCycle(stageNum, curTick); + } + + } + } + + return success; +} + +void +PipelineStage::dumpInsts() +{ + std::cerr << "Insts in Stage " << stageNum << " skidbuffers:" << endl; + + for (int tid=0; tid < ThePipeline::MaxThreads; tid++) { + + std::queue copy_buff(skidBuffer[tid]); + + while (!copy_buff.empty()) { + DynInstPtr inst = copy_buff.front(); + + cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n", + inst->readPC(), inst->threadNumber, inst->seqNum); + + copy_buff.pop(); + } + } + +} diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh new file mode 100644 index 000000000..833547704 --- /dev/null +++ b/src/cpu/inorder/pipeline_stage.hh @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_STAGE_HH__ +#define __CPU_INORDER_PIPELINE_STAGE_HH__ + +#include +#include + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/comm.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class PipelineStage +{ + protected: + typedef ThePipeline::Params Params; + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + /** Overall stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum StageStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking, + MemWaitResponse, + MemWaitRetry, + MemAccessComplete + }; + + protected: + /** The Number of This Pipeline Stage */ + unsigned stageNum; + + /** The width of stage, in instructions. */ + unsigned stageWidth; + + /** Number of Threads*/ + unsigned numThreads; + + /** Stage status. */ + StageStatus _status; + + /** Per-thread status. */ + ThreadStatus stageStatus[ThePipeline::MaxThreads]; + + public: + PipelineStage(Params *params, unsigned stage_num); + + /** MUST use init() function if this constructor is used. */ + PipelineStage() { } + + virtual ~PipelineStage() { } + + /** PipelineStage initialization. */ + void init(Params *params, unsigned stage_num); + + /** Returns the name of stage. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + virtual void setCPU(InOrderCPU *cpu_ptr); + + virtual void scheduleStageStart(int delay, int tid) { } + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer *tb_ptr); + + /** Sets pointer to time buffer coming from fetch. */ + void setPrevStageQueue(TimeBuffer *prev_stage_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setNextStageQueue(TimeBuffer *next_stage_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list *at_ptr); + + bool nextStageQueueValid(int stage_num); + + bool isBlocked(unsigned tid); + + /** Changes the status of this stage to active, and indicates this + * to the CPU. + */ + //inline void switchToActive(); + + /** Changes the status of this stage to inactive, and indicates + * this to the CPU. + */ + //inline void switchToInactive(); + + /** Switches out the stage stage. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks stage, processing all input signals and executing as many + * instructions as possible. + */ + virtual void tick(); + + /** Is out of order processing valid? */ + bool outOfOrderValid(); + + /** Set a resource stall in the pipeline-stage */ + void setResStall(ResReqPtr res_req, unsigned tid); + + /** Unset a resource stall in the pipeline-stage */ + void unsetResStall(ResReqPtr res_req, unsigned tid); + + /** Remove all stall signals for a particular thread; */ + virtual void removeStalls(unsigned tid); + + /** Is there room in the stage buffer? */ + int stageBufferAvail(); + + protected: + /** Evaluate Stage Conditions and then process stage */ + virtual void processStage(bool &status_change); + + /** Determines what to do based on stage's current status. + * @param status_change stage() sets this variable if there was a status + * change (ie switching from from blocking to unblocking). + * @param tid Thread id to stage instructions from. + */ + virtual void processThread(bool &status_change, unsigned tid); + + /** Processes instructions from fetch and passes them on to rename. + * Decoding of instructions actually happens when they are created in + * fetch, so this function mostly checks if PC-relative branches are + * correct. + */ + virtual void processInsts(unsigned tid); + + /** Process all resources on an instruction's resource schedule */ + virtual bool processInstSchedule(DynInstPtr inst); + + /** Is there room in the next stage buffer for this instruction? */ + virtual bool canSendInstToNextStage(); + + /** Send an instruction to the next stage buffer */ + virtual bool sendInstToNextStage(DynInstPtr inst); + + /** Inserts a thread's instructions into the skid buffer, to be staged + * once stage unblocks. + */ + virtual void skidInsert(unsigned tid); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall stage status based on all of the threads' statuses. */ + virtual void updateStatus(); + + /** Separates instructions from fetch into individual lists of instructions + * sorted by thread. + */ + void sortInsts(); + + /** Reads all stall signals from the backwards communication timebuffer. */ + virtual void readStallSignals(unsigned tid); + + /** Checks all input signals and updates stage's status appropriately. */ + virtual bool checkSignalsAndUpdate(unsigned tid); + + /** Checks all stall signals, and returns if any are true. */ + virtual bool checkStall(unsigned tid) const; + + /** Returns if there any instructions from the previous stage + * on this cycle. + */ + inline bool prevStageInstsValid(); + + /** Switches stage to blocking, and signals back that stage has + * become blocked. + * @return Returns true if there is a status change. + */ + virtual bool block(unsigned tid); + + void blockDueToBuffer(unsigned tid); + + /** Switches stage to unblocking if the skid buffer is empty, and + * signals back that stage has unblocked. + * @return Returns true if there is a status change. + */ + virtual bool unblock(unsigned tid); + + + public: + /** Squashes if there is a PC-relative branch that was predicted + * incorrectly. Sends squash information back to fetch. + */ + virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid); + + /** Squash instructions from stage buffer */ + virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid); + + /** Squashes due to commit signalling a squash. Changes status to + * squashing and clears block/unblock signals as needed. + */ + virtual void squash(InstSeqNum squash_num, unsigned tid); + + void dumpInsts(); + + protected: + /** CPU interface. */ + InOrderCPU *cpu; + + Trace::InOrderTrace *tracer; + + /** List of active thread ids */ + std::list *activeThreads; + + /** Queue of all instructions coming from previous stage on this cycle. */ + std::queue insts[ThePipeline::MaxThreads]; + + /** Queue of instructions that are finished processing and ready to go next stage. + * This is used to prevent from processing an instrution more than once on any + * stage. NOTE: It is up to the PROGRAMMER must manage this as a queue + */ + std::list instsToNextStage; + + /** Skid buffer between previous stage and this one. */ + std::queue skidBuffer[ThePipeline::MaxThreads]; + + /** Instruction used to signify that there is no *real* instruction in buffer slot */ + DynInstPtr dummyBufferInst; + + /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */ + Addr bdelayDoneSeqNum[ThePipeline::MaxThreads]; + + /** Instruction used for squashing branch (used for MIPS) */ + DynInstPtr squashInst[ThePipeline::MaxThreads]; + + /** Tells when their is a pending delay slot inst. to send + * to rename. If there is, then wait squash after the next + * instruction (used for MIPS). + */ + bool squashAfterDelaySlot[ThePipeline::MaxThreads]; + + /** Maximum size of the inter-stage buffer connecting the previous stage to + * this stage (which we call a skid buffer) */ + unsigned stageBufferMax; + + /** Variable that tracks if stage has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Index of instructions being sent to the next stage. */ + unsigned toNextStageIndex; + + /** The last stage that this particular stage should look for stalls */ + int lastStallingStage[ThePipeline::MaxThreads]; + + /** Time buffer interface. */ + TimeBuffer *timeBuffer; + + public: + /** Wire to get rename's output from backwards time buffer. */ + TimeBuffer::wire fromNextStages; + + /** Wire to get iew's information from backwards time buffer. */ + TimeBuffer::wire toPrevStages; + + /** Instruction queue linking previous stage */ + TimeBuffer *prevStageQueue; + + /** Wire to get the previous stage's. */ + TimeBuffer::wire prevStage; + + /** Instruction queue linking next stage */ + TimeBuffer *nextStageQueue; + + /** Wire to write to the next stage */ + TimeBuffer::wire nextStage; + + /** Is Previous Stage Valid? */ + bool prevStageValid; + + /** Is Next Stage Valid? */ + bool nextStageValid; + + /** Source of possible stalls. */ + struct Stalls { + bool stage[ThePipeline::NumStages]; + std::vector resources; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[ThePipeline::MaxThreads]; + + //@TODO: Use Stats for the pipeline stages + /** Stat for total number of idle cycles. */ + //Stats::Scalar<> stageIdleCycles; + /** Stat for total number of blocked cycles. */ + //Stats::Scalar<> stageBlockedCycles; + /** Stat for total number of normal running cycles. */ + //Stats::Scalar<> stageRunCycles; + /** Stat for total number of unblocking cycles. */ + //Stats::Scalar<> stageUnblockCycles; + /** Stat for total number of squashing cycles. */ + //Stats::Scalar<> stageSquashCycles; + /** Stat for total number of staged instructions. */ + //Stats::Scalar<> stageProcessedInsts; + /** Stat for total number of squashed instructions. */ + //Stats::Scalar<> stageSquashedInsts; +}; + +#endif diff --git a/src/cpu/inorder/pipeline_traits.5stage.cc b/src/cpu/inorder/pipeline_traits.5stage.cc new file mode 100644 index 000000000..50c30af1e --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.cc @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // IF - Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB, TLBUnit::FetchLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::InitiateFetch)); + + // + // DE - Stage 1 + // --------------------------------------- + stNum++; stPri = 0; + inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::CompleteFetch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode, DecodeUnit::DecodeInst)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred, BranchPredictor::PredictBranch)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // EX - Stage 2 + // --------------------------------------- + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr)); + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData)); + } + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + + // + // MEM - Stage 3 + // --------------------------------------- + stPri = 0; stNum++; + if ( inst->isStore() ) { // for store, need src reg at this point + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1)); + } + if ( inst->isLoad() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData)); + } else if ( inst->isStore() ) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup)); + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData)); + } + + // + // WB - Stage 4 + // --------------------------------------- + stPri = 0; stNum++; + if (inst->isNonSpeculative()) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + + if ( inst->isStore() ) + inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData)); + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx)); + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst)); + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.5stage.hh b/src/cpu/inorder/pipeline_traits.5stage.hh new file mode 100644 index 000000000..aea6eff37 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.5stage.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include +#include +#include + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.cc b/src/cpu/inorder/pipeline_traits.9stage.cc new file mode 100644 index 000000000..d686bb3bc --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.cc @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + if (inst->readTid() == 0) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass)); + else //if (inst->readTid() == 1) + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + } else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + } + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.hh b/src/cpu/inorder/pipeline_traits.9stage.hh new file mode 100644 index 000000000..91e537366 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include +#include +#include +#include + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 3; + const unsigned StageWidth = 2; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.cc b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc new file mode 100644 index 000000000..9d2ed8e61 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + int stNum = 0; + int stPri = 0; + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 0 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch)); + stPri++; + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 1 + // --------------------------------------- + inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch)); + stPri++; + + inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC)); + stPri++; + + int fetch_buff_num = FetchBuff + inst->readTid(); + + inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass)); + + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; + + // + // Stage 2 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stNum++; + stPri = 0; +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + std::string name = inst->staticInst->getName(); + + int stNum = BackEndStartStage; + int stPri = 0; + + // Get Pointer to Instuction's Schedule + ResSchedule *inst_sched = &inst->resSched; + + // + // Stage 3 + // --------------------------------------- + // Set When Source Registers Should be read - Stage 4 + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx)); + } + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 4 + // --------------------------------------- + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr)); + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 5 + // --------------------------------------- + // Execution Unit + if (!inst->isNonSpeculative() && !inst->isMemRef()) { + //if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + //inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv)); + //} else { + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + //} + } + stPri++; + + // DCache Initiate Access + if (inst->isMemRef()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup)); + stPri++; + + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 6 + // --------------------------------------- + // DCache Complete Access + if (inst->isMemRef()) { + if (inst->isLoad()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData)); + } else if (inst->isStore()) { + inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData)); + } + } + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 7 + // --------------------------------------- + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + // + // Stage 8 + // --------------------------------------- + // NonSpeculative Execution + if (inst->isNonSpeculative() ) { + if (inst->isMemRef()) + fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n"); + + inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst)); + stPri++; + } + + // Write Back to Register File + for (int idx=0; idx < inst->numDestRegs(); idx++) { + inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx)); + stPri++; + } + + // Graduate Instructions + inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst)); + stPri++; + + // Reset Priority / Update Next Stage Number + stPri = 0; + stNum++; + + return true; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.hh b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh new file mode 100644 index 000000000..22da4ea0f --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include +#include +#include +#include + +#include "arch/isa_traits.hh" +#include "cpu/inorder/params.hh" + + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 9; + const unsigned MaxThreads = 2; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 3; + + // Use this to over-ride default stage widths + static std::map stageBufferSizes; + + //static unsigned interStageBuffSize[NumStages]; + + static const unsigned interStageBuffSize[NumStages] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + MaxThreads * 4, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + MaxThreads * 4, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + MaxThreads /* Stage 8 - 9 */ + }; + + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + RegManager, + AGEN, + ExecUnit, + DTLB, + DCache, + Grad, + FetchBuff, + FetchBuff2 + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr DynInstPtr; + +//void initPipelineTraits(); + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); +}; +#endif diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc new file mode 100644 index 000000000..eb899452a --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resources/resource_list.hh" + +using namespace std; + +namespace ThePipeline { + +//@TODO: create my own Instruction Schedule Class +//that operates as a Priority QUEUE +int getNextPriority(DynInstPtr &inst, int stage_num) +{ + int cur_pri = 20; + + /* + std::priority_queue, + entryCompare>::iterator sked_it = inst->resSched.begin(); + + std::priority_queue, + entryCompare>::iterator sked_end = inst->resSched.end(); + + while (sked_it != sked_end) { + + if (sked_it.top()->stageNum == stage_num) { + cur_pri = sked_it.top()->priority; + } + + sked_it++; + } + */ + + return cur_pri; +} + +void createFrontEndSchedule(DynInstPtr &inst) +{ + InstStage *I = inst->addStage(); + InstStage *E = inst->addStage(); + + I->needs(FetchSeq, FetchSeqUnit::AssignNextPC); + I->needs(ITLB, TLBUnit::FetchLookup); + I->needs(ICache, CacheUnit::InitiateFetch); + + E->needs(ICache, CacheUnit::CompleteFetch); + E->needs(Decode, DecodeUnit::DecodeInst); + E->needs(BPred, BranchPredictor::PredictBranch); + E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); +} + +bool createBackEndSchedule(DynInstPtr &inst) +{ + if (!inst->staticInst) { + return false; + } + + InstStage *E = inst->currentStage(); + InstStage *M = inst->addStage(); + InstStage *A = inst->addStage(); + InstStage *W = inst->addStage(); + + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) { + E->needs(RegManager, UseDefUnit::ReadSrcReg, idx); + } + } + + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if ( inst->isMemRef() ) { + E->needs(AGEN, AGENUnit::GenerateAddr); + if ( inst->isLoad() ) { + E->needs(DTLB, TLBUnit::DataLookup); + E->needs(DCache, CacheUnit::InitiateReadData); + } + } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + E->needs(MDU, MultDivUnit::StartMultDiv); + + // ZERO-LATENCY Multiply: + // E->needs(MDU, MultDivUnit::MultDiv); + } else { + E->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + M->needs(MDU, MultDivUnit::EndMultDiv); + } + + if ( inst->isLoad() ) { + M->needs(DCache, CacheUnit::CompleteReadData); + } else if ( inst->isStore() ) { + M->needs(RegManager, UseDefUnit::ReadSrcReg, 1); + M->needs(DTLB, TLBUnit::DataLookup); + M->needs(DCache, CacheUnit::InitiateWriteData); + } + + if ( inst->isStore() ) { + A->needs(DCache, CacheUnit::CompleteWriteData); + } + + if ( inst->isNonSpeculative() ) { + if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); + W->needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + for (int idx=0; idx < inst->numDestRegs(); idx++) { + W->needs(RegManager, UseDefUnit::WriteDestReg, idx); + } + + W->needs(Grad, GraduationUnit::GraduateInst); + + return true; +} + +InstStage::InstStage(DynInstPtr inst, int stage_num) +{ + stageNum = stage_num; + nextTaskPriority = 0; + instSched = &inst->resSched; +} + +}; diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh new file mode 100644 index 000000000..c5e4bb228 --- /dev/null +++ b/src/cpu/inorder/pipeline_traits.hh @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_PIPELINE_IMPL_HH__ +#define __CPU_INORDER_PIPELINE_IMPL_HH__ + +#include +#include +#include + +#include "arch/isa_traits.hh" +#include "cpu/base.hh" +//#include "cpu/inorder/params.hh" + +#include "params/InOrderCPU.hh" + +class InOrderDynInst; + +/* This Namespace contains constants, typedefs, functions and + * objects specific to the Pipeline Implementation. + */ +namespace ThePipeline { + // Pipeline Constants + const unsigned NumStages = 5; + const unsigned MaxThreads = 8; + const unsigned StageWidth = 1; + const unsigned BackEndStartStage = 2; + + // Enumerated List of Resources The Pipeline Uses + enum ResourceList { + FetchSeq = 0, + ITLB, + ICache, + Decode, + BPred, + FetchBuff, + RegManager, + AGEN, + ExecUnit, + MDU, + DTLB, + DCache, + Grad, + FetchBuff2 + }; + + // Expand this as necessary for your inter stage buffer sizes + static const unsigned interStageBuffSize[] = { + StageWidth, /* Stage 0 - 1 */ + StageWidth, /* Stage 1 - 2 */ + StageWidth, /* Stage 2 - 3 */ + StageWidth, /* Stage 3 - 4 */ + StageWidth, /* Stage 4 - 5 */ + StageWidth, /* Stage 5 - 6 */ + StageWidth, /* Stage 6 - 7 */ + StageWidth, /* Stage 7 - 8 */ + StageWidth /* Stage 8 - 9 */ + }; + + typedef InOrderCPUParams Params; + typedef RefCountingPtr DynInstPtr; + + ////////////////////////// + // RESOURCE SCHEDULING + ////////////////////////// + struct ScheduleEntry { + ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, + int _idx = 0) : + stageNum(stage_num), resNum(res_num), cmd(_cmd), + idx(_idx), priority(_priority) + { } + virtual ~ScheduleEntry(){} + + // Stage number to perform this service. + int stageNum; + + // Resource ID to access + int resNum; + + // See specific resource for meaning + unsigned cmd; + + // See specific resource for meaning + unsigned idx; + + // Some Resources May Need Priority? + int priority; + }; + + struct entryCompare { + bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const + { + // Prioritize first by stage number that the resource is needed + if (lhs->stageNum > rhs->stageNum) { + return true; + } else if (lhs->stageNum == rhs->stageNum) { + /*if (lhs->resNum > rhs->resNum) { + return true; + } else { + return false; + }*/ + + if (lhs->priority > rhs->priority) { + return true; + } else { + return false; + } + } else { + return false; + } + } + }; + + + typedef std::priority_queue, + entryCompare> ResSchedule; + + void createFrontEndSchedule(DynInstPtr &inst); + bool createBackEndSchedule(DynInstPtr &inst); + int getNextPriority(DynInstPtr &inst, int stage_num); + + class InstStage { + private: + int nextTaskPriority; + int stageNum; + ResSchedule *instSched; + + public: + InstStage(DynInstPtr inst, int stage_num); + + void needs(int unit, int request) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request + )); + } + + void needs(int unit, int request, int param) { + instSched->push( new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request, param + )); + } + + }; +}; + + + + +#endif diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc new file mode 100644 index 000000000..a405b1fb9 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +RegDepMap::RegDepMap(int size) +{ + regMap.resize(size); +} + +string +RegDepMap::name() +{ + return cpu->name() + ".RegDepMap"; +} + +void +RegDepMap::setCPU(InOrderCPU *_cpu) +{ + cpu = _cpu; +} + +void +RegDepMap::clear() +{ + regMap.clear(); +} + +void +RegDepMap::insert(DynInstPtr inst) +{ + int dest_regs = inst->numDestRegs(); + + DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] " + ", %s (dest. regs = %i).\n", + inst->seqNum, + inst->staticInst->getName(), + dest_regs); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + + //if (inst->numFPDestRegs()) + // idx += TheISA::FP_Base_DepTag; + + insert(idx, inst); + } +} + + +void +RegDepMap::insert(unsigned idx, DynInstPtr inst) +{ + DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n", + inst->seqNum, idx); + + regMap[idx].push_back(inst); + + inst->setRegDepEntry(); +} + +void +RegDepMap::remove(DynInstPtr inst) +{ + if (inst->isRegDepEntry()) { + DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n", + inst->seqNum); + + int dest_regs = inst->numDestRegs(); + + for (int i = 0; i < dest_regs; i++) { + int idx = inst->destRegIdx(i); + remove(idx, inst); + } + } +} + +void +RegDepMap::remove(unsigned idx, DynInstPtr inst) +{ + std::list::iterator list_it = regMap[idx].begin(); + std::list::iterator list_end = regMap[idx].end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + regMap[idx].erase(list_it); + break; + } + + list_it++; + } +} + +void +RegDepMap::removeFront(unsigned idx, DynInstPtr inst) +{ + std::list::iterator list_it = regMap[idx].begin(); + + DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg." + "%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum); + + assert(list_it != regMap[idx].end()); + + assert(inst == (*list_it)); + + regMap[idx].erase(list_it); +} + +bool +RegDepMap::canRead(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + return false; + } +} + +ThePipeline::DynInstPtr +RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst) +{ + std::list::iterator list_it = regMap[reg_idx].begin(); + std::list::iterator list_end = regMap[reg_idx].end(); + + DynInstPtr forward_inst = NULL; + + // Look for first, oldest instruction + while (list_it != list_end && + (*list_it)->seqNum < inst->seqNum) { + forward_inst = (*list_it); + list_it++; + } + + if (forward_inst) { + if (forward_inst->isExecuted() && + forward_inst->readResultTime(src_idx) < curTick) { + return forward_inst; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, " + " [sn:%i] has not been executed yet.\n", + inst->seqNum, forward_inst->seqNum); + return NULL; + } + } else { + DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n", + inst->seqNum); + return NULL; + } +} + +bool +RegDepMap::canWrite(unsigned idx, DynInstPtr inst) +{ + if (regMap[idx].size() == 0) + return true; + + std::list::iterator list_it = regMap[idx].begin(); + + if (inst->seqNum <= (*list_it)->seqNum) { + return true; + } else { + DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written" + " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum); + } + + return false; +} + +int +RegDepMap::depSize(unsigned idx) +{ + return regMap[idx].size(); +} + +ThePipeline::DynInstPtr +RegDepMap::findBypassInst(unsigned idx) +{ + std::list::iterator list_it = regMap[idx].begin(); + + if (depSize(idx) == 1) + return NULL; + + list_it++; + + while (list_it != regMap[idx].end()) { + if((*list_it)->isExecuted()) { + return *list_it; + break; + } + } + + return NULL; +} diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh new file mode 100644 index 000000000..ba2a8c8a3 --- /dev/null +++ b/src/cpu/inorder/reg_dep_map.hh @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef CPU_INORDER_REG_DEP_MAP_HH +#define CPU_INORDER_REG_DEP_MAP_HH + +#include +#include + +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" + +class InOrderCPU; + +class RegDepMap +{ + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + RegDepMap(int size = TheISA::TotalNumRegs); + + ~RegDepMap() { } + + std::string name(); + + void setCPU(InOrderCPU *_cpu); + + /** Clear the Entire Map */ + void clear(); + + /** Insert all of a instruction's destination registers into map*/ + void insert(DynInstPtr inst); + + /** Insert an instruction into a specific destination register index onto map */ + void insert(unsigned idx, DynInstPtr inst); + + /** Remove all of a instruction's destination registers into map*/ + void remove(DynInstPtr inst); + + /** Remove a specific instruction and destination register index from map */ + void remove(unsigned idx, DynInstPtr inst); + + /** Remove Front instruction from a destination register */ + void removeFront(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to read from this destination register? */ + bool canRead(unsigned idx, DynInstPtr inst); + + /** Is the current instruction able to get a forwarded value from another instruction + * for this destination register? */ + DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst); + + /** find an instruction to forward/bypass a value from */ + DynInstPtr findBypassInst(unsigned idx); + + /** Is the current instruction able to write to this destination register? */ + bool canWrite(unsigned idx, DynInstPtr inst); + + /** Size of Dependency of Map */ + int depSize(unsigned idx); + + protected: + // Eventually make this a map of lists for + // efficiency sake! + std::vector > regMap; + + InOrderCPU *cpu; +}; + +#endif + + + + + + + diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc new file mode 100644 index 000000000..3106628f0 --- /dev/null +++ b/src/cpu/inorder/resource.cc @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/cpu.hh" +using namespace std; + +Resource::Resource(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : resName(res_name), id(res_id), + width(res_width), latency(res_latency), cpu(_cpu) +{ + // Use to deny a instruction a resource. + deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0); +} + +void +Resource::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new ResourceEvent[width]; + + initSlots(); +} + +void +Resource::initSlots() +{ + // Add available slot numbers for resource + for (int slot_idx = 0; slot_idx < width; slot_idx++) { + availSlots.push_back(slot_idx); + resourceEvent[slot_idx].init(this, slot_idx); + } +} + +std::string +Resource::name() +{ + return cpu->name() + "." + resName; +} + +void +Resource::regStats() +{ + instReqsProcessed + .name(name() + ".instReqsProcessed") + .desc("Number of Instructions Requests that completed in this resource."); +} + +int +Resource::slotsAvail() +{ + return availSlots.size(); +} + +int +Resource::slotsInUse() +{ + return width - availSlots.size(); +} + +void +Resource::freeSlot(int slot_idx) +{ + DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + slot_idx); + + // Put slot number on this resource's free list + availSlots.push_back(slot_idx); + + // Erase Request Pointer From Request Map + std::map::iterator req_it = reqMap.find(slot_idx); + + assert(req_it != reqMap.end()); + reqMap.erase(req_it); + +} + +// TODO: More efficiently search for instruction's slot within +// resource. +int +Resource::findSlot(DynInstPtr inst) +{ + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + int slot_num = -1; + + while (map_it != map_end) { + if ((*map_it).second->getInst()->seqNum == + inst->seqNum) { + slot_num = (*map_it).second->getSlot(); + } + map_it++; + } + + return slot_num; +} + +int +Resource::getSlot(DynInstPtr inst) +{ + int slot_num; + + if (slotsAvail() != 0) { + slot_num = availSlots[0]; + + vector::iterator vect_it = availSlots.begin(); + + assert(slot_num == *vect_it); + + availSlots.erase(vect_it); + } else { + DPRINTF(Resource, "[tid:%i]: No slots in resource " + "available to service [sn:%i].\n", inst->readTid(), + inst->seqNum); + slot_num = -1; + + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second) { + DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n", + (*map_it).second->getInst()->readTid(), + (*map_it).second->getInst()->seqNum); + } + map_it++; + } + } + + return slot_num; +} + +ResReqPtr +Resource::request(DynInstPtr inst) +{ + // See if the resource is already serving this instruction. + // If so, use that request; + bool try_request = false; + int slot_num; + int stage_num; + ResReqPtr inst_req = findRequest(inst); + + if (inst_req) { + // If some preprocessing has to be done on instruction + // that has already requested once, then handle it here. + // update the 'try_request' variable if we should + // re-execute the request. + requestAgain(inst, try_request); + + slot_num = inst_req->getSlot(); + stage_num = inst_req->getStageNum(); + } else { + // Get new slot # for instruction + slot_num = getSlot(inst); + + if (slot_num != -1) { + // Get Stage # from Schedule Entry + stage_num = inst->resSched.top()->stageNum; + unsigned cmd = inst->resSched.top()->cmd; + + // Generate Resource Request + inst_req = getRequest(inst, stage_num, id, slot_num, cmd); + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n", + inst->readTid()); + } + + reqMap[slot_num] = inst_req; + + try_request = true; + } + } + + if (try_request) { + // Schedule execution of resource + scheduleExecution(slot_num); + } else { + inst_req = deniedReq; + rejectRequest(inst); + } + + return inst_req; +} + +void +Resource::requestAgain(DynInstPtr inst, bool &do_request) +{ + do_request = true; + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n", + inst->readTid()); + } +} + +ResReqPtr +Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new ResourceRequest(this, inst, stage_num, id, slot_num, + cmd); +} + +ResReqPtr +Resource::findRequest(DynInstPtr inst) +{ + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second && + (*map_it).second->getInst() == inst) { + return (*map_it).second; + } + map_it++; + } + + return NULL; +} + +void +Resource::rejectRequest(DynInstPtr inst) +{ + DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n", + inst->readTid(), inst->seqNum); +} + +void +Resource::execute(int slot_idx) +{ + DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n", + reqMap[slot_idx]->getTid(), name()); + reqMap[slot_idx]->setCompleted(true); + reqMap[slot_idx]->fault = NoFault; + reqMap[slot_idx]->done(); +} + +void +Resource::deactivateThread(unsigned tid) +{ + // In the most basic case, deactivation means squashing everything + // from a particular thread + DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid); + squash(dummy_inst, 0, 0, tid); +} + +void +Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + std::vector slot_remove_list; + + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + int req_slot_num = req_ptr->getSlot(); + + unscheduleEvent(req_slot_num); + + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } +} + + +Tick +Resource::ticks(int num_cycles) +{ + return cpu->ticks(num_cycles); +} + + +void +Resource::scheduleExecution(int slot_num) +{ + int res_latency = getLatency(slot_num); + + if (res_latency >= 1) { + scheduleEvent(slot_num, res_latency); + } else { + execute(slot_num); + } +} + +void +Resource::scheduleEvent(int slot_idx, int delay) +{ + DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + cpu->ticks(delay) + curTick); + resourceEvent[slot_idx].scheduleEvent(delay); +} + +bool +Resource::scheduleEvent(DynInstPtr inst, int delay) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].scheduleEvent(delay); + + return slot_idx; +} + +void +Resource::unscheduleEvent(int slot_idx) +{ + resourceEvent[slot_idx].unscheduleEvent(); +} + +bool +Resource::unscheduleEvent(DynInstPtr inst) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].unscheduleEvent(); + + return slot_idx; +} + +int ResourceRequest::resReqID = 0; + +int ResourceRequest::resReqCount = 0; + +void +ResourceRequest::done(bool completed) +{ + DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n", + res->name(), inst->seqNum, inst->readTid()); + + setCompleted(completed); + + // Add to remove list + res->cpu->reqRemoveList.push(res->reqMap[slotNum]); + + // Free Slot So Another Instruction Can Use This Resource + res->freeSlot(slotNum); + + res->instReqsProcessed++; +} + +ResourceEvent::ResourceEvent() + : Event((Event::Priority)Resource_Event_Pri) +{ } + +ResourceEvent::ResourceEvent(Resource *res, int slot_idx) + : Event((Event::Priority)Resource_Event_Pri), resource(res), + slotIdx(slot_idx) +{ } + +void +ResourceEvent::init(Resource *res, int slot_idx) +{ + resource = res; + slotIdx = slot_idx; +} + +void +ResourceEvent::process() +{ + resource->execute(slotIdx); +} + +const char * +ResourceEvent::description() +{ + string desc = resource->name() + " event"; + + return desc.c_str(); +} diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh new file mode 100644 index 000000000..e3536258d --- /dev/null +++ b/src/cpu/inorder/resource.hh @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_HH__ +#define __CPU_INORDER_RESOURCE_HH__ + +#include +#include +#include + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class ResourceEvent; +class ResourceRequest; + +typedef ResourceRequest ResReq; +typedef ResourceRequest* ResReqPtr; + +class Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + friend class ResourceEvent; + friend class ResourceRequest; + + public: + Resource(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~Resource() {} + + /** Return name of this resource */ + virtual std::string name(); + + /** Define this function if resource, has a port to connect to an outside + * simulation object. + */ + virtual Port* getPort(const std::string &if_name, int idx) { return NULL; } + + /** Return ID for this resource */ + int getId() { return id; } + + /** Any extra initiliazation stuff can be set up using this function that + * should get called before the simulation starts (tick 0) + */ + virtual void init(); + virtual void initSlots(); + + /** Tasks to perform when simulation starts */ + //virtual void startup() { } + + /** Register Stats for this resource */ + virtual void regStats(); + + /** Resources that care about thread activation override this. */ + virtual void activateThread(unsigned tid) { } + + /** Deactivate Thread. Default action is to squash all instructions + * from deactivated thread. + */ + virtual void deactivateThread(unsigned tid); + + /** Resources that care when an instruction has been graduated + * can override this + */ + virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { } + + /** Request usage of this resource. Returns a ResourceRequest object + * with all the necessary resource information + */ + virtual ResourceRequest* request(DynInstPtr inst); + + /** Get the next available slot in this resource. Instruction is passed + * so that resources can check the instruction before allocating a slot + * if necessary. + */ + virtual int getSlot(DynInstPtr inst); + + /** Find the slot that this instruction is using in a resource */ + virtual int findSlot(DynInstPtr inst); + + /** Free a resource slot */ + virtual void freeSlot(int slot_idx); + + /** Request usage of a resource for this instruction. If this instruction already + * has made this request to this resource, and that request is uncompleted + * this function will just return that request + */ + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + /** Schedule Execution of This Resource For A Given Slot*/ + virtual void scheduleExecution(int slot_idx); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + virtual void execute(int slot_idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. Needs to be defined for derived units. + */ + virtual Fault doFetchAccess(DynInstPtr inst) + { panic("doFetchAccess undefined for %s", name()); return NoFault; } + + /** Read/Write on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to do access.Needs to be defined for derived units. + */ + virtual Fault doDataAccess(DynInstPtr inst) + { panic("doDataAccess undefined for %s", name()); return NoFault; } + + /** Squash All Requests After This Seq Num */ + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + /** The number of instructions available that this resource can + * can still process + */ + int slotsAvail(); + + /** The number of instructions using this resource */ + int slotsInUse(); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int slot_idx, int delay); + + /** Find instruction in list, Schedule resource event, regardless of its current state. */ + bool scheduleEvent(DynInstPtr inst, int delay); + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent(int slot_idx); + + /** Unschedule resource event, regardless of its current state. */ + bool unscheduleEvent(DynInstPtr inst); + + /** Return the number of cycles in 'Tick' format */ + Tick ticks(int numCycles); + + /** Find the request that corresponds to this instruction */ + virtual ResReqPtr findRequest(DynInstPtr inst); + + /** */ + virtual void rejectRequest(DynInstPtr inst); + + /** Request a Resource again. Some resources have to special process this + * in subsequent accesses. + */ + virtual void requestAgain(DynInstPtr inst, bool &try_request); + + /** Return Latency of Resource */ + /* Can be overridden for complex cases */ + virtual int getLatency(int slot_num) { return latency; } + + protected: + /** The name of this resource */ + std::string resName; + + /** ID of the resource. The Resource Pool uses this # to identify this + * resource. + */ + int id; + + /** The number of instructions the resource can simultaneously + * process. + */ + int width; + + /** Constant latency for this resource. + * Note: Dynamic latency resources set this to 0 and + * manage the latency themselves + */ + const int latency; + + public: + /** Mapping of slot-numbers to the resource-request pointers */ + std::map reqMap; + + /** A list of all the available execution slots for this resource. + * This correlates with the actual resource event idx. + */ + std::vector availSlots; + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + protected: + /** The resource event used for scheduling resource slots on the + * event queue + */ + ResourceEvent *resourceEvent; + + /** Default denied resource request pointer*/ + ResReqPtr deniedReq; + + public: + ///////////////////////////////////////////////////////////////// + // + // DEFAULT RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar<> instReqsProcessed; +}; + +class ResourceEvent : public Event +{ + public: + /** Pointer to the CPU. */ + Resource *resource; + + + /// Resource events that come before other associated CPU events + /// (for InOrderCPU model). + /// check src/sim/eventq.hh for more event priorities. + enum InOrderPriority { + Resource_Event_Pri = 45, + }; + + /** The Resource Slot that this event is servicing */ + int slotIdx; + + /** Constructs a resource event. */ + ResourceEvent(); + ResourceEvent(Resource *res, int slot_idx); + virtual ~ResourceEvent() { } + + /** Initialize data for this resource event. */ + virtual void init(Resource *res, int slot_idx); + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Set slot idx for event */ + void setSlot(int slot) { slotIdx = slot; } + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(int delay) + { + if (squashed()) + mainEventQueue.reschedule(this, curTick + resource->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this, curTick + resource->ticks(delay)); + } + + /** Unschedule resource event, regardless of its current state. */ + void unscheduleEvent() + { + if (scheduled()) + squash(); + } + +}; + +class ResourceRequest +{ + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + static int resReqID; + + static int resReqCount; + + public: + ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, unsigned _cmd) + : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num), + resIdx(res_idx), slotNum(slot_num), completed(false), + squashed(false), processing(false), waiting(false) + { + reqID = resReqID++; + resReqCount++; + DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount); + + if (resReqCount > 100) { + fatal("Too many undeleted resource requests. Memory leak?\n"); + } + } + + virtual ~ResourceRequest() + { + resReqCount--; + DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount); + } + + int reqID; + + /** Acknowledge that this is a request is done and remove + * from resource. + */ + void done(bool completed = true); + + ///////////////////////////////////////////// + // + // GET RESOURCE REQUEST IDENTIFICATION / INFO + // + ///////////////////////////////////////////// + /** Get Resource Index */ + int getResIdx() { return resIdx; } + + /** Get Slot Number */ + int getSlot() { return slotNum; } + + /** Get Stage Number */ + int getStageNum() { return stageNum; } + + /** Set/Get Thread Ids */ + void setTid(unsigned _tid) { tid = _tid; } + int getTid() { return tid; } + + /** Instruction this request is for */ + DynInstPtr getInst() { return inst; } + + /** Data from this request. Overridden by Resource-Specific Request + * Objects + */ + virtual PacketDataPtr getData() { return NULL; } + + /** Pointer to Resource that is being used */ + Resource *res; + + /** Instruction being used */ + DynInstPtr inst; + + /** Fault Associated With This Resource Request */ + Fault fault; + + /** Command For This Resource */ + unsigned cmd; + + //////////////////////////////////////// + // + // GET RESOURCE REQUEST STATUS FROM VARIABLES + // + //////////////////////////////////////// + /** Get/Set Completed variables */ + bool isCompleted() { return completed; } + void setCompleted(bool cond = true) { completed = cond; } + + /** Get/Set Squashed variables */ + bool isSquashed() { return squashed; } + void setSquashed() { squashed = true; } + + /** Get/Set IsProcessing variables */ + bool isProcessing() { return processing; } + void setProcessing() { processing = true; } + + /** Get/Set IsWaiting variables */ + bool isWaiting() { return waiting; } + void setWaiting() { waiting = true; } + + protected: + /** Resource Identification */ + int tid; + int stageNum; + int resIdx; + int slotNum; + + /** Resource Status */ + bool completed; + bool squashed; + bool processing; + bool waiting; +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc new file mode 100644 index 000000000..4a0258e71 --- /dev/null +++ b/src/cpu/inorder/resource_pool.9stage.cc @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include +#include + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + for (int i = 0; i < params->numberOfThreads; i++) { + char fbuff_name[20]; + sprintf(fbuff_name, "Fetch-Buffer-T%i", i); + resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params)); + } + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + res_pool_event->schedule(curTick + cpu->cycles(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(&mainEventQueue, CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + reschedule(curTick + resPool->cpu->cycles(delay)); + else if (!scheduled()) + schedule(curTick + resPool->cpu->cycles(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc new file mode 100644 index 000000000..94af68c7a --- /dev/null +++ b/src/cpu/inorder/resource_pool.cc @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/resources/resource_list.hh" + +#include +#include + +using namespace std; +using namespace ThePipeline; + +ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) + : cpu(_cpu) +{ + //@todo: use this function to instantiate the resources in resource pool. This will help in the + //auto-generation of this pipeline model. + //ThePipeline::addResources(resources, memObjects); + + // Declare Resource Objects + // name - id - bandwidth - latency - CPU - Parameters + // -------------------------------------------------- + resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); + + resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(ICache); + resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); + + resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params)); + + resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); + + resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); + + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); + + resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); + + memObjects.push_back(DCache); + resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); + + resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); +} + +void +ResourcePool::init() +{ + for (int i=0; i < resources.size(); i++) { + DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name()); + + resources[i]->init(); + } +} + +string +ResourcePool::name() +{ + return cpu->name() + ".ResourcePool"; +} + + +void +ResourcePool::regStats() +{ + DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->regStats(); + } +} + +Port * +ResourcePool::getPort(const std::string &if_name, int idx) +{ + DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name); + + for (int i = 0; i < memObjects.size(); i++) { + int obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(if_name, idx); + if (port != NULL) { + DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name, + resources[obj_idx]->name(), obj_idx); + return port; + } + } + + return NULL; +} + +unsigned +ResourcePool::getPortIdx(const std::string &port_name) +{ + DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name); + + for (int i = 0; i < memObjects.size(); i++) { + unsigned obj_idx = memObjects[i]; + Port *port = resources[obj_idx]->getPort(port_name, obj_idx); + if (port != NULL) { + DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name); + return obj_idx; + } + } + + return 0; +} + +ResReqPtr +ResourcePool::request(int res_idx, DynInstPtr inst) +{ + //Make Sure This is a valid resource ID + assert(res_idx >= 0 && res_idx < resources.size()); + + return resources[res_idx]->request(inst); +} + +void +ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) +{ + resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); +} + +int +ResourcePool::slotsAvail(int res_idx) +{ + return resources[res_idx]->slotsAvail(); +} + +int +ResourcePool::slotsInUse(int res_idx) +{ + return resources[res_idx]->slotsInUse(); +} + +void +ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, + int delay, int res_idx, int tid) +{ + assert(delay >= 0); + + ResPoolEvent *res_pool_event = new ResPoolEvent(this); + + switch (e_type) + { + case InOrderCPU::ActivateThread: + { + DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + { + DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + tid); + + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::InstGraduated: + { + DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", + curTick + delay); + + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->seqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + case ResourcePool::SquashAll: + { + DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", + curTick + delay); + res_pool_event->setEvent(e_type, + inst, + inst->squashingStage, + inst->bdelaySeqNum, + inst->readTid()); + mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); + + } + break; + + default: + DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); + ; // If Resource Pool doesnt recognize event, we ignore it. + } +} + +void +ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) +{ + resources[res_idx]->unscheduleEvent(inst); +} + +void +ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", + stage_num, tid, done_seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->squash(inst, stage_num, done_seq_num, tid); + } +} + +void +ResourcePool::activateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->activateThread(tid); + } +} + +void +ResourcePool::deactivateAll(unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", + tid); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->deactivateThread(tid); + } +} + +void +ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", + tid, seq_num); + + int num_resources = resources.size(); + + for (int idx = 0; idx < num_resources; idx++) { + resources[idx]->instGraduated(seq_num, tid); + } +} + +ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) + : Event(CPU_Tick_Pri), + resPool(_resPool) +{ eventType = (InOrderCPU::CPUEventType) Default; } + +void +ResourcePool::ResPoolEvent::process() +{ + switch (eventType) + { + case InOrderCPU::ActivateThread: + resPool->activateAll(tid); + break; + + case InOrderCPU::SuspendThread: + case InOrderCPU::DeallocateThread: + resPool->deactivateAll(tid); + break; + + case ResourcePool::InstGraduated: + resPool->instGraduated(seqNum, tid); + break; + + case ResourcePool::SquashAll: + resPool->squashAll(inst, stageNum, seqNum, tid); + break; + + default: + fatal("Unrecognized Event Type"); + } + + resPool->cpu->cpuEventRemoveList.push(this); +} + + +const char * +ResourcePool::ResPoolEvent::description() +{ + return "Resource Pool event"; +} + +/** Schedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::scheduleEvent(int delay) +{ + if (squashed()) + mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay)); + else if (!scheduled()) + mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay)); +} + +/** Unschedule resource event, regardless of its current state. */ +void +ResourcePool::ResPoolEvent::unscheduleEvent() +{ + if (scheduled()) + squash(); +} diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh new file mode 100644 index 000000000..35fce7db7 --- /dev/null +++ b/src/cpu/inorder/resource_pool.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_RESOURCE_POOL_HH__ +#define __CPU_INORDER_RESOURCE_POOL_HH__ + +#include +#include +#include + +#include "cpu/inst_seq.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/params.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/cpu.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Event; +class InOrderCPU; +class Resource; +class ResourceEvent; + +class ResourcePool { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + // List of Resource Pool Events that extends + // the list started by the CPU + // NOTE(1): Resource Pool also uses event list + // CPUEventType defined in inorder/cpu.hh + enum ResPoolEventType { + InstGraduated = InOrderCPU::NumCPUEvents, + SquashAll, + Default + }; + + class ResPoolEvent : public Event + { + protected: + /** Resource Pool */ + ResourcePool *resPool; + + public: + InOrderCPU::CPUEventType eventType; + + DynInstPtr inst; + + InstSeqNum seqNum; + + int stageNum; + + unsigned tid; + + public: + /** Constructs a resource event. */ + ResPoolEvent(ResourcePool *_resPool); + + /** Set Type of Event To Be Scheduled */ + void setEvent(InOrderCPU::CPUEventType e_type, + DynInstPtr _inst, + int stage_num, + InstSeqNum seq_num, + unsigned _tid) + { + eventType = e_type; + inst = _inst; + seqNum = seq_num; + stageNum = stage_num; + tid = _tid; + } + + /** Processes a resource event. */ + virtual void process(); + + /** Returns the description of the resource event. */ + const char *description(); + + /** Schedule Event */ + void scheduleEvent(int delay); + + /** Unschedule This Event */ + void unscheduleEvent(); + }; + + public: + ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ResourcePool() {} + + std::string name(); + + std::string name(int res_idx) { return resources[res_idx]->name(); } + + void init(); + + /** Register Statistics in All Resources */ + void regStats(); + + /** Returns a specific port. */ + Port* getPort(const std::string &if_name, int idx); + + /** Returns a specific port. */ + unsigned getPortIdx(const std::string &if_name); + + Resource* getResource(int res_idx) { return resources[res_idx]; } + + /** Request usage of this resource. Returns -1 if not granted and + * a positive request tag if granted. + */ + ResReqPtr request(int res_idx, DynInstPtr inst); + + /** Squash The Resource */ + void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid); + + /** Squash All Resources in Pool after Done Seq. Num */ + void squashAll(DynInstPtr inst, int stage_num, + InstSeqNum done_seq_num, unsigned tid); + + /** Activate Thread in all resources */ + void activateAll(unsigned tid); + + /** De-Activate Thread in all resources */ + void deactivateAll(unsigned tid); + + /** Broadcast graduation to all resources */ + void instGraduated(InstSeqNum seq_num,unsigned tid); + + /** The number of instructions available that a resource can + * can still process. + */ + int slotsAvail(int res_idx); + + /** The number of instructions using a resource */ + int slotsInUse(int res_idx); + + /** Schedule resource event, regardless of its current state. */ + void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL, + int delay = 0, int res_idx = 0, int tid = 0); + + /** UnSchedule resource event, regardless of its current state. */ + void unscheduleEvent(int res_idx, DynInstPtr inst); + + /** Tasks to perform when simulation starts */ + virtual void startup() { } + + /** The CPU(s) that this resource interacts with */ + InOrderCPU *cpu; + + DynInstPtr dummyInst[ThePipeline::MaxThreads]; + + private: + std::vector resources; + + std::vector memObjects; + +}; + +#endif //__CPU_INORDER_RESOURCE_HH__ diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc new file mode 100644 index 000000000..8e3d25656 --- /dev/null +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resources/agen_unit.hh" + +AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +AGENUnit::execute(int slot_num) +{ + ResourceRequest* agen_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid; + int seq_num = inst->seqNum; + + tid = inst->readTid(); + agen_req->fault = NoFault; + + switch (agen_req->cmd) + { + case GenerateAddr: + { + // Load/Store Instruction + if (inst->isMemRef()) { + DPRINTF(Resource, "[tid:%i] Generating Address for [sn:%i] (%s).\n", + tid, inst->seqNum, inst->staticInst->getName()); + + + // We are not handdling Prefetches quite yet + if (inst->isDataPrefetch() || inst->isInstPrefetch()) { + panic("Prefetches arent handled yet.\n"); + } else { + if (inst->isLoad()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + //inst->setExecuted(); + + DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else if (inst->isStore()) { + fault = inst->calcEA(); + inst->setMemAddr(inst->getEA()); + + DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: " + "%#x.\n", tid, inst->seqNum, inst->getEA()); + } else { + panic("Unexpected memory type!\n"); + } + + if (fault == NoFault) { + agen_req->done(); + } else { + fatal("%s encountered @ [sn:%i]",fault->name(), seq_num); + } + } + } else { + DPRINTF(Resource, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num); + agen_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} diff --git a/src/cpu/inorder/resources/agen_unit.hh b/src/cpu/inorder/resources/agen_unit.hh new file mode 100644 index 000000000..2010c9fa6 --- /dev/null +++ b/src/cpu/inorder/resources/agen_unit.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_AGEN_UNIT_HH__ +#define __CPU_INORDER_AGEN_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/params.hh" + +class AGENUnit : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + AGENUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~AGENUnit() {} + + enum Command { + GenerateAddr + }; + + virtual void execute(int slot_num); + + protected: + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc new file mode 100644 index 000000000..66d0779a2 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.cc @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2004-2005 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: Kevin Lim + */ + +#include +#include + +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/inorder/resources/bpred_unit.hh" + +using namespace std; +using namespace ThePipeline; + +BPredUnit::BPredUnit(ThePipeline::Params *params) + : BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) +{ + // Setup the selected predictor. + if (params->predType == "local") { + localBP = new LocalBP(params->localPredictorSize, + params->localCtrBits, + params->instShiftAmt); + predictor = Local; + } else if (params->predType == "tournament") { + tournamentBP = new TournamentBP(params->localPredictorSize, + params->localCtrBits, + params->localHistoryTableSize, + params->localHistoryBits, + params->globalPredictorSize, + params->globalHistoryBits, + params->globalCtrBits, + params->choicePredictorSize, + params->choiceCtrBits, + params->instShiftAmt); + predictor = Tournament; + } else { + fatal("Invalid BP selected!"); + } + + for (int i=0; i < ThePipeline::MaxThreads; i++) + RAS[i].init(params->RASSize); +} + + +void +BPredUnit::regStats() +{ + lookups + .name(name() + ".BPredUnit.lookups") + .desc("Number of BP lookups") + ; + + condPredicted + .name(name() + ".BPredUnit.condPredicted") + .desc("Number of conditional branches predicted") + ; + + condIncorrect + .name(name() + ".BPredUnit.condIncorrect") + .desc("Number of conditional branches incorrect") + ; + + BTBLookups + .name(name() + ".BPredUnit.BTBLookups") + .desc("Number of BTB lookups") + ; + + BTBHits + .name(name() + ".BPredUnit.BTBHits") + .desc("Number of BTB hits") + ; + + BTBCorrect + .name(name() + ".BPredUnit.BTBCorrect") + .desc("Number of correct BTB predictions (this stat may not " + "work properly.") + ; + + usedRAS + .name(name() + ".BPredUnit.usedRAS") + .desc("Number of times the RAS was used to get a target.") + ; + + RASIncorrect + .name(name() + ".BPredUnit.RASInCorrect") + .desc("Number of incorrect RAS predictions.") + ; +} + + +void +BPredUnit::switchOut() +{ + // Clear any state upon switch out. + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + squash(0, i); + } +} + + +void +BPredUnit::takeOverFrom() +{ + // Can reset all predictor state, but it's not necessarily better + // than leaving it be. +/* + for (int i = 0; i < ThePipeline::MaxThreads; ++i) + RAS[i].reset(); + + BP.reset(); + BTB.reset(); +*/ +} + + +bool +BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid) +{ + // See if branch predictor predicts taken. + // If so, get its target addr either from the BTB or the RAS. + // Save off record of branch stuff so the RAS can be fixed + // up once it's done. + + using TheISA::MachInst; + + bool pred_taken = false; + Addr target; + + ++lookups; + + void *bp_history = NULL; + + if (inst->isUncondCtrl()) { + DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid); + pred_taken = true; + // Tell the BP there was an unconditional branch. + BPUncond(bp_history); + + if (inst->isReturn() && RAS[tid].empty()) { + DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting " + "false.\n", tid); + pred_taken = false; + } + } else { + ++condPredicted; + + pred_taken = BPLookup(PC, bp_history); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i " + "for PC %#x\n", + tid, pred_taken, inst->readPC()); + } + + PredictorHistory predict_record(inst->seqNum, PC, pred_taken, + bp_history, tid); + + // Now lookup in the BTB or RAS. + if (pred_taken) { + if (inst->isReturn()) { + ++usedRAS; + + // If it's a function return call, then look up the address + // in the RAS. + target = RAS[tid].top(); + + // Record the top entry of the RAS, and its index. + predict_record.usedRAS = true; + predict_record.RASIndex = RAS[tid].topIdx(); + predict_record.RASTarget = target; + + assert(predict_record.RASIndex < 16); + + RAS[tid].pop(); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, " + "RAS predicted target: %#x, RAS index: %i.\n", + tid, inst->readPC(), target, predict_record.RASIndex); + } else { + ++BTBLookups; + + if (inst->isCall()) { + RAS[tid].push(PC + sizeof(MachInst)); + + // Record that it was a call so that the top RAS entry can + // be popped off if the speculation is incorrect. + predict_record.wasCall = true; + + DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call" + ", adding %#x to the RAS.\n", + tid, inst->readPC(), PC + sizeof(MachInst)); + } + + if (inst->isCall() && + inst->isUncondCtrl() && + inst->isDirectCtrl()) { + target = inst->branchTarget(); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted" + " target to %#x.\n", + tid, inst->readPC(), target); + } else if (BTB.valid(PC, tid)) { + ++BTBHits; + + // If it's not a return, use the BTB to get the target addr. + target = BTB.lookup(PC, tid); + + DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted" + " target is %#x.\n", + tid, inst->readPC(), target); + } else { + DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a " + "valid entry.\n",tid); + pred_taken = false; + } + } + } + + if (pred_taken) { + // Set the PC and the instruction's predicted target. + PC = target; + inst->setPredTarg(target); + } else { + PC = PC + sizeof(MachInst); + inst->setPredTarg(PC); + } + + predHist[tid].push_front(predict_record); + + DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); + + inst->setBranchPred(pred_taken); + + return pred_taken; +} + + +void +BPredUnit::update(const InstSeqNum &done_sn, unsigned tid) +{ + DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence" + "number %lli.\n", tid, done_sn); + + while (!predHist[tid].empty() && + predHist[tid].back().seqNum <= done_sn) { + // Update the branch predictor with the correct results. + BPUpdate(predHist[tid].back().PC, + predHist[tid].back().predTaken, + predHist[tid].back().bpHistory); + + predHist[tid].pop_back(); + } +} + + +void +BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid) +{ + History &pred_hist = predHist[tid]; + + while (!pred_hist.empty() && + pred_hist.front().seqNum > squashed_sn) { + if (pred_hist.front().usedRAS) { + DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i," + " target: %#x.\n", + tid, + pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + RAS[tid].restore(pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + } else if (pred_hist.front().wasCall) { + DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry " + "added to the RAS.\n",tid); + + RAS[tid].pop(); + } + + // This call should delete the bpHistory. + BPSquash(pred_hist.front().bpHistory); + + pred_hist.pop_front(); + } + +} + + +void +BPredUnit::squash(const InstSeqNum &squashed_sn, + const Addr &corr_target, + const bool actually_taken, + unsigned tid) +{ + // Now that we know that a branch was mispredicted, we need to undo + // all the branches that have been seen up until this branch and + // fix up everything. + + History &pred_hist = predHist[tid]; + + ++condIncorrect; + + DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, " + "setting target to %#x.\n", + tid, squashed_sn, corr_target); + + squash(squashed_sn, tid); + + // If there's a squash due to a syscall, there may not be an entry + // corresponding to the squash. In that case, don't bother trying to + // fix up the entry. + if (!pred_hist.empty()) { + assert(pred_hist.front().seqNum == squashed_sn); + if (pred_hist.front().usedRAS) { + ++RASIncorrect; + } + + BPUpdate(pred_hist.front().PC, actually_taken, + pred_hist.front().bpHistory); + + BTB.update(pred_hist.front().PC, corr_target, tid); + pred_hist.pop_front(); + } +} + + +void +BPredUnit::BPUncond(void * &bp_history) +{ + // Only the tournament predictor cares about unconditional branches. + if (predictor == Tournament) { + tournamentBP->uncondBr(bp_history); + } +} + + +void +BPredUnit::BPSquash(void *bp_history) +{ + if (predictor == Local) { + localBP->squash(bp_history); + } else if (predictor == Tournament) { + tournamentBP->squash(bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +bool +BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history) +{ + if (predictor == Local) { + return localBP->lookup(inst_PC, bp_history); + } else if (predictor == Tournament) { + return tournamentBP->lookup(inst_PC, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history) +{ + if (predictor == Local) { + localBP->update(inst_PC, taken, bp_history); + } else if (predictor == Tournament) { + tournamentBP->update(inst_PC, taken, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + + +void +BPredUnit::dump() +{ + /*typename History::iterator pred_hist_it; + + for (int i = 0; i < ThePipeline::MaxThreads; ++i) { + if (!predHist[i].empty()) { + pred_hist_it = predHist[i].begin(); + + cprintf("predHist[%i].size(): %i\n", i, predHist[i].size()); + + while (pred_hist_it != predHist[i].end()) { + cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, " + "bpHistory:%#x\n", + (*pred_hist_it).seqNum, (*pred_hist_it).PC, + (*pred_hist_it).tid, (*pred_hist_it).predTaken, + (*pred_hist_it).bpHistory); + pred_hist_it++; + } + + cprintf("\n"); + } + }*/ +} diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh new file mode 100644 index 000000000..b945922a7 --- /dev/null +++ b/src/cpu/inorder/resources/bpred_unit.hh @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2004-2005 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: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_INORDER_BPRED_UNIT_HH__ +#define __CPU_INORDER_BPRED_UNIT_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "cpu/inst_seq.hh" + +//#include "cpu/inorder/params.hh" +#include "cpu/o3/2bit_local_pred.hh" +#include "cpu/o3/btb.hh" +#include "cpu/o3/ras.hh" +#include "cpu/o3/tournament_pred.hh" +#include "params/InOrderCPU.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" + +#include + +/** + * Basically a wrapper class to hold both the branch predictor + * and the BTB. + */ +class BPredUnit +{ + private: + + enum PredType { + Local, + Tournament + }; + + PredType predictor; + + public: + + /** + * @param params The params object, that has the size of the BP and BTB. + */ + BPredUnit(ThePipeline::Params *params); + + /** + * Registers statistics. + */ + void regStats(); + + void switchOut(); + + void takeOverFrom(); + + /** + * Predicts whether or not the instruction is a taken branch, and the + * target of the branch if it is taken. + * @param inst The branch instruction. + * @param PC The predicted PC is passed back through this parameter. + * @param tid The thread id. + * @return Returns if the branch is taken or not. + */ + bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid); + + // @todo: Rename this function. + void BPUncond(void * &bp_history); + + /** + * Tells the branch predictor to commit any updates until the given + * sequence number. + * @param done_sn The sequence number to commit any older updates up until. + * @param tid The thread id. + */ + void update(const InstSeqNum &done_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number, and + * corrects that sn's update with the proper address and taken/not taken. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param corr_target The correct branch target. + * @param actually_taken The correct branch direction. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, + bool actually_taken, unsigned tid); + + /** + * @param bp_history Pointer to the history object. The predictor + * will need to update any state and delete the object. + */ + void BPSquash(void *bp_history); + + /** + * Looks up a given PC in the BP to see if it is taken or not taken. + * @param inst_PC The PC to look up. + * @param bp_history Pointer that will be set to an object that + * has the branch predictor state associated with the lookup. + * @return Whether the branch is taken or not taken. + */ + bool BPLookup(Addr &inst_PC, void * &bp_history); + + /** + * Looks up a given PC in the BTB to see if a matching entry exists. + * @param inst_PC The PC to look up. + * @return Whether the BTB contains the given PC. + */ + bool BTBValid(Addr &inst_PC) + { return BTB.valid(inst_PC, 0); } + + /** + * Looks up a given PC in the BTB to get the predicted target. + * @param inst_PC The PC to look up. + * @return The address of the target of the branch. + */ + Addr BTBLookup(Addr &inst_PC) + { return BTB.lookup(inst_PC, 0); } + + /** + * Updates the BP with taken/not taken information. + * @param inst_PC The branch's PC that will be updated. + * @param taken Whether the branch was taken or not taken. + * @param bp_history Pointer to the branch predictor state that is + * associated with the branch lookup that is being updated. + * @todo Make this update flexible enough to handle a global predictor. + */ + void BPUpdate(Addr &inst_PC, bool taken, void *bp_history); + + /** + * Updates the BTB with the target of a branch. + * @param inst_PC The branch's PC that will be updated. + * @param target_PC The branch's target that will be added to the BTB. + */ + void BTBUpdate(Addr &inst_PC, Addr &target_PC) + { BTB.update(inst_PC, target_PC,0); } + + void dump(); + + private: + struct PredictorHistory { + /** + * Makes a predictor history struct that contains any + * information needed to update the predictor, BTB, and RAS. + */ + PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, + const bool pred_taken, void *bp_history, + const unsigned _tid) + : seqNum(seq_num), PC(inst_PC), RASTarget(0), + RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), + wasCall(0), bpHistory(bp_history) + { } + + /** The sequence number for the predictor history entry. */ + InstSeqNum seqNum; + + /** The PC associated with the sequence number. */ + Addr PC; + + /** The RAS target (only valid if a return). */ + Addr RASTarget; + + /** The RAS index of the instruction (only valid if a call). */ + unsigned RASIndex; + + /** The thread id. */ + unsigned tid; + + /** Whether or not it was predicted taken. */ + bool predTaken; + + /** Whether or not the RAS was used. */ + bool usedRAS; + + /** Whether or not the instruction was a call. */ + bool wasCall; + + /** Pointer to the history object passed back from the branch + * predictor. It is used to update or restore state of the + * branch predictor. + */ + void *bpHistory; + }; + + typedef std::list History; + + /** + * The per-thread predictor history. This is used to update the predictor + * as instructions are committed, or restore it to the proper state after + * a squash. + */ + History predHist[ThePipeline::MaxThreads]; + + /** The local branch predictor. */ + LocalBP *localBP; + + /** The tournament branch predictor. */ + TournamentBP *tournamentBP; + + /** The BTB. */ + DefaultBTB BTB; + + /** The per-thread return address stack. */ + ReturnAddrStack RAS[ThePipeline::MaxThreads]; + + /** Stat for number of BP lookups. */ + Stats::Scalar<> lookups; + /** Stat for number of conditional branches predicted. */ + Stats::Scalar<> condPredicted; + /** Stat for number of conditional branches predicted incorrectly. */ + Stats::Scalar<> condIncorrect; + /** Stat for number of BTB lookups. */ + Stats::Scalar<> BTBLookups; + /** Stat for number of BTB hits. */ + Stats::Scalar<> BTBHits; + /** Stat for number of times the BTB is correct. */ + Stats::Scalar<> BTBCorrect; + /** Stat for number of times the RAS is used to get a target. */ + Stats::Scalar<> usedRAS; + /** Stat for number of times the RAS is incorrect. */ + Stats::Scalar<> RASIncorrect; +}; + +#endif // __CPU_INORDER_BPRED_UNIT_HH__ diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc new file mode 100644 index 000000000..b563a3057 --- /dev/null +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resources/branch_predictor.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + branchPred(params) +{ + instSize = sizeof(MachInst); +} + +void +BranchPredictor::regStats() +{ + predictedTaken + .name(name() + ".predictedTaken") + .desc("Number of Branches Predicted As Taken (True)."); + + predictedNotTaken + .name(name() + ".predictedNotTaken") + .desc("Number of Branches Predicted As Not Taken (False)."); + + Resource::regStats(); +} + +void +BranchPredictor::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* bpred_req = reqMap[slot_num]; + + DynInstPtr inst = bpred_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + //int stage_num = bpred_req->getStageNum(); + + bpred_req->fault = NoFault; + + switch (bpred_req->cmd) + { + case PredictBranch: + { + Addr pred_PC = inst->readNextPC(); + + if (inst->isControl()) { + // If predicted, the pred_PC will be updated to new target value + // If not, the pred_PC be updated to pc+8 + bool predict_taken = branchPred.predict(inst, pred_PC, tid); + + if (predict_taken) { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n", + tid, seq_num); + + inst->setPredTarg(pred_PC); + + predictedTaken++; + } else { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted false.\n", + tid, seq_num); + + if (inst->isCondDelaySlot()) + { + inst->setPredTarg(inst->readPC() + (2 * instSize)); + } else { + inst->setPredTarg(pred_PC); + } + + predictedNotTaken++; + } + + inst->setBranchPred(predict_taken); + + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n", + tid, seq_num, pred_PC); + + } else { + DPRINTF(Resource, "[tid:%i]: Ignoring [sn:%i] because this isn't " + "a control instruction.\n", tid, seq_num); + } + + bpred_req->done(); + } + break; + + case UpdatePredictor: + { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n", + tid, seq_num); + + + branchPred.update(seq_num, tid); + + bpred_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +BranchPredictor::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(Resource, "Squashing...\n"); + branchPred.squash(squash_seq_num, tid); +} + +void +BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid) +{ + branchPred.update(seq_num, tid); +} diff --git a/src/cpu/inorder/resources/branch_predictor.hh b/src/cpu/inorder/resources/branch_predictor.hh new file mode 100644 index 000000000..66eb1afe8 --- /dev/null +++ b/src/cpu/inorder/resources/branch_predictor.hh @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__ +#define __CPU_INORDER_BRANCH_PREDICTOR_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/bpred_unit.hh" +#include "cpu/inorder/cpu.hh" +//#include "cpu/inorder/params.hh" + +class BranchPredictor : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + enum Command { + PredictBranch, + UpdatePredictor + }; + + public: + BranchPredictor(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + + virtual void regStats(); + + virtual void execute(int slot_num); + + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + + virtual void instGraduated(InstSeqNum seq_num,unsigned tid); + + protected: + /** List of instructions this resource is currently + * processing. + */ + BPredUnit branchPred; + + int instSize; + + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar<> predictedTaken; + Stats::Scalar<> predictedNotTaken; + +}; + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc new file mode 100644 index 000000000..79ca7a096 --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "arch/isa_traits.hh" +#include "arch/mips/locked_mem.hh" +#include "arch/utility.hh" +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "mem/request.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + + +Tick +CacheUnit::CachePort::recvAtomic(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvAtomic callback!"); + return curTick; +} + +void +CacheUnit::CachePort::recvFunctional(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvFunctional callback!"); +} + +void +CacheUnit::CachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("DefaultFetch doesn't expect recvStatusChange callback!"); +} + +bool +CacheUnit::CachePort::recvTiming(Packet *pkt) +{ + cachePortUnit->processCacheCompletion(pkt); + return true; +} + +void +CacheUnit::CachePort::recvRetry() +{ + cachePortUnit->recvRetry(); +} + +CacheUnit::CacheUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + retryPkt(NULL), retrySlot(-1) +{ + //cacheData.resize(res_width); + //slotStatus = new CachePortStatus[width]; + //fetchPC = new Addr[width]; + cachePort = new CachePort(this); + + cacheBlocked = false; +} + + +Port * +CacheUnit::getPort(const std::string &if_name, int idx) +{ + if (if_name == resName) + return cachePort; + else + return NULL; +} + +int +CacheUnit::getSlot(DynInstPtr inst) +{ + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access.\n"); + } + + Addr req_addr = inst->getMemAddr(); + + if (resName == "icache_port" || + find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) { + + int new_slot = Resource::getSlot(inst); + + if (new_slot != -1) { + inst->memTime = curTick; + addrList.push_back(req_addr); + addrMap[req_addr] = inst->seqNum; + DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Address %08p added to dependency list.\n", + inst->readTid(), inst->seqNum, req_addr); + return new_slot; + } else { + return -1; + } + + + } else { + DPRINTF(InOrderCachePort,"Denying request because there is an outstanding" + " request to/for addr. %08p. by [sn:%i] @ tick %i\n", + req_addr, addrMap[req_addr], inst->memTime); + return -1; + } +} + +void +CacheUnit::freeSlot(int slot_num) +{ + std::vector::iterator vect_it = find(addrList.begin(), addrList.end(), + reqMap[slot_num]->inst->getMemAddr()); + assert(vect_it != addrList.end()); + + DPRINTF(InOrderCachePort, "[tid:%i]: Address %08p removed from dependency list.\n", + reqMap[slot_num]->inst->readTid(), (*vect_it)); + + addrList.erase(vect_it); + + Resource::freeSlot(slot_num); +} + +ResReqPtr +CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + ScheduleEntry* sched_entry = inst->resSched.top(); + + if (!inst->validMemAddr()) { + panic("Mem. Addr. must be set before requesting cache access.\n"); + } + + int req_size = 0; + MemCmd::Command pkt_cmd; + + if (sched_entry->cmd == InitiateReadData) { + pkt_cmd = MemCmd::ReadReq; + req_size = inst->getMemAccSize(); + + DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p.\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateWriteData) { + pkt_cmd = MemCmd::WriteReq; + req_size = inst->getMemAccSize(); + + + DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p.\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else if (sched_entry->cmd == InitiateFetch){ + pkt_cmd = MemCmd::ReadReq; + req_size = sizeof(MachInst); //@TODO: mips16e + + DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p.\n", + inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); + } else { + panic("%i: Unexpected request type (%i) to %s", curTick, sched_entry->cmd, name()); + } + + return new CacheRequest(this, inst, stage_num, id, slot_num, + sched_entry->cmd, req_size, pkt_cmd, + 0/*flags*/, this->cpu->readCpuId()); +} + +void +CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) +{ + //service_request = false; + + CacheReqPtr cache_req = dynamic_cast(findRequest(inst)); + assert(cache_req); + + // Check to see if this instruction is requesting the same command + // or a different one + if (cache_req->cmd != inst->resSched.top()->cmd) { + // If different, then update command in the request + cache_req->cmd = inst->resSched.top()->cmd; + DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this " + "instruction.\n", inst->readTid(), inst->seqNum); + + service_request = true; + } else { + // If same command, just check to see if memory access was completed + // but dont try to re-execute + DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: requesting this resource again.\n", + inst->readTid(), inst->seqNum); + + service_request = true; + } + +} + +void +CacheUnit::execute(int slot_num) +{ + if (cacheBlocked) { + DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access.\n"); + return; + } + + CacheReqPtr cache_req = dynamic_cast(reqMap[slot_num]); + assert(cache_req); + + DynInstPtr inst = cache_req->inst; + int tid; + tid = inst->readTid(); + int seq_num; + seq_num = inst->seqNum; + //int stage_num = cache_req->getStageNum(); + + cache_req->fault = NoFault; + + switch (cache_req->cmd) + { + case InitiateFetch: + { + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating fetch access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: Fetching new cache block from addr: %08p\n", + tid, cache_req->memReq->getVaddr()); + + inst->setCurResSlot(slot_num); + doDataAccess(inst); + } + break; + + case CompleteFetch: + { + if (cache_req->isMemAccComplete()) { + DPRINTF(InOrderCachePort, + "[tid:%i]: Completing Fetch Access for [sn:%i]\n", + tid, inst->seqNum); + + MachInst mach_inst = cache_req->dataPkt->get(); + + //@TODO: May Need This Function for Endianness-Compatibility + //mach_inst = gtoh(*reinterpret_cast(&cacheData[tid][offset])); + + DPRINTF(InOrderCachePort, + "[tid:%i]: Fetched instruction is %08p\n", + tid, mach_inst); + + //ExtMachInst ext_inst + // = TheISA::makeExtMI(mach_inst, cpu->tcBase(tid)); + + inst->setMachInst(mach_inst); + inst->setASID(tid); + inst->setThreadState(cpu->thread[tid]); + + DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n", + tid, seq_num, inst->staticInst->disassemble(inst->PC)); + + // Set Up More TraceData info + if (inst->traceData) { + inst->traceData->setStaticInst(inst->staticInst); + inst->traceData->setPC(inst->readPC()); + } + + cache_req->done(); + } else { + DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access.\n", + tid, inst->seqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: Fetch miss from %08p.\n", + tid, cache_req->inst->readPC()); + cache_req->setCompleted(false); + } + } + break; + + case InitiateReadData: + case InitiateWriteData: + { + DPRINTF(InOrderCachePort, "[tid:%u]: Initiating data access to %s " + "for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + inst->setCurResSlot(slot_num); + //inst->memAccess(); + inst->initiateAcc(); + } + break; + + case CompleteReadData: + case CompleteWriteData: + { + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Data Access.\n", + tid, inst->seqNum); + if (cache_req->isMemAccComplete()) { + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->getMemAddr()); + cache_req->setCompleted(false); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +Fault +CacheUnit::doDataAccess(DynInstPtr inst) +{ + Fault fault = NoFault; + int tid = 0; + + tid = inst->readTid(); + + CacheReqPtr cache_req + = dynamic_cast(reqMap[inst->getCurResSlot()]); + assert(cache_req); + + cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd, + Packet::Broadcast); + + if (cache_req->dataPkt->isRead()) { + cache_req->dataPkt->dataStatic(cache_req->reqData); + } else if (cache_req->dataPkt->isWrite()) { + cache_req->dataPkt->dataStatic(&cache_req->inst->storeData); + + } + + cache_req->dataPkt->time = curTick; + + bool do_access = true; // flag to suppress cache access + + Request *memReq = cache_req->dataPkt->req; + + if (cache_req->dataPkt->isWrite() && memReq->isLocked()) { + assert(cache_req->inst->isStoreConditional()); + DPRINTF(InOrderCachePort, "Evaluating Store Conditional access.\n"); + do_access = TheISA::handleLockedWrite(cpu, memReq); + } + + + DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] attempting to access cache..\n", tid, inst->seqNum); + + //@TODO: If you want to ignore failed store conditional accesses, then + // enable this. However, this might skew memory stats because + // the failed store conditional access will get ignored. + // - Remove optionality here ... + if (1/*do_access*/) { + if (!cachePort->sendTiming(cache_req->dataPkt)) { + DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is waiting to retry request.\n", tid, inst->seqNum); + + retrySlot = cache_req->getSlot(); + retryReq = cache_req; + retryPkt = cache_req->dataPkt; + + cacheStatus = cacheWaitRetry; + + //cacheBlocked = true; + + DPRINTF(InOrderStall, "STALL: \n"); + + cache_req->setCompleted(false); + } else { + DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is now waiting for cache response.\n", tid, inst->seqNum); + cache_req->setCompleted(); + cache_req->setMemAccPending(); + cacheStatus = cacheWaitResponse; + cacheBlocked = false; + } + } else if (!do_access && memReq->isLocked()){ + // Store-Conditional instructions complete even if they "failed" + assert(cache_req->inst->isStoreConditional()); + cache_req->setCompleted(true); + + DPRINTF(LLSC, "[tid:%i]: T%i Ignoring Failed Store Conditional Access.\n", + tid, tid); + + cache_req->dataPkt->req->setExtraData(0); + + processCacheCompletion(cache_req->dataPkt); + + // Automatically set these since we ignored the memory access + //cache_req->setMemAccPending(false); + //cache_req->setMemAccCompleted(); + } else { + // Make cache request again since access due to + // inability to access + DPRINTF(InOrderStall, "STALL: \n"); + cache_req->setCompleted(false); + } + + return fault; +} + +void +CacheUnit::processCacheCompletion(PacketPtr pkt) +{ + // Cast to correct packet type + CacheReqPacket* cache_pkt = dynamic_cast(pkt); + assert(cache_pkt); + + if (cache_pkt->cacheReq->isSquashed()) { + DPRINTF(InOrderCachePort, + "Ignoring completion of squashed access, [tid:%i] [sn:%i].\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum); + + cache_pkt->cacheReq->done(); + return; + } else { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p.\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum, + cache_pkt->cacheReq->getInst()->getMemAddr()); + } + + // Cast to correct request type + CacheRequest *cache_req = dynamic_cast( + findRequest(cache_pkt->cacheReq->getInst())); + assert(cache_req); + +#if TRACING_ON + // Get resource request info + unsigned tid = 0; +#endif + + //tid = pkt->req->getThreadNum(); + unsigned stage_num = cache_req->getStageNum(); + DynInstPtr inst = cache_req->inst; + + if (!cache_req->isSquashed()) { + if (inst->resSched.top()->cmd == CompleteFetch) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing fetch access.\n", + tid, inst->seqNum); + } else if (inst->staticInst && inst->isMemRef()) { + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Processing cache access.\n", + tid, inst->seqNum); + + inst->completeAcc(pkt); + + if (inst->isLoad()) { + assert(cache_pkt->isRead()); + + if (cache_pkt->req->isLocked()) { + DPRINTF(InOrderCachePort, "[tid:%u]: Handling Load-Linked " + "access for [sn:%u].\n", tid, inst->seqNum); + TheISA::handleLockedRead(cpu, cache_pkt->req); + } + + // @TODO: Hardcoded to for load instructions. Assumes that + // the dest. idx 0 is always where the data is loaded to. + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data loaded was: %08p.\n", + tid, inst->seqNum, inst->readIntResult(0)); + } else if(inst->isStore()) { + assert(cache_pkt->isWrite()); + + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Data stored was: %08p.\n", + tid, inst->seqNum, + getMemData(cache_pkt)); + + } + } + + cache_req->setMemAccPending(false); + cache_req->setMemAccCompleted(); + + // Wake up the CPU (if it went to sleep and was waiting on this + // completion event). + cpu->wakeCPU(); + + DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n", + tid, cpu->pipelineStage[stage_num]->name()); + + cpu->switchToActive(stage_num); + } else { + DPRINTF(InOrderCachePort, + "[tid:%u] Cache miss on memory access to block @ %08p " + "completed, but squashed.\n", tid, cache_req->inst->readPC()); + cache_req->setMemAccCompleted(); + } + + inst->unsetMemAddr(); +} + +void +CacheUnit::recvRetry() +{ + DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i].\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + + assert(retryPkt != NULL); + assert(cacheBlocked); + assert(cacheStatus == cacheWaitRetry); + + if (cachePort->sendTiming(retryPkt)) { + cacheStatus = cacheWaitResponse; + retryPkt = NULL; + cacheBlocked = false; + } else { + DPRINTF(InOrderCachePort, "Retry Request for [tid:%i] [sn:%i] failed.\n", + retryReq->inst->readTid(), retryReq->inst->seqNum); + } + +} + +void +CacheUnit::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + std::vector slot_remove_list; + + std::map::iterator map_it = reqMap.begin(); + std::map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(InOrderCachePort, + "[tid:%i] Squashing request from [sn:%i].\n", + req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); + + req_ptr->setSquashed(); + + req_ptr->getInst()->setSquashed(); + + CacheReqPtr cache_req = dynamic_cast(req_ptr); + assert(cache_req); + + if (!cache_req->isMemAccPending()) { + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } + +} + +uint64_t CacheUnit::getMemData(Packet *packet) { + switch (packet->getSize()) + { + case 8: + return packet->get(); + + case 16: + return packet->get(); + + case 32: + return packet->get(); + + case 864: + return packet->get(); + + default: + std::cerr << "bad store data size = " << packet->getSize() << std::endl; + + assert(0); + return 0; + } +} + diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh new file mode 100644 index 000000000..9d048d789 --- /dev/null +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_CACHE_UNIT_HH__ +#define __CPU_INORDER_CACHE_UNIT_HH__ + +#include +#include +#include + +//#include "cpu/inorder/params.hh" + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" +#include "mem/port.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "sim/sim_object.hh" + +#include "params/InOrderCPU.hh" + +class CacheRequest; +typedef CacheRequest* CacheReqPtr; + +class CacheReqPacket; +typedef CacheReqPacket* CacheReqPktPtr; + +class CacheUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + CacheUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~CacheUnit() {} + + enum Command { + InitiateFetch, + CompleteFetch, + InitiateReadData, + CompleteReadData, + InitiateWriteData, + CompleteWriteData, + Fetch, + ReadData, + WriteData + }; + + public: + /** CachePort class for the Cache Unit. Handles doing the + * communication with the cache/memory. + */ + class CachePort : public Port + { + protected: + /** Pointer to cache port unit */ + CacheUnit *cachePortUnit; + + public: + /** Default constructor. */ + CachePort(CacheUnit *_cachePortUnit) + : Port(_cachePortUnit->name() + "-cache-port", (MemObject*)_cachePortUnit->cpu), + cachePortUnit(_cachePortUnit) + { } + + bool snoopRangeSent; + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles setting fetch to the + * proper status to start fetching. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of a failed fetch. */ + virtual void recvRetry(); + }; + + enum CachePortStatus { + cacheWaitResponse, + cacheWaitRetry, + cacheAccessComplete + }; + + ///virtual void init(); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + void requestAgain(DynInstPtr inst, bool &try_request); + + int getSlot(DynInstPtr inst); + + void freeSlot(int slot_num); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + + /** Processes cache completion event. */ + void processCacheCompletion(PacketPtr pkt); + + void recvRetry(); + + /** Align a PC to the start of an I-cache block. */ + Addr cacheBlockAlignPC(Addr addr) + { + //addr = TheISA::realPCToFetchPC(addr); + return (addr & ~(cacheBlkMask)); + } + + /** Returns a specific port. */ + Port *getPort(const std::string &if_name, int idx); + + /** Fetch on behalf of an instruction. Will check to see + * if instruction is actually in resource before + * trying to fetch. + */ + //Fault doFetchAccess(DynInstPtr inst); + + /** Read/Write on behalf of an instruction. + * curResSlot needs to be a valid value in instruction. + */ + Fault doDataAccess(DynInstPtr inst); + + uint64_t getMemData(Packet *packet); + + protected: + /** Cache interface. */ + CachePort *cachePort; + + CachePortStatus cacheStatus; + + CacheReqPtr retryReq; + + PacketPtr retryPkt; + + int retrySlot; + + bool cacheBlocked; + + std::vector addrList; + + std::map addrMap; + + public: + int cacheBlkSize; + + int cacheBlkMask; + + /** Align a PC to the start of the Cache block. */ + Addr cacheBlockAlign(Addr addr) + { + return (addr & ~(cacheBlkMask)); + } + + /** THINGS USED FOR FETCH */ + // NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION + /** The mem line being fetched. */ + //uint8_t *cacheData[ThePipeline::MaxThreads]; + + /** The Addr of the cacheline that has been loaded. */ + //Addr cacheBlockAddr[ThePipeline::MaxThreads]; + + //unsigned fetchOffset[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ +}; + +struct CacheSchedEntry : public ThePipeline::ScheduleEntry { + enum EntryType { + FetchAccess, + DataAccess + }; + + CacheSchedEntry(int stage_num, int _priority, int res_num, MemCmd::Command pkt_cmd, + EntryType _type = FetchAccess) : + ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd), + type(_type) + { } + + MemCmd::Command pktCmd; + EntryType type; +}; + +class CacheRequest : public ResourceRequest { + public: + CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int req_size, + MemCmd::Command pkt_cmd, unsigned flags, int cpu_id) + : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd), + pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false) + { + memReq = inst->memReq; + + reqData = new uint8_t[req_size]; + retryPkt = NULL; + } + + virtual ~CacheRequest() + { + /* + delete reqData; + + Can get rid of packet and packet request now + if (*dataPkt) { + if (*dataPkt->req) { + delete dataPkt->req; + } + delete dataPkt; + } + + // Can get rid of packet and packet request now + if (retryPkt) { + if (retryPkt->req) { + delete retryPkt->req; + } + delete retryPkt; + }*/ + + if (memReq) { + delete memReq; + } + } + + virtual PacketDataPtr getData() + { return reqData; } + + void setMemAccCompleted(bool completed = true) { memAccComplete = completed; } + bool isMemAccComplete() { return memAccComplete; } + + void setMemAccPending(bool pending = true) { memAccPending = pending; } + bool isMemAccPending() { return memAccPending; } + + //Make this data private/protected! + MemCmd::Command pktCmd; + RequestPtr memReq; + PacketDataPtr reqData; + PacketPtr dataPkt; + PacketPtr retryPkt; + + bool memAccComplete; + bool memAccPending; +}; + +class CacheReqPacket : public Packet { + public: + CacheReqPacket(CacheRequest *_req, + Command _cmd, short _dest) + : Packet(_req->memReq, _cmd, _dest), cacheReq(_req) + { + + } + + CacheRequest *cacheReq; +}; + +#endif //__CPU_CACHE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc new file mode 100644 index 000000000..1628c32d0 --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resources/decode_unit.hh" + +using namespace TheISA; +using namespace ThePipeline; +using namespace std; + +DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + for (int tid = 0; tid < MaxThreads; tid++) { + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +void +DecodeUnit::execute(int slot_num) +{ + ResourceRequest* decode_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + decode_req->fault = NoFault; + + switch (decode_req->cmd) + { + case DecodeInst: + { + bool done_sked = ThePipeline::createBackEndSchedule(inst); + + if (done_sked) { + DPRINTF(Resource, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", + tid, seq_num); + regDepMap[tid]->insert(inst); + decode_req->done(); + } else { + DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create " + "schedule for instruction [sn:%i] \n", tid, inst->seqNum); + DPRINTF(InOrderStall, "STALL: \n"); + decode_req->done(false); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + +void +DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n", + tid, stage_num, squash_seq_num); + + //cpu->removeInstsUntil(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh new file mode 100644 index 000000000..3813de6c4 --- /dev/null +++ b/src/cpu/inorder/resources/decode_unit.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_DECODE_UNIT_HH__ +#define __CPU_INORDER_DECODE_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class DecodeUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + DecodeUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~DecodeUnit() {} + + enum Command { + DecodeInst + }; + + virtual void execute(int slot_num); + + void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + protected: + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_DECODE_UNIT_HH__ diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc new file mode 100644 index 000000000..e41291103 --- /dev/null +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace ThePipeline; + +ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +ExecutionUnit::regStats() +{ + predictedTakenIncorrect + .name(name() + ".predictedTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Taken."); + + predictedNotTakenIncorrect + .name(name() + ".predictedNotTakenIncorrect") + .desc("Number of Branches Incorrectly Predicted As Not Taken)."); + + Resource::regStats(); +} + +void +ExecutionUnit::execute(int slot_num) +{ + ResourceRequest* exec_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + exec_req->fault = NoFault; + + DPRINTF(Resource, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n", + tid, seq_num, inst->readPC()); + + switch (exec_req->cmd) + { + case ExecuteInst: + { + if (inst->isMemRef()) { + fatal("%s not configured to handle memory ops.\n", resName); + } else if (inst->isControl()) { + // Evaluate Branch + fault = inst->execute(); + + inst->setExecuted(); + + if (fault == NoFault) { + // If branch is mispredicted, then signal squash + // throughout all stages behind the pipeline stage + // that got squashed. + if (inst->mispredicted()) { + int stage_num = exec_req->getStageNum(); + int tid = inst->readTid(); + + // If it's a branch ... + if (inst->isDirectCtrl()) { + assert(!inst->isIndirectCtrl()); + + if (inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + + DPRINTF(Resource, "[tid:%i]: Conditional branch inst" + "[sn:%i] PC %#x mispredicted as taken.\n", tid, + seq_num, inst->PC); + } else if (!inst->predTaken() && inst->isCondDelaySlot()) { + inst->bdelaySeqNum = seq_num; + inst->setPredTarg(inst->nextPC); + inst->procDelaySlotOnMispred = true; + + DPRINTF(Resource, "[tid:%i]: Conditional branch inst." + "[sn:%i] PC %#x mispredicted as not taken.\n", tid, + seq_num, inst->PC); + } else { + inst->bdelaySeqNum = seq_num + 1; + + DPRINTF(Resource, "[tid:%i]: Misprediction detected at " + "[sn:%i] PC %#x,\n\t squashing after delay slot " + "instruction [sn:%i].\n", + tid, seq_num, inst->PC, inst->bdelaySeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch " + "misprediction at %#x\n", tid, inst->PC); + inst->setPredTarg(inst->nextNPC); + } + + DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + + } else if(inst->isIndirectCtrl()){ + inst->setPredTarg(inst->nextNPC); + inst->bdelaySeqNum = seq_num + 1; + DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid, + inst->readPredTarg()); + } else { + panic("Non-control instruction (%s) mispredicting?!!", + inst->staticInst->getName()); + } + + DPRINTF(Resource, "[tid:%i] Squashing will start from stage %i.\n", + tid, stage_num); + + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + inst->squashingStage = stage_num; + + // Squash throughout other resources + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, + inst, 0, 0, tid); + + if (inst->predTaken()) { + predictedTakenIncorrect++; + } else { + predictedNotTakenIncorrect++; + } + } + exec_req->done(); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + } + } else { + // Regular ALU instruction + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + exec_req->done(); + + DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + + diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh new file mode 100644 index 000000000..e969497a2 --- /dev/null +++ b/src/cpu/inorder/resources/execution_unit.hh @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_EXECUTION_UNIT_HH__ +#define __CPU_INORDER_EXECUTION_UNIT_HH__ + +#include +#include +#include + +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class ExecutionUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ExecuteInst + }; + + public: + ExecutionUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~ExecutionUnit() {} + + public: + virtual void regStats(); + + /** Execute the function of this resource. The Default is action + * is to do nothing. More specific models will derive from this + * class and define their own execute function. + */ + virtual void execute(int slot_num); + + protected: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + Stats::Scalar<> predictedTakenIncorrect; + Stats::Scalar<> predictedNotTakenIncorrect; +}; + + +#endif //__CPU_INORDER_EXCUTION_UNIT_HH__ diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc new file mode 100644 index 000000000..00f76f74b --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resource_pool.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + instSize = sizeof(MachInst); + + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + } +} + +void +FetchSeqUnit::init() +{ + resourceEvent = new FetchSeqEvent[width]; + + initSlots(); +} + +void +FetchSeqUnit::execute(int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + ResourceRequest* fs_req = reqMap[slot_num]; + DynInstPtr inst = fs_req->inst; + int tid = inst->readTid(); + int stage_num = fs_req->getStageNum(); + int seq_num = inst->seqNum; + + fs_req->fault = NoFault; + + switch (fs_req->cmd) + { + case AssignNextPC: + { + if (pcValid[tid]) { + + if (delaySlotInfo[tid].targetReady && + delaySlotInfo[tid].numInsts == 0) { + // Set PC to target + PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC + nextPC[tid] = PC[tid] + instSize; //next_NPC + nextNPC[tid] = PC[tid] + (2 * instSize); + + delaySlotInfo[tid].targetReady = false; + + DPRINTF(Resource, "[tid:%i]: Setting PC to delay slot target\n",tid); + } + + inst->setPC(PC[tid]); + inst->setNextPC(PC[tid] + instSize); + inst->setNextNPC(PC[tid] + (instSize * 2)); + + inst->setPredTarg(inst->readNextNPC()); + + inst->setMemAddr(PC[tid]); + inst->setSeqNum(cpu->getAndIncrementInstSeq(tid)); + + DPRINTF(Resource, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid, + inst->seqNum, inst->readPC()); + + if (delaySlotInfo[tid].numInsts > 0) { + --delaySlotInfo[tid].numInsts; + + // It's OK to set PC to target of branch + if (delaySlotInfo[tid].numInsts == 0) { + delaySlotInfo[tid].targetReady = true; + } + + DPRINTF(Resource, "[tid:%i]: %i delay slot inst(s) left to" + " process.\n", tid, delaySlotInfo[tid].numInsts); + } + + PC[tid] = nextPC[tid]; + nextPC[tid] = nextNPC[tid]; + nextNPC[tid] += instSize; + + fs_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid); + fs_req->setCompleted(false); + } + } + break; + + case UpdateTargetPC: + { + if (inst->isControl()) { + // If it's a return, then we must wait for resolved address. + if (inst->isReturn() && !inst->predTaken()) { + cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true; + pcValid[tid] = false; + pcBlockStage[tid] = stage_num; + } else if (inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken AND Conditional Control + DPRINTF(Resource, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. " + "Delay inst. Skipping delay slot and Updating PC to %08p\n", + tid, inst->seqNum, inst->readPC(), inst->readPredTarg()); + + DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num); + + inst->bdelaySeqNum = seq_num; + inst->squashingStage = stage_num; + + squashAfterInst(inst, stage_num, tid); + } else if (!inst->isCondDelaySlot() && !inst->predTaken()) { + // Not-Taken Control + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control " + "inst. updating PC to %08p\n", tid, inst->seqNum, + inst->readNextPC()); + + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readNextNPC(); + + } else if (inst->predTaken()) { + // Taken Control + ++delaySlotInfo[tid].numInsts; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = inst->readPredTarg(); + + DPRINTF(Resource, "[tid:%i]: [sn:%i] Updating delay slot target " + "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg()); + + // Set-Up Squash Through-Out Pipeline + DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + tid, stage_num, seq_num + 1); + inst->bdelaySeqNum = seq_num + 1; + inst->squashingStage = stage_num; + + // Do Squashing + squashAfterInst(inst, stage_num, tid); + } + } else { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Ignoring branch target update " + "since then is not a control instruction.\n", tid, inst->seqNum); + } + + fs_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +inline void +FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid) +{ + // Squash In Pipeline Stage + cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); + + // Squash inside current resource, so if there needs to be fetching on same cycle + // the fetch information will be correct. + // squash(inst, stage_num, inst->bdelaySeqNum, tid); + + // Schedule Squash Through-out Resource Pool + cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0); +} +void +FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i.\n", + tid, squash_stage); + + InstSeqNum done_seq_num = inst->bdelaySeqNum; + Addr new_PC = inst->readPredTarg(); + + if (squashSeqNum[tid] <= done_seq_num && + lastSquashCycle[tid] == curTick) { + DPRINTF(Resource, "[tid:%i]: Ignoring squash from stage %i, since" + "there is an outstanding squash that is older.\n", + tid, squash_stage); + } else { + squashSeqNum[tid] = done_seq_num; + lastSquashCycle[tid] = curTick; + + // If The very next instruction number is the done seq. num, + // then we haven't seen the delay slot yet ... if it isn't + // the last done_seq_num then this is the delay slot inst. + if (cpu->nextInstSeqNum(tid) != done_seq_num && + !inst->procDelaySlotOnMispred) { + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + // Reset PC + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + + DPRINTF(Resource, "[tid:%i]: Setting PC to %08p.\n", + tid, PC[tid]); + } else { + delaySlotInfo[tid].numInsts = 1; + delaySlotInfo[tid].targetReady = false; + delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC; + + // Reset PC to Delay Slot Instruction + if (inst->procDelaySlotOnMispred) { + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + nextNPC[tid] = new_PC + (2 * instSize); + } + + } + + // Unblock Any Stages Waiting for this information to be updated ... + if (!pcValid[tid]) { + cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true; + } + + pcValid[tid] = true; + } + + Resource::squash(inst, squash_stage, squash_seq_num, tid); +} + +FetchSeqUnit::FetchSeqEvent::FetchSeqEvent() + : ResourceEvent() +{ } + +void +FetchSeqUnit::FetchSeqEvent::process() +{ + FetchSeqUnit* fs_res = dynamic_cast(resource); + assert(fs_res); + + for (int i=0; i < MaxThreads; i++) { + fs_res->PC[i] = fs_res->cpu->readPC(i); + fs_res->nextPC[i] = fs_res->cpu->readNextPC(i); + fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i); + DPRINTF(Resource, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n", + fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]); + + fs_res->pcValid[i] = true; + } + + //cpu->fetchPriorityList.push_back(tid); +} + + +void +FetchSeqUnit::activateThread(unsigned tid) +{ + pcValid[tid] = true; + + PC[tid] = cpu->readPC(tid); + nextPC[tid] = cpu->readNextPC(tid); + nextNPC[tid] = cpu->readNextNPC(tid); + + cpu->fetchPriorityList.push_back(tid); + + DPRINTF(Resource, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n", + tid, PC[tid], nextPC[tid], nextNPC[tid]); +} + +void +FetchSeqUnit::deactivateThread(unsigned tid) +{ + delaySlotInfo[tid].numInsts = 0; + delaySlotInfo[tid].targetReady = false; + + pcValid[tid] = false; + pcBlockStage[tid] = 0; + + squashSeqNum[tid] = (InstSeqNum)-1; + lastSquashCycle[tid] = 0; + + std::list::iterator thread_it = find(cpu->fetchPriorityList.begin(), + cpu->fetchPriorityList.end(), + tid); + + if (thread_it != cpu->fetchPriorityList.end()) + cpu->fetchPriorityList.erase(thread_it); +} diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh new file mode 100644 index 000000000..2b074bbaa --- /dev/null +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_FETCH_SEQ_UNIT_HH__ +#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +using namespace ThePipeline; + +class FetchSeqUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + AssignNextPC, + UpdateTargetPC + }; + + public: + FetchSeqUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~FetchSeqUnit() {} + + virtual void init(); + virtual void activateThread(unsigned tid); + virtual void deactivateThread(unsigned tid); + virtual void execute(int slot_num); + + /** Override default Resource squash sequence. This actually, + * looks in the global communication buffer to get squash + * info + */ + virtual void squash(DynInstPtr inst, int squash_stage, + InstSeqNum squash_seq_num, unsigned tid); + + + inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid); + + protected: + unsigned instSize; + + bool pcValid[ThePipeline::MaxThreads]; + int pcBlockStage[ThePipeline::MaxThreads]; + + TheISA::IntReg PC[ThePipeline::MaxThreads]; + TheISA::IntReg nextPC[ThePipeline::MaxThreads]; + TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; + + /** Tracks delay slot information for threads in ISAs which use + * delay slots; + */ + struct DelaySlotInfo { + InstSeqNum delaySlotSeqNum; + InstSeqNum branchSeqNum; + int numInsts; + Addr targetAddr; + bool targetReady; + }; + + DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + InstSeqNum squashSeqNum[ThePipeline::MaxThreads]; + + /** Squash Seq. Nums*/ + Tick lastSquashCycle[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class FetchSeqEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + FetchSeqEvent(); + virtual ~FetchSeqEvent() {} + + /** Processes a resource event. */ + virtual void process(); + }; + +}; + +#endif diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc new file mode 100644 index 000000000..f4bbf3f5d --- /dev/null +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "cpu/inorder/resources/graduation_unit.hh" + +using namespace ThePipeline; + +GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + lastCycleGrad = 0; + numCycleGrad = 0; + + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + } +} + +void +GraduationUnit::execute(int slot_num) +{ + ResourceRequest* grad_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid, seq_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + int stage_num = inst->resSched.top()->stageNum; + + grad_req->fault = NoFault; + + switch (grad_req->cmd) + { + case GraduateInst: + { + // @TODO: Instructions should never really get to this point since this should be handled + // through the request interface. Check to make sure this happens and delete this + // code. + if (lastCycleGrad != curTick) { + lastCycleGrad = curTick; + numCycleGrad = 0; + } else if (numCycleGrad > width) { + DPRINTF(Resource, "Graduation bandwidth reached for this cycle.\n"); + return; + } + + // Make sure this is the last thing on the resource schedule + assert(inst->resSched.size() == 1); + + DPRINTF(Resource, "[tid:%i] Graduating instruction [sn:%i].\n", + tid, seq_num); + + DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/); + + // Release Non-Speculative "Block" on instructions that could not execute + // because there was a non-speculative inst. active. + // @TODO: Fix this functionality. Probably too conservative. + if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = false; + DPRINTF(Resource, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n", + tid, seq_num); + } + + if (inst->traceData) { + inst->traceData->setStageCycle(stage_num, curTick); + } + + // Tell CPU that instruction is finished processing + cpu->instDone(inst, tid); + + //cpu->pipelineStage[stage_num]->toPrevStages-> + //stageInfo[stage_num][tid].doneSeqNum = inst->seqNum; + + grad_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} diff --git a/src/cpu/inorder/resources/graduation_unit.hh b/src/cpu/inorder/resources/graduation_unit.hh new file mode 100644 index 000000000..ad222b119 --- /dev/null +++ b/src/cpu/inorder/resources/graduation_unit.hh @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class GraduationUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + GraduateInst + }; + + public: + GraduationUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~GraduationUnit() {} + + virtual void execute(int slot_num); + + protected: + Tick lastCycleGrad; + int numCycleGrad; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc new file mode 100644 index 000000000..97924d2d3 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +void +InstBuffer::regStats() +{ + instsBypassed + .name(name() + ".instsBypassed") + .desc("Number of Instructions Bypassed."); + + Resource::regStats(); +} + +void +InstBuffer::execute(int slot_idx) +{ + ResReqPtr ib_req = reqMap[slot_idx]; + DynInstPtr inst = ib_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = ib_req->getStageNum(); + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case ScheduleOrBypass: + { + int next_stage = stage_num + 1; + int bypass_stage = stage_num + 2; + bool do_bypass = true; + + if (!instList.empty()) { + DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) { + DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n", + inst->seqNum, next_stage); + do_bypass = false; + } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) { + DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because there is no room in " + "stage %i incoming stage buffer.\n", inst->seqNum, next_stage); + do_bypass = false; + } + + if (!do_bypass) { // SCHEDULE USAGE OF BUFFER + DPRINTF(Resource, "Scheduling [sn:%i] for buffer insertion in stage %i\n", + inst->seqNum, next_stage); + + // Add to schedule: Insert into buffer in next stage + int stage_pri = ThePipeline::getNextPriority(inst, next_stage); + + inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id, + InstBuffer::InsertInst)); + + // Add to schedule: Remove from buffer in next next (bypass) stage + stage_pri = ThePipeline::getNextPriority(inst, bypass_stage); + + inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id, + InstBuffer::RemoveInst)); + } else { // BYPASS BUFFER & NEXT STAGE + DPRINTF(Resource, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n", + inst->seqNum, next_stage, bypass_stage); + inst->setNextStage(bypass_stage); + instsBypassed++; + } + + ib_req->done(); + } + break; + + case InsertInst: + { + bool inserted = false; + + if (instList.size() < width) { + DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + inserted = true; + } else { + DPRINTF(Resource, "[tid:%i]: Denying [sn:%i] request because " + "buffer is full.\n", tid, seq_num); + + + std::list::iterator list_it = instList.begin(); + std::list::iterator list_end = instList.end(); + + while (list_it != list_end) { + DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum); + list_it++; + } + } + + ib_req->done(inserted); + } + break; + + case RemoveInst: + { + DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list::iterator list_it = instList.begin(); + std::list::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop(unsigned tid) +{ + instList.pop_front(); +} + +ThePipeline::DynInstPtr +InstBuffer::top(unsigned tid) +{ + return instList.front(); +} + +void +InstBuffer::squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid) +{ + queue::iterator> remove_list; + list::iterator list_it = instList.begin(); + list::iterator list_end = instList.end(); + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->readTid() == tid && + (*list_it)->seqNum > squash_seq_num) { + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + DPRINTF(Resource, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n", + tid, (*remove_list.front())->seqNum); + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(inst, stage_num, squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh new file mode 100644 index 000000000..f4851e868 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer.hh @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr, + ScheduleOrBypass + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~InstBuffer() {} + + virtual void regStats(); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(unsigned tid); + + virtual DynInstPtr top(unsigned tid); + + virtual void squash(DynInstPtr inst, int stage_num, + InstSeqNum squash_seq_num, unsigned tid); + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list instList; + + public: + ///////////////////////////////////////////////////////////////// + // + // RESOURCE STATISTICS + // + ///////////////////////////////////////////////////////////////// + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar<> instsBypassed; + +}; + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc new file mode 100644 index 000000000..7e2c98837 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +InstBuffer::InstBuffer(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ } + +ResReqPtr +InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferEntry* ib_entry = dynamic_cast(inst->resSched.top()); + assert(ib_entry); + + return new InstBufferRequest(this, inst, stage_num, id, slot_num, + ib_entry->cmd); +} + +void +InstBuffer::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + InstBufferRequest* ib_req = dynamic_cast(reqMap[slot_idx]); + assert(ib_req); + + DynInstPtr inst = ib_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + ib_req->fault = NoFault; + + switch (ib_req->cmd) + { + case InsertInst: + { + DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + tid, seq_num); + insert(inst); + ib_req->done(); + } + break; + + case RemoveInst: + { + DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", + tid, seq_num); + remove(inst); + ib_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + + DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); +} + +void +InstBuffer::insert(DynInstPtr inst) +{ + instList.push_back(inst); +} + +void +InstBuffer::remove(DynInstPtr inst) +{ + std::list::iterator list_it = instList.begin(); + std::list::iterator list_end = instList.end(); + + while (list_it != list_end) { + if((*list_it) == inst) { + instList.erase(list_it); + break; + } + list_it++; + } +} + +void +InstBuffer::pop() +{ instList.pop_front(); } + +ThePipeline::DynInstPtr +InstBuffer::top() +{ return instList.front(); } + +void +InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid) +{ + list::iterator list_it = instList.begin(); + list::iterator list_end = instList.end(); + queue::iterator> remove_list; + + // Collect All Instructions to be Removed in Remove List + while (list_it != list_end) { + if((*list_it)->seqNum > squash_seq_num) { + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n", + tid, (*list_it)->seqNum); + (*list_it)->setSquashed(); + remove_list.push(list_it); + } + + list_it++; + } + + // Removed Instructions from InstList & Clear Remove List + while (!remove_list.empty()) { + instList.erase(remove_list.front()); + remove_list.pop(); + } + + Resource::squash(squash_seq_num, tid); +} diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh new file mode 100644 index 000000000..e374fa109 --- /dev/null +++ b/src/cpu/inorder/resources/inst_buffer_new.hh @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ +#define __CPU_INORDER_INST_BUFF_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class InstBuffer : public Resource { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + enum Command { + InsertInst, + InsertAddr, + RemoveInst, + RemoveAddr + }; + + public: + InstBuffer(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~InstBuffer() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num); + + virtual void execute(int slot_num); + + virtual void insert(DynInstPtr inst); + + virtual void remove(DynInstPtr inst); + + virtual void pop(); + + virtual DynInstPtr top(); + + virtual void squash(InstSeqNum squash_seq_num, unsigned tid); + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list instList; + + /** @todo: Add Resource Stats Here */ + +}; + +struct InstBufferEntry : public ThePipeline::ScheduleEntry { + InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) : + ScheduleEntry(stage_num, res_num), cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + +class InstBufferRequest : public ResourceRequest { + public: + typedef InOrderDynInst::DynInstPtr DynInstPtr; + + public: + InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + InstBuffer::Command _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num), + cmd(_cmd) + { } + + InstBuffer::Command cmd; +}; + + +#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mem_dep_unit.hh b/src/cpu/inorder/resources/mem_dep_unit.hh new file mode 100644 index 000000000..0bd850c5c --- /dev/null +++ b/src/cpu/inorder/resources/mem_dep_unit.hh @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_GRAD_UNIT_HH__ +#define __CPU_INORDER_GRAD_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class MemDepUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + MemDepUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu); + virtual ~MemDepUnit() {} + + virtual void execute(int slot_num); + + protected: + Tick lastCycleGrad; + int numCycleGrad; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ +}; + +#endif //__CPU_INORDER_GRAD_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc new file mode 100644 index 000000000..abef11247 --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "cpu/inorder/resources/mult_div_unit.hh" +#include "cpu/inorder/resource_pool.hh" +#include "cpu/inorder/cpu.hh" +#include "cpu/op_class.hh" + +using namespace std; +using namespace ThePipeline; + +MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu) +{ + multRepeatRate = params->multRepeatRate; + multLatency = params->multLatency; + + div8RepeatRate = params->div8RepeatRate; + div8Latency = params->div8Latency; + + div16RepeatRate = params->div16RepeatRate; + div16Latency = params->div16Latency; + + div24RepeatRate = params->div24RepeatRate; + div24Latency = params->div24Latency; + + div32RepeatRate = params->div32RepeatRate; + div32Latency = params->div32Latency; +} + +void +MultDivUnit::regStats() +{ + multInstReqsProcessed + .name(name() + ".multInstReqsProcessed") + .desc("Number of Multiply Requests Processed."); + + divInstReqsProcessed + .name(name() + ".divInstReqsProcessed") + .desc("Number of Divide Requests Processed."); + + Resource::regStats(); +} + +void +MultDivUnit::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new MDUEvent[width]; + + initSlots(); +} + +int +MultDivUnit::findSlot(DynInstPtr inst) +{ + DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + inst->seqNum, slotsAvail(), slotsInUse()); + + return Resource::findSlot(inst); +} + +void +MultDivUnit::freeSlot(int slot_idx) +{ + DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n", + reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse()); + + Resource::freeSlot(slot_idx); +} + + +int +MultDivUnit::getSlot(DynInstPtr inst) +{ + // If MDU already has instruction, return current slot. + int slot_num = findSlot(inst); + + // If we have this instruction's request already then return + if (slot_num != -1 && + inst->resSched.top()->cmd == reqMap[slot_num]->cmd) + return slot_num; + + unsigned repeat_rate = 0; + + /** Enforce MDU dependencies after a multiply is seen last */ + if (lastOpType == IntMultOp) { + repeat_rate = multRepeatRate; + } + + /** Enforce dependencies after a divide is seen last */ + if (lastOpType == IntDivOp) { + switch (lastDivSize) { + case 8: + repeat_rate = div8RepeatRate; + break; + + case 16: + repeat_rate = div16RepeatRate; + break; + + case 24: + repeat_rate = div24RepeatRate; + break; + + case 32: + repeat_rate = div32RepeatRate; + break; + } + } + + if (lastMDUCycle + repeat_rate > curTick) { + DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n", + lastMDUCycle + repeat_rate); + return -1; + } else { + int rval = Resource::getSlot(inst); + DPRINTF(InOrderMDU, "MDU request should pass: %i.\n", + rval); + + if (rval != -1) { + } + + return rval; + } +} + +int +MultDivUnit::getDivOpSize(DynInstPtr inst) +{ + // Get RT Register from instruction (index #1) + uint32_t div_op = inst->readIntSrc(1); + + if (div_op <= 0xFF) { + return 8; + } else if (div_op <= 0xFFFF) { + return 16; + } else if (div_op <= 0xFFFFFF) { + return 24; + } else { + return 32; + } +} + +void +MultDivUnit::execute(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + + //int tid = inst->readTid(); + //int seq_num = inst->seqNum; + + switch (mult_div_req->cmd) + { + case StartMultDiv: + DPRINTF(InOrderMDU, "Start MDU called ...\n"); + + if (inst->opClass() == IntMultOp) { + scheduleEvent(slot_num, multLatency); + multInstReqsProcessed++; + } else if (inst->opClass() == IntDivOp) { + int op_size = getDivOpSize(inst); + + switch (op_size) + { + case 8: + scheduleEvent(slot_num, div8Latency); + break; + + case 16: + scheduleEvent(slot_num, div16Latency); + break; + + case 24: + scheduleEvent(slot_num, div24Latency); + break; + + case 32: + scheduleEvent(slot_num, div32Latency); + break; + } + + lastDivSize = op_size; + + divInstReqsProcessed++; + } + + // Allow to pass through to next stage while + // event processes + mult_div_req->setCompleted(); + break; + + case MultDiv: + DPRINTF(InOrderMDU, "Execute MDU called ...\n"); + exeMulDiv(slot_num); + mult_div_req->done(); + break; + + + case EndMultDiv: + //@TODO: Why not allow high-latency requests to sleep + // within stage until event wakes up???? + // Seems wasteful to continually check to see if + // this is done when we have a event in parallel + // counting down the time + { + DPRINTF(InOrderMDU, "End MDU called ...\n"); + if (mult_div_req->getInst()->isExecuted()) + mult_div_req->done(); + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +void +MultDivUnit::exeMulDiv(int slot_num) +{ + ResourceRequest* mult_div_req = reqMap[slot_num]; + DynInstPtr inst = reqMap[slot_num]->inst; + Fault fault = reqMap[slot_num]->fault; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + + fault = inst->execute(); + + if (fault == NoFault) { + inst->setExecuted(); + mult_div_req->setCompleted(); + + DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", + inst->readTid(), inst->readIntResult(0)); + } else { + warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); + cpu->trap(fault, tid); + } +} + + +MDUEvent::MDUEvent() + : ResourceEvent() +{ } + +void +MDUEvent::process() +{ + MultDivUnit* mdu_res = reinterpret_cast(resource); + + mdu_res->exeMulDiv(slotIdx); + + ResourceRequest* mult_div_req = resource->reqMap[slotIdx]; + + mult_div_req->done(); +} + + diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh new file mode 100644 index 000000000..762442c4b --- /dev/null +++ b/src/cpu/inorder/resources/mult_div_unit.hh @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_MULT_DIV_UNIT_HH__ +#define __CPU_INORDER_MULT_DIV_UNIT_HH__ + +#include +#include +#include + +#include "cpu/func_unit.hh" +#include "cpu/op_class.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" + +class MDUEvent; + +class MultDivUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + StartMultDiv, + EndMultDiv, + MultDiv + }; + + public: + MultDivUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~MultDivUnit() {} + + public: + /** Override default Resource getSlot(). Will only getSlot if + * valid mult/div sequence is being maintained + */ + virtual int getSlot(DynInstPtr inst); + + virtual int findSlot(DynInstPtr inst); + + virtual void freeSlot(int slot_idx); + + virtual void init(); + + /** Get Operand Size For A Division Operation */ + int getDivOpSize(DynInstPtr inst); + + /** Override default Resource execute */ + virtual void execute(int slot_num); + + void exeMulDiv(int slot_num); + + /** Register extra resource stats */ + virtual void regStats(); + + protected: + /** Latency & Repeat Rate for Multiply Insts */ + unsigned multLatency; + unsigned multRepeatRate; + + /** Latency & Repeat Rate for 8-bit Divide Insts */ + unsigned div8Latency; + unsigned div8RepeatRate; + + /** Latency & Repeat Rate for 16-bit Divide Insts */ + unsigned div16Latency; + unsigned div16RepeatRate; + + /** Latency & Repeat Rate for 24-bit Divide Insts */ + unsigned div24Latency; + unsigned div24RepeatRate; + + /** Latency & Repeat Rate for 32-bit Divide Insts */ + unsigned div32Latency; + unsigned div32RepeatRate; + + /** Last cycle that MDU was used */ + Tick lastMDUCycle; + + /** Last type of instruction MDU started processing */ + OpClass lastOpType; + + /** Last Division Operand of instruction MDU was processing */ + uint32_t lastDivSize; + + /** Last instruction name the MDU used */ + std::string lastInstName; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar<> multInstReqsProcessed; + + /** Number of Instruction Requests the Resource Processes */ + Stats::Scalar<> divInstReqsProcessed; + + MDUEvent *mduEvent; +}; + +class MDUEvent : public ResourceEvent +{ + public: + MDUEvent(); + virtual ~MDUEvent() { } + + + virtual void process(); +}; + + +#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__ diff --git a/src/cpu/inorder/resources/resource_list.hh b/src/cpu/inorder/resources/resource_list.hh new file mode 100644 index 000000000..cbe2ad8c3 --- /dev/null +++ b/src/cpu/inorder/resources/resource_list.hh @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef CPU_INORDER_RESOURCE_LIST_HH +#define CPU_INORDER_RESOURCE_LIST_HH + +#include "cpu/inorder/resources/cache_unit.hh" +#include "cpu/inorder/resources/execution_unit.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/resources/decode_unit.hh" +#include "cpu/inorder/resources/graduation_unit.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/resources/fetch_seq_unit.hh" +#include "cpu/inorder/resources/branch_predictor.hh" +#include "cpu/inorder/resources/agen_unit.hh" +#include "cpu/inorder/resources/mult_div_unit.hh" + +#endif diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc new file mode 100644 index 000000000..9b0decedb --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/tlb_unit.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +TLBUnit::TLBUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params) +{ + for (int i=0; i < MaxThreads; i++) { + tlbBlocked[i] = false; + } +} + +void +TLBUnit::init() +{ + resourceEvent = new TLBUnitEvent[width]; + + initSlots(); +} + +int +TLBUnit::getSlot(DynInstPtr inst) +{ + if (tlbBlocked[inst->threadNumber]) { + return -1; + } else { + return Resource::getSlot(inst); + } +} + +ResourceRequest* +TLBUnit::getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd) +{ + return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num, + cmd); +} + +void +TLBUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + TLBUnitRequest* tlb_req = dynamic_cast(reqMap[slot_idx]); + assert(tlb_req); + + DynInstPtr inst = tlb_req->inst; + int tid, seq_num, stage_num; + + tid = inst->readTid(); + seq_num = inst->seqNum; + stage_num = tlb_req->getStageNum(); + + tlb_req->fault = NoFault; + + switch (tlb_req->cmd) + { + case FetchLookup: + { + tlb_req->fault = + this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]); + + if (tlb_req->fault != NoFault) { + DPRINTF(Resource, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + case DataLookup: + { + DPRINTF(Resource, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n", + tid, seq_num, tlb_req->memReq->getVaddr()); + + tlb_req->fault = + this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]); + + if (tlb_req->fault != NoFault) { + DPRINTF(Resource, "[tid:%i]: %s encountered while translating " + "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), + tlb_req->memReq->getVaddr(), seq_num); + //insert(inst); + cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid); + tlbBlocked[tid] = true; + scheduleEvent(slot_idx, 1); + + // Let CPU handle the fault + cpu->trap(tlb_req->fault, tid); + } else { + DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated " + "to phys. addr:%08p.\n", tid, seq_num, + tlb_req->memReq->getVaddr(), + tlb_req->memReq->getPaddr()); + tlb_req->done(); + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } +} + +TLBUnitEvent::TLBUnitEvent() + : ResourceEvent() +{ } + +void +TLBUnitEvent::process() +{ + DynInstPtr inst = resource->reqMap[slotIdx]->inst; + int stage_num = resource->reqMap[slotIdx]->getStageNum(); + int tid = inst->threadNumber; + + DPRINTF(Resource, "Waking up from TLB Miss caused by [sn:%i].\n", + inst->seqNum); + + TLBUnit* tlb_res = dynamic_cast(resource); + assert(tlb_res); + + tlb_res->tlbBlocked[tid] = false; + + tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid); + + // Effectively NOP the instruction but still allow it + // to commit + //while (!inst->resSched.empty() && + // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) { + //inst->resSched.pop(); + //} +} diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh new file mode 100644 index 000000000..c7fee6030 --- /dev/null +++ b/src/cpu/inorder/resources/tlb_unit.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_TLB_UNIT_HH__ +#define __CPU_INORDER_TLB_UNIT_HH__ + +#include +#include +#include + +#include "cpu/inorder/resources/inst_buffer.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/cpu.hh" + +class TLBUnit : public InstBuffer { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum TLBCommand { + FetchLookup, + DataLookup + }; + + public: + TLBUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~TLBUnit() {} + + void init(); + + int getSlot(DynInstPtr inst); + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual void execute(int slot_num); + + bool tlbBlocked[ThePipeline::MaxThreads]; + + protected: + /** List of instructions this resource is currently + * processing. + */ + std::list instList; + + /** @todo: Add Resource Stats Here */ + +}; + +class TLBUnitEvent : public ResourceEvent { + public: + /** Constructs a resource event. */ + TLBUnitEvent(); + virtual ~TLBUnitEvent() {} + + /** Processes a resource event. */ + virtual void process(); +}; + +class TLBUnitRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, + unsigned _cmd) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd) + { + Addr aligned_addr; + int req_size; + unsigned flags; + + if (_cmd == TLBUnit::FetchLookup) { + aligned_addr = inst->getMemAddr(); + req_size = sizeof(MachInst); + flags = 0; + } else { + aligned_addr = inst->getMemAddr();; + req_size = inst->getMemAccSize(); + flags = inst->getMemFlags(); + } + + // @TODO: Add Vaddr & Paddr functions + inst->memReq = new Request(inst->readTid(), aligned_addr, req_size, + flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid()); + + memReq = inst->memReq; + } + + RequestPtr memReq; +}; + + +#endif //__CPU_INORDER_TLB_UNIT_HH__ diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc new file mode 100644 index 000000000..ed697c4ca --- /dev/null +++ b/src/cpu/inorder/resources/use_def.cc @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include +#include +#include "arch/isa_traits.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/resources/use_def.hh" +#include "cpu/inorder/cpu.hh" + +using namespace std; +using namespace TheISA; +using namespace ThePipeline; + +UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + maxSeqNum((InstSeqNum)-1) +{ + for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { + nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; + nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; + + outReadSeqNum[tid] = maxSeqNum; + outWriteSeqNum[tid] = maxSeqNum; + + regDepMap[tid] = &cpu->archRegDepMap[tid]; + } +} + +ResReqPtr +UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd, + inst->resSched.top()->idx); +} + + +ResReqPtr +UseDefUnit::findRequest(DynInstPtr inst) +{ + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + UseDefRequest* ud_req = dynamic_cast((*map_it).second); + assert(ud_req); + + if (ud_req && + ud_req->getInst() == inst && + ud_req->cmd == inst->resSched.top()->cmd && + ud_req->useDefIdx == inst->resSched.top()->idx) { + return ud_req; + } + map_it++; + } + + return NULL; +} + +void +UseDefUnit::execute(int slot_idx) +{ + // After this is working, change this to a reinterpret cast + // for performance considerations + UseDefRequest* ud_req = dynamic_cast(reqMap[slot_idx]); + assert(ud_req); + + DynInstPtr inst = ud_req->inst; + int tid = inst->readTid(); + int seq_num = inst->seqNum; + int ud_idx = ud_req->useDefIdx; + + // If there is a non-speculative instruction + // in the pipeline then stall instructions here + if (*nonSpecInstActive[tid] == true && + seq_num > *nonSpecSeqNum[tid]) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] cannot execute because there is " + "non-speculative instruction [sn:%i] has not graduated.\n", + tid, seq_num, *nonSpecSeqNum[tid]); + return; + } else if (inst->isNonSpeculative()) { + *nonSpecInstActive[tid] = true; + *nonSpecSeqNum[tid] = seq_num; + } + + switch (ud_req->cmd) + { + case ReadSrcReg: + { + int reg_idx = inst->_srcRegIdx[ud_idx]; + + DPRINTF(Resource, "[tid:%i]: Attempting to read source register idx %i.\n", + tid, ud_idx); + + // Ask register dependency map if it is OK to read from Arch. Reg. File + if (regDepMap[tid]->canRead(reg_idx, inst)) { + // Read From Register File + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(Resource, "[tid:%i]: Reading Int Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readIntReg(reg_idx,inst->readTid())); + } else if (reg_idx <= Ctrl_Base_DepTag) { + reg_idx -= FP_Base_DepTag; + DPRINTF(Resource, "[tid:%i]: Reading Float Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now + cpu->readFloatRegBits(reg_idx, inst->readTid())); + } else { + reg_idx -= Ctrl_Base_DepTag; + DPRINTF(Resource, "[tid:%i]: Reading Misc Reg %i from Register File.\n", + tid, reg_idx); + inst->setIntSrc(ud_idx, + cpu->readMiscReg(reg_idx, inst->readTid())); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n", + tid, outReadSeqNum[tid]); + } + + } else { + DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst); + + if (forward_inst) { + + if (inst->seqNum <= outReadSeqNum[tid]) { + int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx); + + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } else if (reg_idx <= Ctrl_Base_DepTag) { + DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readFloatResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx)); + } else { + DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + "[sn:%i] to [sn:%i] source #%i.\n", + tid, forward_inst->readIntResult(dest_reg_idx) , + forward_inst->seqNum, inst->seqNum, ud_idx); + inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); + } + + outReadSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum[tid]); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n", + tid, outReadSeqNum[tid]); + } + } else { + DPRINTF(Resource, "[tid:%i]: Source register idx: %i is not ready to read.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n", + tid, reg_idx); + outReadSeqNum[tid] = inst->seqNum; + } + } + } + break; + + case WriteDestReg: + { + int reg_idx = inst->_destRegIdx[ud_idx]; + + if (regDepMap[tid]->canWrite(reg_idx, inst)) { + DPRINTF(Resource, "[tid:%i]: Attempting to write to Register File.\n", + tid); + + if (inst->seqNum <= outReadSeqNum[tid]) { + if (reg_idx <= FP_Base_DepTag) { + DPRINTF(Resource, "[tid:%i]: Writing 0x%x to register idx %i.\n", + tid, inst->readIntResult(ud_idx), reg_idx); + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + cpu->setIntReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } else if(reg_idx <= Ctrl_Base_DepTag) { + + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= FP_Base_DepTag; + + cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here + inst->readFloatResult(ud_idx), + inst->readTid()); + } else { + // Remove Dependencies + regDepMap[tid]->removeFront(reg_idx, inst); + + reg_idx -= Ctrl_Base_DepTag; + cpu->setMiscReg(reg_idx, + inst->readIntResult(ud_idx), + inst->readTid()); + } + + outWriteSeqNum[tid] = maxSeqNum; + + ud_req->done(); + } else { + DPRINTF(Resource, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's" + " registers yet.\n", tid, outReadSeqNum); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n", + tid, outReadSeqNum); + } + } else { + DPRINTF(Resource, "[tid:%i]: Dest. register idx: %i is not ready to write.\n", + tid, reg_idx); + DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n", + tid, reg_idx); + outWriteSeqNum[tid] = inst->seqNum; + } + } + break; + + default: + fatal("Unrecognized command to %s", resName); + } + +} + +void +UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + DPRINTF(Resource, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", + tid, squash_seq_num); + + std::vector slot_remove_list; + + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + regDepMap[tid]->remove(req_ptr->getInst()); + + int req_slot_num = req_ptr->getSlot(); + + if (latency > 0) + unscheduleEvent(req_slot_num); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } + + if (outReadSeqNum[tid] >= squash_seq_num) { + DPRINTF(Resource, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid); + outReadSeqNum[tid] = maxSeqNum; + } else if (outReadSeqNum[tid] != maxSeqNum) { + DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n", + tid, outReadSeqNum[tid]); + } + + if (outWriteSeqNum[tid] >= squash_seq_num) { + DPRINTF(Resource, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid); + outWriteSeqNum[tid] = maxSeqNum; + } else if (outWriteSeqNum[tid] != maxSeqNum) { + DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n", + tid, outWriteSeqNum[tid]); + } +} diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh new file mode 100644 index 000000000..238591117 --- /dev/null +++ b/src/cpu/inorder/resources/use_def.hh @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_USE_DEF_UNIT_HH__ +#define __CPU_INORDER_USE_DEF_UNIT_HH__ + +#include +#include +#include + +#include "cpu/func_unit.hh" +#include "cpu/inorder/first_stage.hh" +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/inorder_dyn_inst.hh" +#include "cpu/inorder/pipeline_traits.hh" +#include "cpu/inorder/reg_dep_map.hh" + +class UseDefUnit : public Resource { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + enum Command { + ReadSrcReg, + WriteDestReg + }; + + public: + UseDefUnit(std::string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~UseDefUnit() {} + + virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, + unsigned cmd); + + virtual ResReqPtr findRequest(DynInstPtr inst); + + virtual void execute(int slot_num); + + virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); + + const InstSeqNum maxSeqNum; + + protected: + RegDepMap *regDepMap[ThePipeline::MaxThreads]; + + /** Outstanding Seq. Num. Trying to Read from Register File */ + InstSeqNum outReadSeqNum[ThePipeline::MaxThreads]; + + InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads]; + + bool *nonSpecInstActive[ThePipeline::MaxThreads]; + + InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; + + /** @todo: Add Resource Stats Here */ + + public: + class UseDefRequest : public ResourceRequest { + public: + typedef ThePipeline::DynInstPtr DynInstPtr; + + public: + UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd, int use_def_idx) + : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd), + useDefIdx(use_def_idx) + { } + + int useDefIdx; + }; +}; + +#endif //__CPU_INORDER_USE_DEF_UNIT_HH__ diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc new file mode 100644 index 000000000..5e2c789cb --- /dev/null +++ b/src/cpu/inorder/thread_context.cc @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#include "arch/isa_traits.hh" +#include "cpu/exetrace.hh" +#include "cpu/inorder/thread_context.hh" + +using namespace TheISA; + +void +InOrderThreadContext::takeOverFrom(ThreadContext *old_context) +{ + // some things should already be set up + assert(getProcessPtr() == old_context->getProcessPtr()); + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + //setCpuId(0/*old_context->readCpuId()*/); + + thread->funcExeInst = old_context->readFuncExeInst(); + old_context->setStatus(ThreadContext::Unallocated); + thread->inSyscall = false; + thread->trapPending = false; +} + +void +InOrderThreadContext::activate(int delay) +{ + DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Active) + return; + + // @TODO: Make this process useful again... + //if (thread->status() == ThreadContext::Unallocated) { + // Allows the CPU to drain partitioned resources + // before inserting thread into the CPU + // (e.g. bind physical registers) + //cpu->activateWhenReady(thread->readTid()); + //return; + //} + + thread->setStatus(ThreadContext::Active); + + // status() == Suspended + cpu->activateContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::suspend(int delay) +{ + DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Suspended) + return; + + thread->setStatus(ThreadContext::Suspended); + cpu->suspendContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::deallocate(int delay) +{ + DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Unallocated) + return; + + thread->setStatus(ThreadContext::Unallocated); + cpu->deallocateContext(thread->readTid(), delay); +} + +void +InOrderThreadContext::halt(int delay) +{ + DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n", + getThreadNum()); + + if (thread->status() == ThreadContext::Halted) + return; + + thread->setStatus(ThreadContext::Halted); + cpu->haltContext(thread->readTid(), delay); +} + + +void +InOrderThreadContext::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif + ; +} + + +void +InOrderThreadContext::serialize(std::ostream &os) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->serialize(os); +#endif + ; +} + + +void +InOrderThreadContext::unserialize(Checkpoint *cp, const std::string §ion) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->unserialize(cp, section); +#endif + ; +} + +TheISA::MachInst +InOrderThreadContext:: getInst() +{ + return thread->getInst(); +} + + +void +InOrderThreadContext::copyArchRegs(ThreadContext *tc) +{ + unsigned tid = thread->readTid(); + PhysRegIndex renamed_reg; + + // First loop through the integer registers. + for (int i = 0; i < TheISA::NumIntRegs; ++i) { + renamed_reg = cpu->renameMap[tid].lookup(i); + + DPRINTF(InOrderCPU, "Copying over register %i, had data %lli, " + "now has data %lli.\n", + renamed_reg, cpu->readIntReg(renamed_reg, tid), + tc->readIntReg(i)); + + cpu->setIntReg(renamed_reg, tc->readIntReg(i), tid); + } + + // Then loop through the floating point registers. + for (int i = 0; i < TheISA::NumFloatRegs; ++i) { + renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag); + cpu->setFloatRegBits(renamed_reg, tc->readFloatRegBits(i), tid); + } + + // Copy the misc regs. + TheISA::copyMiscRegs(tc, this); + + // Then finally set the PC and the next PC. + cpu->setPC(tc->readPC(), tid); + cpu->setNextPC(tc->readNextPC(), tid); + cpu->setNextNPC(tc->readNextNPC(), tid); + this->thread->funcExeInst = tc->readFuncExeInst(); +} + + +void +InOrderThreadContext::clearArchRegs() +{} + + +uint64_t +InOrderThreadContext::readIntReg(int reg_idx) +{ + return cpu->readIntReg(reg_idx, thread->readTid()); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx, int width) +{ + return cpu->readFloatReg(reg_idx, thread->readTid(), width); +} + +FloatReg +InOrderThreadContext::readFloatReg(int reg_idx) +{ + return cpu->readFloatReg(reg_idx, thread->readTid()); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx, int width) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid(), width); +} + +FloatRegBits +InOrderThreadContext::readFloatRegBits(int reg_idx) +{ + return cpu->readFloatRegBits(reg_idx, thread->readTid()); +} + +uint64_t +InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid) +{ + return cpu->readRegOtherThread(reg_idx, tid); +} + +void +InOrderThreadContext::setIntReg(int reg_idx, uint64_t val) +{ + cpu->setIntReg(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + // cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid(), width); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val) +{ + cpu->setFloatReg(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, + int width) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + cpu->setFloatRegBits(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid) +{ + cpu->setRegOtherThread(misc_reg, val, tid); +} + +void +InOrderThreadContext::setPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting PC to %08p\n", val); + cpu->setPC(val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setNextPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val); + cpu->setNextPC(val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setNextNPC(uint64_t val) +{ + DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val); + cpu->setNextNPC(val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) +{ + cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +void +InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val) +{ + cpu->setMiscReg(misc_reg, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + //if (!thread->trapPending && !thread->inSyscall) { + //cpu->squashFromTC(thread->readTid()); + //} +} + +TheISA::IntReg +InOrderThreadContext::getSyscallArg(int i) +{ + return cpu->getSyscallArg(i, thread->readTid()); +} + +void +InOrderThreadContext::setSyscallArg(int i, IntReg val) +{ + cpu->setSyscallArg(i, val, thread->readTid()); +} + +void +InOrderThreadContext::setSyscallReturn(SyscallReturn return_value) +{ + cpu->setSyscallReturn(return_value, thread->readTid()); +} diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh new file mode 100644 index 000000000..919d5d2b6 --- /dev/null +++ b/src/cpu/inorder/thread_context.hh @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2007 MIPS Technologies, Inc. + * 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: Korey Sewell + * + */ + +#ifndef __CPU_INORDER_THREAD_CONTEXT_HH__ +#define __CPU_INORDER_THREAD_CONTEXT_HH__ + +#include "cpu/exetrace.hh" +#include "cpu/thread_context.hh" +#include "cpu/inorder/thread_state.hh" +#include "cpu/inorder/cpu.hh" + +class TranslatingPort; + +/** + * Derived ThreadContext class for use with the InOrderCPU. It + * provides the interface for any external objects to access a + * single thread's state and some general CPU state. Any time + * external objects try to update state through this interface, + * the CPU will create an event to squash all in-flight + * instructions in order to ensure state is maintained correctly. + * It must be defined specifically for the InOrderCPU because + * not all architectural state is located within the O3ThreadState + * (such as the commit PC, and registers), and specific actions + * must be taken when using this interface (such as squashing all + * in-flight instructions when doing a write to this interface). + */ +class InOrderThreadContext : public ThreadContext +{ + public: + InOrderThreadContext() { } + + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + /** Pointer to the thread state that this TC corrseponds to. */ + InOrderThreadState *thread; + + + /** Returns a pointer to the ITB. */ + TheISA::ITB *getITBPtr() { return cpu->itb; } + + /** Returns a pointer to the DTB. */ + TheISA::DTB *getDTBPtr() { return cpu->dtb; } + + System *getSystemPtr() { return cpu->system; } + + /** Returns a pointer to this CPU. */ + virtual BaseCPU *getCpuPtr() { return cpu; } + + /** Returns a pointer to this CPU. */ + virtual std::string getCpuName() { return cpu->name(); } + + /** Reads this CPU's ID. */ + virtual int cpuId() { return cpu->cpuId(); } + + virtual int contextId() { return thread->contextId(); } + + virtual void setContextId(int id) { thread->setContextId(id); } + + /** Returns this thread's ID number. */ + virtual int threadId() { return thread->threadId(); } + virtual void setThreadId(int id) { return thread->setThreadId(id); } + + virtual uint64_t readMicroPC() + { return 0; } + + virtual void setMicroPC(uint64_t val) { }; + + virtual uint64_t readNextMicroPC() + { return 0; } + + virtual void setNextMicroPC(uint64_t val) { }; + + virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } + + /** Returns a pointer to this thread's process. */ + virtual Process *getProcessPtr() { return thread->getProcessPtr(); } + + /** Returns this thread's status. */ + virtual Status status() const { return thread->status(); } + + /** Sets this thread's status. */ + virtual void setStatus(Status new_status) + { thread->setStatus(new_status); } + + /** Returns a pointer to the last graduated/committed instruction in the thread */ + //DynInstPtr getLastGradInst() { return thread->getLastGradInst(); } + + /** Set the status to Active. Optional delay indicates number of + * cycles to wait before beginning execution. */ + virtual void activate(int delay = 1); + + /** Set the status to Suspended. */ + virtual void suspend(int delay = 0); + + /** Set the status to Unallocated. */ + virtual void deallocate(int delay = 1); + + /** Set the status to Halted. */ + virtual void halt(int delay = 0); + + /** Takes over execution of a thread from another CPU. */ + virtual void takeOverFrom(ThreadContext *old_context); + + /** Registers statistics associated with this TC. */ + virtual void regStats(const std::string &name); + + /** Serializes state. */ + virtual void serialize(std::ostream &os); + /** Unserializes state. */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** Returns this thread's ID number. */ + virtual int getThreadNum() { return thread->readTid(); } + + /** Returns the instruction this thread is currently committing. + * Only used when an instruction faults. + */ + virtual TheISA::MachInst getInst(); + + /** Copies the architectural registers from another TC into this TC. */ + virtual void copyArchRegs(ThreadContext *tc); + + /** Resets all architectural registers to 0. */ + virtual void clearArchRegs(); + + /** Reads an integer register. */ + virtual uint64_t readIntReg(int reg_idx); + + virtual FloatReg readFloatReg(int reg_idx, int width); + + virtual FloatReg readFloatReg(int reg_idx); + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width); + + virtual FloatRegBits readFloatRegBits(int reg_idx); + + virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid); + + /** Sets an integer register to a value. */ + virtual void setIntReg(int reg_idx, uint64_t val); + + virtual void setFloatReg(int reg_idx, FloatReg val, int width); + + virtual void setFloatReg(int reg_idx, FloatReg val); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val); + + virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid); + + /** Reads this thread's PC. */ + virtual uint64_t readPC() + { return cpu->readPC(thread->readTid()); } + + /** Sets this thread's PC. */ + virtual void setPC(uint64_t val); + + /** Reads this thread's next PC. */ + virtual uint64_t readNextPC() + { return cpu->readNextPC(thread->readTid()); } + + /** Sets this thread's next PC. */ + virtual void setNextPC(uint64_t val); + + virtual uint64_t readNextNPC() + { return cpu->readNextNPC(thread->readTid()); } + + virtual void setNextNPC(uint64_t val); + + /** Reads a miscellaneous register. */ + virtual MiscReg readMiscRegNoEffect(int misc_reg) + { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); } + + /** Reads a misc. register, including any side-effects the + * read might have as defined by the architecture. */ + virtual MiscReg readMiscReg(int misc_reg) + { return cpu->readMiscReg(misc_reg, thread->readTid()); } + + /** Sets a misc. register. */ + virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val); + + /** Sets a misc. register, including any side-effects the + * write might have as defined by the architecture. */ + virtual void setMiscReg(int misc_reg, const MiscReg &val); + + virtual void activateContext(int delay) + { cpu->activateContext(thread->readTid(), delay); } + + virtual void deallocateContext() + { cpu->deallocateContext(thread->readTid()); } + + /** Returns the number of consecutive store conditional failures. */ + // @todo: Figure out where these store cond failures should go. + virtual unsigned readStCondFailures() + { return thread->storeCondFailures; } + + /** Sets the number of consecutive store conditional failures. */ + virtual void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + + // Only really makes sense for old CPU model. Lots of code + // outside the CPU still checks this function, so it will + // always return false to keep everything working. + /** Checks if the thread is misspeculating. Because it is + * very difficult to determine if the thread is + * misspeculating, this is set as false. */ + virtual bool misspeculating() { return false; } + + /** Gets a syscall argument by index. */ + virtual IntReg getSyscallArg(int i); + + /** Sets a syscall argument. */ + virtual void setSyscallArg(int i, IntReg val); + + /** Sets the syscall return value. */ + virtual void setSyscallReturn(SyscallReturn return_value); + + /** Executes a syscall in SE mode. */ + virtual void syscall(int64_t callnum) + { return cpu->syscall(callnum, thread->readTid()); } + + /** Reads the funcExeInst counter. */ + virtual Counter readFuncExeInst() { return thread->funcExeInst; } + + virtual void changeRegFileContext(unsigned param, + unsigned val) + { panic("Not supported!"); } + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system (for now + // this single cpu) + if (this->cpu->numActiveThreads() - 1 > 0) + return 0; // don't exit simulation + else + return 1; // exit simulation + } + + virtual void setThreadRescheduleCondition(uint64_t cond) + { + this->deallocate(); + + this->setStatus(ThreadContext::Suspended); + + activateContext(cond); + } +}; + +#endif diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh new file mode 100644 index 000000000..eb4fe40b2 --- /dev/null +++ b/src/cpu/inorder/thread_state.hh @@ -0,0 +1,90 @@ +/* + * 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: Kevin Lim + */ + +#ifndef __CPU_INORDER_THREAD_STATE_HH__ +#define __CPU_INORDER_THREAD_STATE_HH__ + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" + +class Event; +class FunctionalMemory; +class Process; +class InOrderCPU; + +/** + * Class that has various thread state, such as the status, the + * current instruction being processed, whether or not the thread has + * a trap pending or is being externally updated, the ThreadContext + * pointer, etc. It also handles anything related to a specific + * thread's process, such as syscalls and checking valid addresses. + */ +class InOrderThreadState : public ThreadState { + typedef ThreadContext::Status Status; + + private: + /** Pointer to the CPU. */ + InOrderCPU *cpu; + + public: + /** Whether or not the thread is currently in syscall mode, and + * thus able to be externally updated without squashing. + */ + bool inSyscall; + + /** Whether or not the thread is currently waiting on a trap, and + * thus able to be externally updated without squashing. + */ + bool trapPending; + + + InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid) + : ThreadState(reinterpret_cast(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/), + cpu(_cpu), inSyscall(0), trapPending(0) + { } + + /** Handles the syscall. */ + void syscall(int64_t callnum) { process->syscall(callnum, tc); } + + /** Pointer to the ThreadContext of this thread. */ + ThreadContext *tc; + + /** Returns a pointer to the TC of this thread. */ + ThreadContext *getTC() { return tc; } + + int readTid() { return 0; } + + /** Pointer to the last graduated instruction in the thread */ + //DynInstPtr lastGradInst; +}; + +#endif // __CPU_INORDER_THREAD_STATE_HH__ -- cgit v1.2.3 From cf4a00ca410226d3fd1b4db816938b7ddf78a333 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Tue, 10 Feb 2009 15:49:29 -0800 Subject: Configs: Add support for the InOrder CPU model --- src/cpu/inorder/cpu.hh | 15 +- src/cpu/inorder/inorder_dyn_inst.cc | 10 +- src/cpu/inorder/resources/cache_unit.cc | 254 ++++++++++++++++---------------- src/cpu/inorder/resources/cache_unit.hh | 42 ++++-- 4 files changed, 169 insertions(+), 152 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index cd1eb6f92..34eabbad4 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -312,6 +312,13 @@ class InOrderCPU : public BaseCPU void deallocateThread(unsigned tid); void deactivateThread(unsigned tid); + int + contextId() + { + hack_once("return a bogus context id"); + return 0; + } + /** Remove Thread from Active Threads List && * Remove Thread Context from CPU. */ @@ -414,20 +421,20 @@ class InOrderCPU : public BaseCPU int width = TheISA::SingleWidth); /** Reads a miscellaneous register. */ - MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid); + MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0); /** Reads a misc. register, including any side effects the read * might have as defined by the architecture. */ - MiscReg readMiscReg(int misc_reg, unsigned tid); + MiscReg readMiscReg(int misc_reg, unsigned tid = 0); /** Sets a miscellaneous register. */ - void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid); + void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0); /** Sets a misc. register, including any side effects the write * might have as defined by the architecture. */ - void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0); /** Reads a int/fp/misc reg. from another thread depending on ISA-defined * target thread diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index 89362c656..3a45bd01e 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -454,9 +454,8 @@ InOrderDynInst::readMiscRegNoEffect(int misc_reg) MiscReg InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx) { - return this->cpu->readMiscRegNoEffect( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return cpu->readMiscRegNoEffect(reg, this->threadNumber); } /** Reads a misc. register, including any side-effects the read @@ -465,9 +464,8 @@ InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx) MiscReg InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx) { - return this->cpu->readMiscReg( - si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag, - this->threadNumber); + int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return this->cpu->readMiscReg(reg, this->threadNumber); } /** Sets a misc. register. */ diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 79ca7a096..6b62c864a 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -43,7 +43,6 @@ using namespace std; using namespace TheISA; using namespace ThePipeline; - Tick CacheUnit::CachePort::recvAtomic(PacketPtr pkt) { @@ -80,7 +79,7 @@ CacheUnit::CachePort::recvRetry() } CacheUnit::CacheUnit(string res_name, int res_id, int res_width, - int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) + int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), retryPkt(NULL), retrySlot(-1) { @@ -92,9 +91,8 @@ CacheUnit::CacheUnit(string res_name, int res_id, int res_width, cacheBlocked = false; } - Port * -CacheUnit::getPort(const std::string &if_name, int idx) +CacheUnit::getPort(const string &if_name, int idx) { if (if_name == resName) return cachePort; @@ -106,7 +104,7 @@ int CacheUnit::getSlot(DynInstPtr inst) { if (!inst->validMemAddr()) { - panic("Mem. Addr. must be set before requesting cache access.\n"); + panic("Mem. Addr. must be set before requesting cache access\n"); } Addr req_addr = inst->getMemAddr(); @@ -116,20 +114,19 @@ CacheUnit::getSlot(DynInstPtr inst) int new_slot = Resource::getSlot(inst); - if (new_slot != -1) { - inst->memTime = curTick; - addrList.push_back(req_addr); - addrMap[req_addr] = inst->seqNum; - DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Address %08p added to dependency list.\n", - inst->readTid(), inst->seqNum, req_addr); - return new_slot; - } else { + if (new_slot == -1) return -1; - } - + inst->memTime = curTick; + addrList.push_back(req_addr); + addrMap[req_addr] = inst->seqNum; + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n", + inst->readTid(), inst->seqNum, req_addr); + return new_slot; } else { - DPRINTF(InOrderCachePort,"Denying request because there is an outstanding" + DPRINTF(InOrderCachePort, + "Denying request because there is an outstanding" " request to/for addr. %08p. by [sn:%i] @ tick %i\n", req_addr, addrMap[req_addr], inst->memTime); return -1; @@ -139,11 +136,12 @@ CacheUnit::getSlot(DynInstPtr inst) void CacheUnit::freeSlot(int slot_num) { - std::vector::iterator vect_it = find(addrList.begin(), addrList.end(), - reqMap[slot_num]->inst->getMemAddr()); + vector::iterator vect_it = find(addrList.begin(), addrList.end(), + reqMap[slot_num]->inst->getMemAddr()); assert(vect_it != addrList.end()); - DPRINTF(InOrderCachePort, "[tid:%i]: Address %08p removed from dependency list.\n", + DPRINTF(InOrderCachePort, + "[tid:%i]: Address %08p removed from dependency list\n", reqMap[slot_num]->inst->readTid(), (*vect_it)); addrList.erase(vect_it); @@ -158,7 +156,7 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, ScheduleEntry* sched_entry = inst->resSched.top(); if (!inst->validMemAddr()) { - panic("Mem. Addr. must be set before requesting cache access.\n"); + panic("Mem. Addr. must be set before requesting cache access\n"); } int req_size = 0; @@ -168,23 +166,26 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, pkt_cmd = MemCmd::ReadReq; req_size = inst->getMemAccSize(); - DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p.\n", + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p\n", inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); } else if (sched_entry->cmd == InitiateWriteData) { pkt_cmd = MemCmd::WriteReq; req_size = inst->getMemAccSize(); - - DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p.\n", + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p\n", inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); } else if (sched_entry->cmd == InitiateFetch){ pkt_cmd = MemCmd::ReadReq; req_size = sizeof(MachInst); //@TODO: mips16e - DPRINTF(InOrderCachePort, "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p.\n", + DPRINTF(InOrderCachePort, + "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p\n", inst->readTid(), req_size, inst->seqNum, inst->getMemAddr()); } else { - panic("%i: Unexpected request type (%i) to %s", curTick, sched_entry->cmd, name()); + panic("%i: Unexpected request type (%i) to %s", curTick, + sched_entry->cmd, name()); } return new CacheRequest(this, inst, stage_num, id, slot_num, @@ -205,26 +206,27 @@ CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) if (cache_req->cmd != inst->resSched.top()->cmd) { // If different, then update command in the request cache_req->cmd = inst->resSched.top()->cmd; - DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this " - "instruction.\n", inst->readTid(), inst->seqNum); + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: the command for this instruction\n", + inst->readTid(), inst->seqNum); service_request = true; } else { // If same command, just check to see if memory access was completed // but dont try to re-execute - DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: requesting this resource again.\n", + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: requesting this resource again\n", inst->readTid(), inst->seqNum); service_request = true; } - } void CacheUnit::execute(int slot_num) { if (cacheBlocked) { - DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access.\n"); + DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access\n"); return; } @@ -243,89 +245,85 @@ CacheUnit::execute(int slot_num) switch (cache_req->cmd) { case InitiateFetch: - { - DPRINTF(InOrderCachePort, - "[tid:%u]: Initiating fetch access to %s for addr. %08p\n", - tid, name(), cache_req->inst->getMemAddr()); + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating fetch access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); - DPRINTF(InOrderCachePort, - "[tid:%u]: Fetching new cache block from addr: %08p\n", - tid, cache_req->memReq->getVaddr()); + DPRINTF(InOrderCachePort, + "[tid:%u]: Fetching new cache block from addr: %08p\n", + tid, cache_req->memReq->getVaddr()); - inst->setCurResSlot(slot_num); - doDataAccess(inst); - } + inst->setCurResSlot(slot_num); + doDataAccess(inst); break; case CompleteFetch: - { - if (cache_req->isMemAccComplete()) { - DPRINTF(InOrderCachePort, - "[tid:%i]: Completing Fetch Access for [sn:%i]\n", - tid, inst->seqNum); + if (cache_req->isMemAccComplete()) { + DPRINTF(InOrderCachePort, + "[tid:%i]: Completing Fetch Access for [sn:%i]\n", + tid, inst->seqNum); - MachInst mach_inst = cache_req->dataPkt->get(); + MachInst mach_inst = cache_req->dataPkt->get(); - //@TODO: May Need This Function for Endianness-Compatibility - //mach_inst = gtoh(*reinterpret_cast(&cacheData[tid][offset])); + /** + * @TODO: May Need This Function for Endianness-Compatibility + * mach_inst = + * gtoh(*reinterpret_cast(&cacheData[tid][offset])); + */ - DPRINTF(InOrderCachePort, - "[tid:%i]: Fetched instruction is %08p\n", - tid, mach_inst); + DPRINTF(InOrderCachePort, + "[tid:%i]: Fetched instruction is %08p\n", + tid, mach_inst); - //ExtMachInst ext_inst - // = TheISA::makeExtMI(mach_inst, cpu->tcBase(tid)); + // ExtMachInst ext_inst = makeExtMI(mach_inst, cpu->tcBase(tid)); - inst->setMachInst(mach_inst); - inst->setASID(tid); - inst->setThreadState(cpu->thread[tid]); + inst->setMachInst(mach_inst); + inst->setASID(tid); + inst->setThreadState(cpu->thread[tid]); - DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n", - tid, seq_num, inst->staticInst->disassemble(inst->PC)); + DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n", + tid, seq_num, inst->staticInst->disassemble(inst->PC)); - // Set Up More TraceData info - if (inst->traceData) { - inst->traceData->setStaticInst(inst->staticInst); - inst->traceData->setPC(inst->readPC()); - } + // Set Up More TraceData info + if (inst->traceData) { + inst->traceData->setStaticInst(inst->staticInst); + inst->traceData->setPC(inst->readPC()); + } - cache_req->done(); - } else { - DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access.\n", + cache_req->done(); + } else { + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n", tid, inst->seqNum); - DPRINTF(InOrderStall, "STALL: [tid:%i]: Fetch miss from %08p.\n", - tid, cache_req->inst->readPC()); - cache_req->setCompleted(false); - } + DPRINTF(InOrderStall, + "STALL: [tid:%i]: Fetch miss from %08p\n", + tid, cache_req->inst->readPC()); + cache_req->setCompleted(false); } break; case InitiateReadData: case InitiateWriteData: - { - DPRINTF(InOrderCachePort, "[tid:%u]: Initiating data access to %s " - "for addr. %08p\n", - tid, name(), cache_req->inst->getMemAddr()); - - inst->setCurResSlot(slot_num); - //inst->memAccess(); - inst->initiateAcc(); - } + DPRINTF(InOrderCachePort, + "[tid:%u]: Initiating data access to %s for addr. %08p\n", + tid, name(), cache_req->inst->getMemAddr()); + + inst->setCurResSlot(slot_num); + //inst->memAccess(); + inst->initiateAcc(); break; case CompleteReadData: case CompleteWriteData: - { - DPRINTF(InOrderCachePort, - "[tid:%i]: [sn:%i]: Trying to Complete Data Access.\n", - tid, inst->seqNum); - if (cache_req->isMemAccComplete()) { - cache_req->done(); - } else { - DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", - tid, cache_req->inst->getMemAddr()); - cache_req->setCompleted(false); - } + DPRINTF(InOrderCachePort, + "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n", + tid, inst->seqNum); + if (cache_req->isMemAccComplete()) { + cache_req->done(); + } else { + DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n", + tid, cache_req->inst->getMemAddr()); + cache_req->setCompleted(false); } break; @@ -364,12 +362,13 @@ CacheUnit::doDataAccess(DynInstPtr inst) if (cache_req->dataPkt->isWrite() && memReq->isLocked()) { assert(cache_req->inst->isStoreConditional()); - DPRINTF(InOrderCachePort, "Evaluating Store Conditional access.\n"); + DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n"); do_access = TheISA::handleLockedWrite(cpu, memReq); } - - DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] attempting to access cache..\n", tid, inst->seqNum); + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] attempting to access cache\n", + tid, inst->seqNum); //@TODO: If you want to ignore failed store conditional accesses, then // enable this. However, this might skew memory stats because @@ -377,7 +376,9 @@ CacheUnit::doDataAccess(DynInstPtr inst) // - Remove optionality here ... if (1/*do_access*/) { if (!cachePort->sendTiming(cache_req->dataPkt)) { - DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is waiting to retry request.\n", tid, inst->seqNum); + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is waiting to retry request\n", + tid, inst->seqNum); retrySlot = cache_req->getSlot(); retryReq = cache_req; @@ -391,7 +392,9 @@ CacheUnit::doDataAccess(DynInstPtr inst) cache_req->setCompleted(false); } else { - DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] is now waiting for cache response.\n", tid, inst->seqNum); + DPRINTF(InOrderCachePort, + "[tid:%i] [sn:%i] is now waiting for cache response\n", + tid, inst->seqNum); cache_req->setCompleted(); cache_req->setMemAccPending(); cacheStatus = cacheWaitResponse; @@ -402,7 +405,8 @@ CacheUnit::doDataAccess(DynInstPtr inst) assert(cache_req->inst->isStoreConditional()); cache_req->setCompleted(true); - DPRINTF(LLSC, "[tid:%i]: T%i Ignoring Failed Store Conditional Access.\n", + DPRINTF(LLSC, + "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n", tid, tid); cache_req->dataPkt->req->setExtraData(0); @@ -431,20 +435,20 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) if (cache_pkt->cacheReq->isSquashed()) { DPRINTF(InOrderCachePort, - "Ignoring completion of squashed access, [tid:%i] [sn:%i].\n", + "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n", cache_pkt->cacheReq->getInst()->readTid(), cache_pkt->cacheReq->getInst()->seqNum); cache_pkt->cacheReq->done(); return; - } else { - DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p.\n", - cache_pkt->cacheReq->getInst()->readTid(), - cache_pkt->cacheReq->getInst()->seqNum, - cache_pkt->cacheReq->getInst()->getMemAddr()); } + DPRINTF(InOrderCachePort, + "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n", + cache_pkt->cacheReq->getInst()->readTid(), + cache_pkt->cacheReq->getInst()->seqNum, + cache_pkt->cacheReq->getInst()->getMemAddr()); + // Cast to correct request type CacheRequest *cache_req = dynamic_cast( findRequest(cache_pkt->cacheReq->getInst())); @@ -462,11 +466,11 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) if (!cache_req->isSquashed()) { if (inst->resSched.top()->cmd == CompleteFetch) { DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Processing fetch access.\n", + "[tid:%u]: [sn:%i]: Processing fetch access\n", tid, inst->seqNum); } else if (inst->staticInst && inst->isMemRef()) { DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Processing cache access.\n", + "[tid:%u]: [sn:%i]: Processing cache access\n", tid, inst->seqNum); inst->completeAcc(pkt); @@ -475,21 +479,22 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) assert(cache_pkt->isRead()); if (cache_pkt->req->isLocked()) { - DPRINTF(InOrderCachePort, "[tid:%u]: Handling Load-Linked " - "access for [sn:%u].\n", tid, inst->seqNum); + DPRINTF(InOrderCachePort, + "[tid:%u]: Handling Load-Linked for [sn:%u]\n", + tid, inst->seqNum); TheISA::handleLockedRead(cpu, cache_pkt->req); } // @TODO: Hardcoded to for load instructions. Assumes that // the dest. idx 0 is always where the data is loaded to. DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Data loaded was: %08p.\n", + "[tid:%u]: [sn:%i]: Data loaded was: %08p\n", tid, inst->seqNum, inst->readIntResult(0)); } else if(inst->isStore()) { assert(cache_pkt->isWrite()); DPRINTF(InOrderCachePort, - "[tid:%u]: [sn:%i]: Data stored was: %08p.\n", + "[tid:%u]: [sn:%i]: Data stored was: %08p\n", tid, inst->seqNum, getMemData(cache_pkt)); @@ -509,8 +514,8 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) cpu->switchToActive(stage_num); } else { DPRINTF(InOrderCachePort, - "[tid:%u] Cache miss on memory access to block @ %08p " - "completed, but squashed.\n", tid, cache_req->inst->readPC()); + "[tid:%u] Miss on block @ %08p completed, but squashed\n", + tid, cache_req->inst->readPC()); cache_req->setMemAccCompleted(); } @@ -520,7 +525,7 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) void CacheUnit::recvRetry() { - DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i].\n", + DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i]\n", retryReq->inst->readTid(), retryReq->inst->seqNum); assert(retryPkt != NULL); @@ -532,20 +537,20 @@ CacheUnit::recvRetry() retryPkt = NULL; cacheBlocked = false; } else { - DPRINTF(InOrderCachePort, "Retry Request for [tid:%i] [sn:%i] failed.\n", + DPRINTF(InOrderCachePort, + "Retry Request for [tid:%i] [sn:%i] failed\n", retryReq->inst->readTid(), retryReq->inst->seqNum); } - } void CacheUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) { - std::vector slot_remove_list; + vector slot_remove_list; - std::map::iterator map_it = reqMap.begin(); - std::map::iterator map_end = reqMap.end(); + map::iterator map_it = reqMap.begin(); + map::iterator map_end = reqMap.end(); while (map_it != map_end) { ResReqPtr req_ptr = (*map_it).second; @@ -555,7 +560,7 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, req_ptr->getInst()->seqNum > squash_seq_num) { DPRINTF(InOrderCachePort, - "[tid:%i] Squashing request from [sn:%i].\n", + "[tid:%i] Squashing request from [sn:%i]\n", req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); req_ptr->setSquashed(); @@ -578,13 +583,13 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, } // Now Delete Slot Entry from Req. Map - for (int i = 0; i < slot_remove_list.size(); i++) { + for (int i = 0; i < slot_remove_list.size(); i++) freeSlot(slot_remove_list[i]); - } - } -uint64_t CacheUnit::getMemData(Packet *packet) { +uint64_t +CacheUnit::getMemData(Packet *packet) +{ switch (packet->getSize()) { case 8: @@ -600,10 +605,7 @@ uint64_t CacheUnit::getMemData(Packet *packet) { return packet->get(); default: - std::cerr << "bad store data size = " << packet->getSize() << std::endl; - - assert(0); - return 0; + panic("bad store data size = %d\n", packet->getSize()); } } diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh index 9d048d789..8cd2b89cb 100644 --- a/src/cpu/inorder/resources/cache_unit.hh +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -54,7 +54,8 @@ typedef CacheRequest* CacheReqPtr; class CacheReqPacket; typedef CacheReqPacket* CacheReqPktPtr; -class CacheUnit : public Resource { +class CacheUnit : public Resource +{ public: typedef ThePipeline::DynInstPtr DynInstPtr; @@ -88,8 +89,9 @@ class CacheUnit : public Resource { public: /** Default constructor. */ CachePort(CacheUnit *_cachePortUnit) - : Port(_cachePortUnit->name() + "-cache-port", (MemObject*)_cachePortUnit->cpu), - cachePortUnit(_cachePortUnit) + : Port(_cachePortUnit->name() + "-cache-port", + (MemObject*)_cachePortUnit->cpu), + cachePortUnit(_cachePortUnit) { } bool snoopRangeSent; @@ -214,23 +216,25 @@ class CacheUnit : public Resource { /** @todo: Add Resource Stats Here */ }; -struct CacheSchedEntry : public ThePipeline::ScheduleEntry { +struct CacheSchedEntry : public ThePipeline::ScheduleEntry +{ enum EntryType { FetchAccess, DataAccess }; - CacheSchedEntry(int stage_num, int _priority, int res_num, MemCmd::Command pkt_cmd, - EntryType _type = FetchAccess) : - ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd), - type(_type) + CacheSchedEntry(int stage_num, int _priority, int res_num, + MemCmd::Command pkt_cmd, EntryType _type = FetchAccess) + : ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd), + type(_type) { } MemCmd::Command pktCmd; EntryType type; }; -class CacheRequest : public ResourceRequest { +class CacheRequest : public ResourceRequest +{ public: CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd, int req_size, @@ -246,10 +250,10 @@ class CacheRequest : public ResourceRequest { virtual ~CacheRequest() { - /* +#if 0 delete reqData; - Can get rid of packet and packet request now + // Can get rid of packet and packet request now if (*dataPkt) { if (*dataPkt->req) { delete dataPkt->req; @@ -263,17 +267,22 @@ class CacheRequest : public ResourceRequest { delete retryPkt->req; } delete retryPkt; - }*/ + } +#endif - if (memReq) { + if (memReq) delete memReq; - } } virtual PacketDataPtr getData() { return reqData; } - void setMemAccCompleted(bool completed = true) { memAccComplete = completed; } + void + setMemAccCompleted(bool completed = true) + { + memAccComplete = completed; + } + bool isMemAccComplete() { return memAccComplete; } void setMemAccPending(bool pending = true) { memAccPending = pending; } @@ -290,7 +299,8 @@ class CacheRequest : public ResourceRequest { bool memAccPending; }; -class CacheReqPacket : public Packet { +class CacheReqPacket : public Packet +{ public: CacheReqPacket(CacheRequest *_req, Command _cmd, short _dest) -- cgit v1.2.3 From f255957b902e8d7c0a274d8a2f5afe326a813be8 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 10 Feb 2009 22:19:27 -0800 Subject: style --- src/cpu/static_inst.cc | 43 +++++++++++++++++++++++++++++--- src/cpu/static_inst.hh | 67 +++++++++++++++++--------------------------------- 2 files changed, 63 insertions(+), 47 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc index 52a7ede03..01136bda1 100644 --- a/src/cpu/static_inst.cc +++ b/src/cpu/static_inst.cc @@ -40,11 +40,17 @@ StaticInst::DecodeCache StaticInst::decodeCache; StaticInst::AddrDecodeCache StaticInst::addrDecodeCache; StaticInst::cacheElement StaticInst::recentDecodes[2]; +using namespace std; + +StaticInst::~StaticInst() +{ + if (cachedDisassembly) + delete cachedDisassembly; +} + void StaticInst::dumpDecodeCacheStats() { - using namespace std; - cerr << "Decode hash table stats @ " << curTick << ":" << endl; cerr << "\tnum entries = " << decodeCache.size() << endl; cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl; @@ -81,6 +87,37 @@ StaticInstPtr StaticInst::fetchMicroop(MicroPC micropc) { panic("StaticInst::fetchMicroop() called on instruction " - "that is not microcoded."); + "that is not microcoded."); } +Addr +StaticInst::branchTarget(Addr branchPC) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not a PC-relative branch."); + M5_DUMMY_RETURN; +} + +Addr +StaticInst::branchTarget(ThreadContext *tc) const +{ + panic("StaticInst::branchTarget() called on instruction " + "that is not an indirect branch."); + M5_DUMMY_RETURN; +} + +Request::Flags +StaticInst::memAccFlags() +{ + panic("StaticInst::memAccFlags called on non-memory instruction"); + return 0; +} + +const string & +StaticInst::disassemble(Addr pc, const SymbolTable *symtab) const +{ + if (!cachedDisassembly) + cachedDisassembly = new string(generateDisassembly(pc, symtab)); + + return *cachedDisassembly; +} diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index f28b53ccf..bf07e06c7 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -382,12 +382,7 @@ class StaticInst : public StaticInstBase { } public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } + virtual ~StaticInst(); /** * The execute() signatures are auto-generated by scons based on the @@ -406,12 +401,7 @@ class StaticInst : public StaticInstBase * Invalid if not a PC-relative branch (i.e. isDirectCtrl() * should be true). */ - virtual Addr branchTarget(Addr branchPC) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not a PC-relative branch."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(Addr branchPC) const; /** * Return the target address for an indirect branch (jump). The @@ -420,12 +410,7 @@ class StaticInst : public StaticInstBase * execute the branch in question. Invalid if not an indirect * branch (i.e. isIndirectCtrl() should be true). */ - virtual Addr branchTarget(ThreadContext *tc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - M5_DUMMY_RETURN - } + virtual Addr branchTarget(ThreadContext *tc) const; /** * Return true if the instruction is a control transfer, and if so, @@ -433,11 +418,7 @@ class StaticInst : public StaticInstBase */ bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const; - virtual Request::Flags memAccFlags() - { - panic("StaticInst::memAccFlags called on non-memory instruction"); - return 0; - }; + virtual Request::Flags memAccFlags(); /** * Return string representation of disassembled instruction. @@ -447,14 +428,7 @@ class StaticInst : public StaticInstBase * should not be cached, this function should be overridden directly. */ virtual const std::string &disassemble(Addr pc, - const SymbolTable *symtab = 0) const - { - if (!cachedDisassembly) - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - - return *cachedDisassembly; - } + const SymbolTable *symtab = 0) const; /// Decoded instruction cache type. /// For now we're using a generic hash_map; this seems to work @@ -486,13 +460,13 @@ class StaticInst : public StaticInstBase /// A cache of decoded instruction objects from addresses. static AddrDecodeCache addrDecodeCache; - struct cacheElement { + struct cacheElement + { Addr page_addr; AddrDecodePage *decodePage; - cacheElement() - :decodePage(NULL) { } - } ; + cacheElement() : decodePage(NULL) { } + }; /// An array of recently decoded instructions. // might not use an array if there is only two elements @@ -521,7 +495,7 @@ class StaticInst : public StaticInstBase /// @retval A pointer to the corresponding StaticInst object. //This is defined as inlined below. static StaticInstPtr searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage); + AddrDecodePage *decodePage); }; typedef RefCountingPtr StaticInstBasePtr; @@ -575,7 +549,8 @@ class AddrDecodePage public: /// Constructor - AddrDecodePage() { + AddrDecodePage() + { lowerMask = TheISA::PageBytes - 1; memset(valid, 0, TheISA::PageBytes); } @@ -585,7 +560,8 @@ class AddrDecodePage /// related to the address /// @param mach_inst The binary instruction to check /// @param addr The address containing the instruction - inline bool decoded(ExtMachInst mach_inst, Addr addr) + bool + decoded(ExtMachInst mach_inst, Addr addr) { return (valid[addr & lowerMask] && (instructions[addr & lowerMask]->machInst == mach_inst)); @@ -595,19 +571,22 @@ class AddrDecodePage /// to check if the instruction is valid. /// @param addr The address of the instruction. /// @retval A pointer to the corresponding StaticInst object. - inline StaticInstPtr getInst(Addr addr) - { return instructions[addr & lowerMask]; } + StaticInstPtr + getInst(Addr addr) + { + return instructions[addr & lowerMask]; + } /// Inserts a pointer to a StaticInst object into the list of decoded /// instructions on the page. /// @param addr The address of the instruction. /// @param si A pointer to the corresponding StaticInst object. - inline void insert(Addr addr, StaticInstPtr &si) + void + insert(Addr addr, StaticInstPtr &si) { instructions[addr & lowerMask] = si; valid[addr & lowerMask] = true; } - }; @@ -656,7 +635,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) } // creates a new object for a page of decoded instructions - AddrDecodePage * decodePage = new AddrDecodePage; + AddrDecodePage *decodePage = new AddrDecodePage; addrDecodeCache[page_addr] = decodePage; updateCache(page_addr, decodePage); return searchCache(mach_inst, addr, decodePage); @@ -664,7 +643,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr) inline StaticInstPtr StaticInst::searchCache(ExtMachInst mach_inst, Addr addr, - AddrDecodePage * decodePage) + AddrDecodePage *decodePage) { DecodeCache::iterator iter = decodeCache.find(mach_inst); if (iter != decodeCache.end()) { -- cgit v1.2.3 From 89a7fb03934b3e38c7d8b2c4818794b3ec874fdf Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Mon, 16 Feb 2009 08:56:40 -0800 Subject: Fixes to get prefetching working again. Apparently we broke it with the cache rewrite and never noticed. Thanks to Bao Yungang for a significant part of these changes (and for inspiring me to work on the rest). Some other overdue cleanup on the prefetch code too. --- src/cpu/base.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 06fcebad8..0ef206d90 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -344,8 +344,12 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) assert(newTC->threadId() == oldTC->threadId()); system->replaceThreadContext(newTC, newTC->contextId()); - if (DTRACE(Context)) + /* This code no longer works since the zero register (e.g., + * r31 on Alpha) doesn't necessarily contain zero at this + * point. + if (DTRACE(Context)) ThreadContext::compare(oldTC, newTC); + */ } #if FULL_SYSTEM -- cgit v1.2.3 From 6c5afe6346b31edf6af245002c270a3c26618833 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Fri, 20 Feb 2009 11:02:48 -0500 Subject: Remove unnecessary building of FreeList/RenameMap in InOrder. Clean-up comments and O3 extensions InOrder Thread Context --- src/cpu/inorder/SConscript | 5 +-- src/cpu/inorder/cpu.hh | 9 ---- src/cpu/inorder/thread_context.cc | 93 +-------------------------------------- src/cpu/inorder/thread_context.hh | 2 +- 4 files changed, 4 insertions(+), 105 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript index c7edd1d76..dc5ff6f46 100644 --- a/src/cpu/inorder/SConscript +++ b/src/cpu/inorder/SConscript @@ -42,13 +42,12 @@ if 'InOrderCPU' in env['CPU_MODELS']: TraceFlag('InOrderCPU') TraceFlag('InOrderMDU') TraceFlag('RegDepMap') - TraceFlag('Rename') TraceFlag('InOrderDynInst') TraceFlag('Resource') TraceFlag('RefCount') CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', - 'InOrderMDU', 'RegDepMap', 'Resource', 'Rename']) + 'InOrderMDU', 'RegDepMap', 'Resource']) Source('pipeline_traits.cc') Source('inorder_dyn_inst.cc') @@ -74,8 +73,6 @@ if 'InOrderCPU' in env['CPU_MODELS']: Source('../o3/btb.cc') Source('../o3/tournament_pred.cc') Source('../o3/2bit_local_pred.cc') - Source('../o3/free_list.cc') - Source('../o3/rename_map.cc') Source('../o3/ras.cc') Source('thread_context.cc') Source('cpu.cc') diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 34eabbad4..6c1cdc9dc 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -77,7 +77,6 @@ class InOrderCPU : public BaseCPU typedef TheISA::FloatRegBits FloatRegBits; typedef TheISA::MiscReg MiscReg; typedef TheISA::RegFile RegFile; - typedef SimpleRenameMap RenameMap; //DynInstPtr TypeDefs typedef ThePipeline::DynInstPtr DynInstPtr; @@ -586,14 +585,6 @@ class InOrderCPU : public BaseCPU std::list fetchPriorityList; - /** Rename Map for architectural-to-physical register mappings. - * In a In-order processor, the mapping is fixed - * (e.g. Thread 1: 0-31, Thread 1: 32-63, etc.) - * In a Out-of-Order processor, this is used to maintain - * sequential consistency (?right word here?). - */ - RenameMap renameMap[ThePipeline::MaxThreads]; - protected: /** Active Threads List */ std::list activeThreads; diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc index 5e2c789cb..2470ee676 100644 --- a/src/cpu/inorder/thread_context.cc +++ b/src/cpu/inorder/thread_context.cc @@ -44,7 +44,6 @@ InOrderThreadContext::takeOverFrom(ThreadContext *old_context) // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); - //setCpuId(0/*old_context->readCpuId()*/); thread->funcExeInst = old_context->readFuncExeInst(); old_context->setStatus(ThreadContext::Unallocated); @@ -61,18 +60,8 @@ InOrderThreadContext::activate(int delay) if (thread->status() == ThreadContext::Active) return; - // @TODO: Make this process useful again... - //if (thread->status() == ThreadContext::Unallocated) { - // Allows the CPU to drain partitioned resources - // before inserting thread into the CPU - // (e.g. bind physical registers) - //cpu->activateWhenReady(thread->readTid()); - //return; - //} - thread->setStatus(ThreadContext::Active); - // status() == Suspended cpu->activateContext(thread->readTid(), delay); } @@ -157,37 +146,9 @@ InOrderThreadContext:: getInst() void -InOrderThreadContext::copyArchRegs(ThreadContext *tc) +InOrderThreadContext::copyArchRegs(ThreadContext *src_tc) { - unsigned tid = thread->readTid(); - PhysRegIndex renamed_reg; - - // First loop through the integer registers. - for (int i = 0; i < TheISA::NumIntRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i); - - DPRINTF(InOrderCPU, "Copying over register %i, had data %lli, " - "now has data %lli.\n", - renamed_reg, cpu->readIntReg(renamed_reg, tid), - tc->readIntReg(i)); - - cpu->setIntReg(renamed_reg, tc->readIntReg(i), tid); - } - - // Then loop through the floating point registers. - for (int i = 0; i < TheISA::NumFloatRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag); - cpu->setFloatRegBits(renamed_reg, tc->readFloatRegBits(i), tid); - } - - // Copy the misc regs. - TheISA::copyMiscRegs(tc, this); - - // Then finally set the PC and the next PC. - cpu->setPC(tc->readPC(), tid); - cpu->setNextPC(tc->readNextPC(), tid); - cpu->setNextNPC(tc->readNextNPC(), tid); - this->thread->funcExeInst = tc->readFuncExeInst(); + TheISA::copyRegs(src_tc, this); } @@ -236,33 +197,18 @@ void InOrderThreadContext::setIntReg(int reg_idx, uint64_t val) { cpu->setIntReg(reg_idx, val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - // cpu->squashFromTC(thread->readTid()); - //} } void InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) { cpu->setFloatReg(reg_idx, val, thread->readTid(), width); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val) { cpu->setFloatReg(reg_idx, val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void @@ -270,22 +216,12 @@ InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, int width) { cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) { cpu->setFloatRegBits(reg_idx, val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void @@ -299,11 +235,6 @@ InOrderThreadContext::setPC(uint64_t val) { DPRINTF(InOrderCPU, "Setting PC to %08p\n", val); cpu->setPC(val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void @@ -311,11 +242,6 @@ InOrderThreadContext::setNextPC(uint64_t val) { DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val); cpu->setNextPC(val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void @@ -323,33 +249,18 @@ InOrderThreadContext::setNextNPC(uint64_t val) { DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val); cpu->setNextNPC(val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } void InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val) { cpu->setMiscReg(misc_reg, val, thread->readTid()); - - // Squash if we're not already in a state update mode. - //if (!thread->trapPending && !thread->inSyscall) { - //cpu->squashFromTC(thread->readTid()); - //} } TheISA::IntReg diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh index 919d5d2b6..708dcf6b3 100644 --- a/src/cpu/inorder/thread_context.hh +++ b/src/cpu/inorder/thread_context.hh @@ -147,7 +147,7 @@ class InOrderThreadContext : public ThreadContext virtual TheISA::MachInst getInst(); /** Copies the architectural registers from another TC into this TC. */ - virtual void copyArchRegs(ThreadContext *tc); + virtual void copyArchRegs(ThreadContext *src_tc); /** Resets all architectural registers to 0. */ virtual void clearArchRegs(); -- cgit v1.2.3 From 3fa9812e1d572cd06f95cec138b87d590160e4b4 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Mon, 23 Feb 2009 11:48:40 -0800 Subject: debug: Move debug_break into src/base --- src/cpu/pc_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc index 438218df2..79f5277d5 100644 --- a/src/cpu/pc_event.cc +++ b/src/cpu/pc_event.cc @@ -34,12 +34,12 @@ #include #include +#include "base/debug.hh" #include "base/trace.hh" #include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "cpu/pc_event.hh" -#include "sim/debug.hh" #include "sim/core.hh" #include "sim/system.hh" -- cgit v1.2.3 From a1aba01a02a8c1261120de83d8fbfd6624f0cb17 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:15:34 -0800 Subject: CPU: Get rid of translate... functions from various interface classes. --- src/cpu/base_dyn_inst.hh | 56 +--------------- src/cpu/checker/cpu.cc | 55 +--------------- src/cpu/checker/cpu.hh | 4 -- src/cpu/checker/cpu_impl.hh | 2 +- src/cpu/inorder/cpu.hh | 18 ------ src/cpu/inorder/resources/tlb_unit.cc | 6 +- src/cpu/o3/cpu.hh | 18 ------ src/cpu/o3/fetch_impl.hh | 2 +- src/cpu/ozone/cpu.hh | 47 ++------------ src/cpu/ozone/front_end_impl.hh | 2 +- src/cpu/ozone/inorder_back_end.hh | 4 +- src/cpu/simple/atomic.cc | 117 +-------------------------------- src/cpu/simple/atomic.hh | 5 -- src/cpu/simple/base.cc | 2 +- src/cpu/simple/timing.cc | 118 ++++++++++++++-------------------- src/cpu/simple/timing.hh | 6 -- src/cpu/simple_thread.hh | 15 ----- 17 files changed, 70 insertions(+), 407 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index f40616e54..f58bf7cf8 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -115,9 +115,6 @@ class BaseDynInst : public FastAlloc, public RefCounted template Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Does a write to a given address. * @param data The data to be written. @@ -130,9 +127,6 @@ class BaseDynInst : public FastAlloc, public RefCounted Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void prefetch(Addr addr, unsigned flags); void writeHint(Addr addr, int size, unsigned flags); Fault copySrcTranslate(Addr src); @@ -856,29 +850,6 @@ class BaseDynInst : public FastAlloc, public RefCounted { thread->storeCondFailures = sc_failures; } }; -template -Fault -BaseDynInst::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->contextId(), threadNumber); - - fault = cpu->translateDataReadReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - template template inline Fault @@ -889,7 +860,7 @@ BaseDynInst::read(Addr addr, T &data, unsigned flags) req->setVirt(asid, addr, sizeof(T), flags, this->PC); req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataReadReq(req, thread); + fault = cpu->dtb->translate(req, thread->getTC(), false); if (req->isUncacheable()) isUncacheable = true; @@ -930,29 +901,6 @@ BaseDynInst::read(Addr addr, T &data, unsigned flags) return fault; } -template -Fault -BaseDynInst::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - if (traceData) { - traceData->setAddr(vaddr); - } - - reqMade = true; - Request *req = new Request(); - req->setVirt(asid, vaddr, size, flags, PC); - req->setThreadContext(thread->contextId(), threadNumber); - - fault = cpu->translateDataWriteReq(req, thread); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - template template inline Fault @@ -968,7 +916,7 @@ BaseDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(asid, addr, sizeof(T), flags, this->PC); req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->translateDataWriteReq(req, thread); + fault = cpu->dtb->translate(req, thread->getTC(), true); if (req->isUncacheable()) isUncacheable = true; diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc index a6af98d66..e530e6014 100644 --- a/src/cpu/checker/cpu.cc +++ b/src/cpu/checker/cpu.cc @@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - translateDataReadReq(memReq); + dtb->translate(memReq, tc, false); PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); @@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - thread->translateDataWriteReq(memReq); + dtb->translate(memReq, tc, true); // Can compare the write data and result only if it's cacheable, // not a store conditional, or is a store conditional that @@ -324,57 +324,6 @@ CheckerCPU::dbg_vtophys(Addr addr) } #endif // FULL_SYSTEM -bool -CheckerCPU::translateInstReq(Request *req) -{ -#if FULL_SYSTEM - return (thread->translateInstReq(req) == NoFault); -#else - thread->translateInstReq(req); - return true; -#endif -} - -void -CheckerCPU::translateDataReadReq(Request *req) -{ - thread->translateDataReadReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - -void -CheckerCPU::translateDataWriteReq(Request *req) -{ - thread->translateDataWriteReq(req); - - if (req->getVaddr() != unverifiedReq->getVaddr()) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->getVaddr(), req->getVaddr()); - handleError(); - } - req->setPaddr(unverifiedReq->getPaddr()); - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->getFlags(), req->getFlags()); - handleError(); - } -} - bool CheckerCPU::checkFlags(Request *req) { diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index 5b3c4582c..0d3dddded 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -331,10 +331,6 @@ class CheckerCPU : public BaseCPU this->dtb->demapPage(vaddr, asn); } - bool translateInstReq(Request *req); - void translateDataWriteReq(Request *req); - void translateDataReadReq(Request *req); - #if FULL_SYSTEM Fault hwrei() { return thread->hwrei(); } void ev5_trap(Fault fault) { fault->invoke(tc); } diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index 0428e8806..e1ecc151c 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -155,7 +155,7 @@ Checker::verify(DynInstPtr &completed_inst) fetch_PC, thread->contextId(), inst->threadNumber); - bool succeeded = translateInstReq(memReq); + bool succeeded = itb->translate(memReq, thread); if (!succeeded) { if (inst->getFault() == NoFault) { diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 6c1cdc9dc..4a7dfb404 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -498,24 +498,6 @@ class InOrderCPU : public BaseCPU /** Debug function to print all instructions on the list. */ void dumpInsts(); - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(RequestPtr &req, Thread *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(RequestPtr &req, Thread *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(RequestPtr &req, Thread *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - /** Forwards an instruction read to the appropriate data * resource (indexes into Resource Pool thru "dataPortIdx") */ diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc index 9b0decedb..4eeb4727b 100644 --- a/src/cpu/inorder/resources/tlb_unit.cc +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -98,7 +98,8 @@ TLBUnit::execute(int slot_idx) case FetchLookup: { tlb_req->fault = - this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]); + this->cpu->itb->translate(tlb_req->memReq, + cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { DPRINTF(Resource, "[tid:%i]: %s encountered while translating " @@ -128,7 +129,8 @@ TLBUnit::execute(int slot_idx) tid, seq_num, tlb_req->memReq->getVaddr()); tlb_req->fault = - this->cpu->translateInstReq(tlb_req->memReq, cpu->thread[tid]); + this->cpu->itb->translate(tlb_req->memReq, + cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { DPRINTF(Resource, "[tid:%i]: %s encountered while translating " diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index d14001d0d..683e4284f 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -279,24 +279,6 @@ class FullO3CPU : public BaseO3CPU this->dtb->demapPage(vaddr, asn); } - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, Thread *thread) - { - return this->itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, Thread *thread) - { - return this->dtb->translate(req, thread->getTC(), true); - } - /** Returns a specific port. */ Port *getPort(const std::string &if_name, int idx); diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index cff6db299..4beb34a85 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -599,7 +599,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid memReq[tid] = mem_req; // Translate the instruction request. - fault = cpu->translateInstReq(mem_req, cpu->thread[tid]); + fault = cpu->itb->translate(mem_req, cpu->thread[tid]->getTC()); // In the case of faults, the fetch stage may need to stall and wait // for the ITB miss to be handled. diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 55ad7b3fb..0eb4b31f7 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -415,59 +415,20 @@ class OzoneCPU : public BaseCPU void demapPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); - dtb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); + cpu->dtb->demap(vaddr, asn); } void demapInstPage(Addr vaddr, uint64_t asn) { - itb->demap(vaddr, asn); + cpu->itb->demap(vaddr, asn); } void demapDataPage(Addr vaddr, uint64_t asn) { - dtb->demap(vaddr, asn); + cpu->dtb->demap(vaddr, asn); } -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState *thread) - { - return itb->translate(req, thread->getTC()); - } - - /** Translates data read request. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState *thread) - { - return dtb->translate(req, thread->getTC(), false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState *thread) - { - return dtb->translate(req, thread->getTC(), true); - } - -#else - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(RequestPtr &req, OzoneThreadState *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(RequestPtr &req, OzoneThreadState *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState *thread) - { - return thread->getProcessPtr()->pTable->translate(req); - } -#endif - /** CPU read function, forwards read to LSQ. */ template Fault read(Request *req, T &data, int load_idx) diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index b1e131115..2a9b107d4 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -480,7 +480,7 @@ FrontEnd::fetchCacheLine() PC, cpu->thread->contextId()); // Translate the instruction request. - fault = cpu->translateInstReq(memReq, thread); + fault = cpu->itb->translate(memReq, thread); // Now do the timing access to see whether or not the instruction // exists within the cache. diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index c23d801ba..8850fa737 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -204,7 +204,7 @@ InorderBackEnd::read(Addr addr, T &data, unsigned flags) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataReadReq(memReq); + Fault fault = cpu->dtb->translate(memReq, thread->getTC(), false); // if we have a cache, do cache access too if (fault == NoFault && dcacheInterface) { @@ -245,7 +245,7 @@ InorderBackEnd::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->translateDataWriteReq(memReq); + Fault fault = cpu->dtb->translate(memReq, thread->getTC(), true); if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index feb8a7fc5..cd07a9fe3 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -314,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataReadReq(req); + Fault fault = thread->dtb->translate(req, tc, false); // Now do the access. if (fault == NoFault) { @@ -370,61 +370,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) } } -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 @@ -507,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->translateDataWriteReq(req); + Fault fault = thread->dtb->translate(req, tc, true); // Now do the access. if (fault == NoFault) { @@ -586,64 +531,6 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) } } -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 diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 24400df22..190097637 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -136,11 +136,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU template Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - /** * Print state of address in memory system via PrintReq (for * debugging). diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index b1a77247f..f9fa8d835 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -347,7 +347,7 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - Fault fault = thread->translateInstReq(req); + Fault fault = thread->itb->translate(req, tc); return fault; } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 5da08db47..844eccc75 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -275,6 +275,7 @@ TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, if ((fault = buildPacket(pkt1, req1, read)) != NoFault || (fault = buildPacket(pkt2, req2, read)) != NoFault) { delete req; + delete req1; delete pkt1; req = NULL; pkt1 = NULL; @@ -286,6 +287,15 @@ TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), Packet::Broadcast); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + delete req1; + delete pkt1; + delete req2; + delete pkt2; + pkt1 = pkt; + pkt2 = NULL; + return NoFault; + } pkt->dataDynamic(data); pkt1->dataStatic(data); @@ -304,8 +314,7 @@ TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, Fault TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) { - Fault fault = read ? thread->translateDataReadReq(req) : - thread->translateDataWriteReq(req); + Fault fault = thread->dtb->translate(req, tc, !read); MemCmd cmd; if (fault != NoFault) { delete req; @@ -348,9 +357,13 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) if (split_addr > addr) { PacketPtr pkt1, pkt2; - this->buildSplitPacket(pkt1, pkt2, req, + Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr, (uint8_t *)(new T), true); - if (handleReadPacket(pkt1)) { + if (fault != NoFault) + return fault; + if (req->getFlags().isSet(Request::NO_ACCESS)) { + dcache_pkt = pkt1; + } else if (handleReadPacket(pkt1)) { SplitFragmentSenderState * send_state = dynamic_cast(pkt1->senderState); send_state->clearFromParent(); @@ -365,9 +378,12 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) if (fault != NoFault) { return fault; } - pkt->dataDynamic(new T); - - handleReadPacket(pkt); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + dcache_pkt = pkt; + } else { + pkt->dataDynamic(new T); + handleReadPacket(pkt); + } } if (traceData) { @@ -382,26 +398,6 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) return NoFault; } -Fault -TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); - - if (traceData) { - traceData->setAddr(vaddr); - } - - Fault fault = thread->translateDataWriteReq(req); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS template @@ -497,15 +493,19 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) if (fault != NoFault) return fault; dcache_pkt = pkt1; - if (handleWritePacket()) { - SplitFragmentSenderState * send_state = - dynamic_cast(pkt1->senderState); - send_state->clearFromParent(); - dcache_pkt = pkt2; - if (handleReadPacket(pkt2)) { - send_state = - dynamic_cast(pkt1->senderState); + if (!req->getFlags().isSet(Request::NO_ACCESS)) { + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast( + pkt1->senderState); send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleReadPacket(pkt2)) { + send_state = + dynamic_cast( + pkt1->senderState); + send_state->clearFromParent(); + } } } } else { @@ -515,21 +515,23 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) if (fault != NoFault) return fault; - if (req->isLocked()) { - do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } + if (!req->getFlags().isSet(Request::NO_ACCESS)) { + if (req->isLocked()) { + do_access = TheISA::handleLockedWrite(thread, req); + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } - dcache_pkt->allocate(); - if (req->isMmapedIpr()) - dcache_pkt->set(htog(data)); - else - dcache_pkt->set(data); + dcache_pkt->allocate(); + if (req->isMmapedIpr()) + dcache_pkt->set(htog(data)); + else + dcache_pkt->set(data); - if (do_access) - handleWritePacket(); + if (do_access) + handleWritePacket(); + } } if (traceData) { @@ -546,26 +548,6 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) return NoFault; } -Fault -TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags) -{ - Request *req = - new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); - - if (traceData) { - traceData->setAddr(vaddr); - } - - Fault fault = thread->translateDataWriteReq(req); - - if (fault == NoFault) - paddr = req->getPaddr(); - - delete req; - return fault; -} - #ifndef DOXYGEN_SHOULD_SKIP_THIS template diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index c305d0361..0a639a627 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -224,15 +224,9 @@ class TimingSimpleCPU : public BaseSimpleCPU template Fault read(Addr addr, T &data, unsigned flags); - Fault translateDataReadAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - template Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - Fault translateDataWriteAddr(Addr vaddr, Addr &paddr, - int size, unsigned flags); - void fetch(); void completeIfetch(PacketPtr ); void completeDataAccess(PacketPtr ); diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 678bb42bb..c2ddeca06 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -148,21 +148,6 @@ class SimpleThread : public ThreadState */ ThreadContext *getTC() { return tc; } - Fault translateInstReq(RequestPtr &req) - { - return itb->translate(req, tc); - } - - Fault translateDataReadReq(RequestPtr &req) - { - return dtb->translate(req, tc, false); - } - - Fault translateDataWriteReq(RequestPtr &req) - { - return dtb->translate(req, tc, true); - } - void demapPage(Addr vaddr, uint64_t asn) { itb->demapPage(vaddr, asn); -- cgit v1.2.3 From 5605079b1f20bc7f6a4a80c8d1e4daabe7125270 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:15:44 -0800 Subject: ISA: Replace the translate functions in the TLBs with translateAtomic. --- src/cpu/base_dyn_inst.hh | 4 ++-- src/cpu/checker/cpu.cc | 4 ++-- src/cpu/checker/cpu_impl.hh | 2 +- src/cpu/inorder/resources/tlb_unit.cc | 4 ++-- src/cpu/o3/fetch_impl.hh | 2 +- src/cpu/ozone/front_end_impl.hh | 2 +- src/cpu/ozone/inorder_back_end.hh | 4 ++-- src/cpu/simple/atomic.cc | 4 ++-- src/cpu/simple/base.cc | 2 +- src/cpu/simple/timing.cc | 2 +- src/cpu/simple_thread.hh | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index f58bf7cf8..41c57cf39 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -860,7 +860,7 @@ BaseDynInst::read(Addr addr, T &data, unsigned flags) req->setVirt(asid, addr, sizeof(T), flags, this->PC); req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->dtb->translate(req, thread->getTC(), false); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), false); if (req->isUncacheable()) isUncacheable = true; @@ -916,7 +916,7 @@ BaseDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(asid, addr, sizeof(T), flags, this->PC); req->setThreadContext(thread->contextId(), threadNumber); - fault = cpu->dtb->translate(req, thread->getTC(), true); + fault = cpu->dtb->translateAtomic(req, thread->getTC(), true); if (req->isUncacheable()) isUncacheable = true; diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc index e530e6014..14777bc12 100644 --- a/src/cpu/checker/cpu.cc +++ b/src/cpu/checker/cpu.cc @@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - dtb->translate(memReq, tc, false); + dtb->translateAtomic(memReq, tc, false); PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); @@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); // translate to physical address - dtb->translate(memReq, tc, true); + dtb->translateAtomic(memReq, tc, true); // Can compare the write data and result only if it's cacheable, // not a store conditional, or is a store conditional that diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index e1ecc151c..26571ed68 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -155,7 +155,7 @@ Checker::verify(DynInstPtr &completed_inst) fetch_PC, thread->contextId(), inst->threadNumber); - bool succeeded = itb->translate(memReq, thread); + bool succeeded = itb->translateAtomic(memReq, thread); if (!succeeded) { if (inst->getFault() == NoFault) { diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc index 4eeb4727b..321ac90f8 100644 --- a/src/cpu/inorder/resources/tlb_unit.cc +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -98,7 +98,7 @@ TLBUnit::execute(int slot_idx) case FetchLookup: { tlb_req->fault = - this->cpu->itb->translate(tlb_req->memReq, + this->cpu->itb->translateAtomic(tlb_req->memReq, cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { @@ -129,7 +129,7 @@ TLBUnit::execute(int slot_idx) tid, seq_num, tlb_req->memReq->getVaddr()); tlb_req->fault = - this->cpu->itb->translate(tlb_req->memReq, + this->cpu->itb->translateAtomic(tlb_req->memReq, cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 4beb34a85..06df46c2b 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -599,7 +599,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid memReq[tid] = mem_req; // Translate the instruction request. - fault = cpu->itb->translate(mem_req, cpu->thread[tid]->getTC()); + fault = cpu->itb->translateAtomic(mem_req, cpu->thread[tid]->getTC()); // In the case of faults, the fetch stage may need to stall and wait // for the ITB miss to be handled. diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index 2a9b107d4..6b47ef539 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -480,7 +480,7 @@ FrontEnd::fetchCacheLine() PC, cpu->thread->contextId()); // Translate the instruction request. - fault = cpu->itb->translate(memReq, thread); + fault = cpu->itb->translateAtomic(memReq, thread); // Now do the timing access to see whether or not the instruction // exists within the cache. diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index 8850fa737..0840591e0 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -204,7 +204,7 @@ InorderBackEnd::read(Addr addr, T &data, unsigned flags) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->dtb->translate(memReq, thread->getTC(), false); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), false); // if we have a cache, do cache access too if (fault == NoFault && dcacheInterface) { @@ -245,7 +245,7 @@ InorderBackEnd::write(T data, Addr addr, unsigned flags, uint64_t *res) memReq->reset(addr, sizeof(T), flags); // translate to physical address - Fault fault = cpu->dtb->translate(memReq, thread->getTC(), true); + Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), true); if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index cd07a9fe3..7a1cf71c4 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -314,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->dtb->translate(req, tc, false); + Fault fault = thread->dtb->translateAtomic(req, tc, false); // Now do the access. if (fault == NoFault) { @@ -452,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) req->setVirt(0, addr, dataSize, flags, thread->readPC()); // translate to physical address - Fault fault = thread->dtb->translate(req, tc, true); + Fault fault = thread->dtb->translateAtomic(req, tc, true); // Now do the access. if (fault == NoFault) { diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index f9fa8d835..ddeb9a7c8 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -347,7 +347,7 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - Fault fault = thread->itb->translate(req, tc); + Fault fault = thread->itb->translateAtomic(req, tc); return fault; } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 844eccc75..65222266e 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -314,7 +314,7 @@ TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, Fault TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) { - Fault fault = thread->dtb->translate(req, tc, !read); + Fault fault = thread->dtb->translateAtomic(req, tc, !read); MemCmd cmd; if (fault != NoFault) { delete req; diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index c2ddeca06..4eba493c3 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -139,7 +139,7 @@ class SimpleThread : public ThreadState /*************************************************************** * SimpleThread functions to provide CPU with access to various - * state, and to provide address translation methods. + * state. **************************************************************/ /** Returns the pointer to this SimpleThread's ThreadContext. Used -- cgit v1.2.3 From 6ed47e94644f854baa33d1e9f367cc9eebd99abf Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:16:15 -0800 Subject: CPU: Implement translateTiming which defers to translateAtomic, and convert the timing simple CPU to use it. --- src/cpu/simple/atomic.cc | 6 +- src/cpu/simple/base.cc | 6 +- src/cpu/simple/base.hh | 4 +- src/cpu/simple/timing.cc | 364 ++++++++++++++++++++++++++--------------------- src/cpu/simple/timing.hh | 114 ++++++++++++++- 5 files changed, 321 insertions(+), 173 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 7a1cf71c4..2ada12b8d 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -607,8 +607,10 @@ AtomicSimpleCPU::tick() Fault fault = NoFault; bool fromRom = isRomMicroPC(thread->readMicroPC()); - if (!fromRom) - fault = setupFetchRequest(&ifetch_req); + if (!fromRom) { + setupFetchRequest(&ifetch_req); + fault = thread->itb->translateAtomic(&ifetch_req, tc); + } if (fault == NoFault) { Tick icache_latency = 0; diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index ddeb9a7c8..9372ff43d 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -330,7 +330,7 @@ BaseSimpleCPU::checkForInterrupts() } -Fault +void BaseSimpleCPU::setupFetchRequest(Request *req) { Addr threadPC = thread->readPC(); @@ -346,10 +346,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - - Fault fault = thread->itb->translateAtomic(req, tc); - - return fault; } diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 34d0f5954..d2ccc0ff1 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -125,9 +125,11 @@ class BaseSimpleCPU : public BaseCPU enum Status { Idle, Running, + ITBWaitResponse, IcacheRetry, IcacheWaitResponse, IcacheWaitSwitch, + DTBWaitResponse, DcacheRetry, DcacheWaitResponse, DcacheWaitSwitch, @@ -160,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU bool stayAtPC; void checkForInterrupts(); - Fault setupFetchRequest(Request *req); + void setupFetchRequest(Request *req); void preExecute(); void postExecute(); void advancePC(Fault fault); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 65222266e..3f5778138 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -104,7 +104,8 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) } TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) - : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), fetchEvent(this) + : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), + dcachePort(this, p->clock), fetchEvent(this) { _status = Idle; @@ -262,66 +263,123 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt) return dcache_pkt == NULL; } -Fault -TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, - RequestPtr &req, Addr split_addr, uint8_t *data, bool read) +void +TimingSimpleCPU::sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read) { - Fault fault; - RequestPtr req1, req2; - assert(!req->isLocked() && !req->isSwap()); - req->splitOnVaddr(split_addr, req1, req2); - - pkt1 = pkt2 = NULL; - if ((fault = buildPacket(pkt1, req1, read)) != NoFault || - (fault = buildPacket(pkt2, req2, read)) != NoFault) { + _status = Running; + if (fault != NoFault) { + delete data; delete req; - delete req1; - delete pkt1; - req = NULL; - pkt1 = NULL; - return fault; + + translationFault(fault); + return; } + PacketPtr pkt; + buildPacket(pkt, req, read); + pkt->dataDynamic(data); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt->makeResponse(); + completeDataAccess(pkt); + } else if (read) { + handleReadPacket(pkt); + } else { + bool do_access = true; // flag to suppress cache access - assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + if (req->isLocked()) { + do_access = TheISA::handleLockedWrite(thread, req); + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } - req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); - PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), - Packet::Broadcast); - if (req->getFlags().isSet(Request::NO_ACCESS)) { + if (do_access) { + dcache_pkt = pkt; + handleWritePacket(); + } else { + _status = DcacheWaitResponse; + completeDataAccess(pkt); + } + } +} + +void +TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + _status = Running; + if (fault1 != NoFault || fault2 != NoFault) { + delete data; delete req1; - delete pkt1; delete req2; - delete pkt2; - pkt1 = pkt; - pkt2 = NULL; - return NoFault; + if (fault1 != NoFault) + translationFault(fault1); + else if (fault2 != NoFault) + translationFault(fault2); + return; + } + PacketPtr pkt1, pkt2; + buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt1->makeResponse(); + completeDataAccess(pkt1); + } else if (read) { + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = dynamic_cast( + pkt1->senderState); + send_state->clearFromParent(); + } + } + } else { + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleWritePacket()) { + send_state = dynamic_cast( + pkt1->senderState); + send_state->clearFromParent(); + } + } } +} - pkt->dataDynamic(data); - pkt1->dataStatic(data); - pkt2->dataStatic(data + req1->getSize()); +void +TimingSimpleCPU::translationFault(Fault fault) +{ + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; - SplitMainSenderState * main_send_state = new SplitMainSenderState; - pkt->senderState = main_send_state; - main_send_state->fragments[0] = pkt1; - main_send_state->fragments[1] = pkt2; - main_send_state->outstanding = 2; - pkt1->senderState = new SplitFragmentSenderState(pkt, 0); - pkt2->senderState = new SplitFragmentSenderState(pkt, 1); - return fault; + if (traceData) { + // Since there was a fault, we shouldn't trace this instruction. + delete traceData; + traceData = NULL; + } + + postExecute(); + + if (getState() == SimObject::Draining) { + advancePC(fault); + completeDrain(); + } else { + advanceInst(fault); + } } -Fault -TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) +void +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) { - Fault fault = thread->dtb->translateAtomic(req, tc, !read); MemCmd cmd; - if (fault != NoFault) { - delete req; - req = NULL; - pkt = NULL; - return fault; - } else if (read) { + if (read) { cmd = MemCmd::ReadReq; if (req->isLocked()) cmd = MemCmd::LoadLockedReq; @@ -334,7 +392,40 @@ TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) } } pkt = new Packet(req, cmd, Packet::Broadcast); - return NoFault; +} + +void +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + pkt1 = pkt2 = NULL; + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + if (req->getFlags().isSet(Request::NO_ACCESS)) { + buildPacket(pkt1, req, read); + return; + } + + buildPacket(pkt1, req1, read); + buildPacket(pkt2, req2, read); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic(data); + pkt1->dataStatic(data); + pkt2->dataStatic(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); } template @@ -348,42 +439,30 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - PacketPtr pkt; RequestPtr req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); Addr split_addr = roundDown(addr + data_size - 1, block_size); assert(split_addr <= addr || split_addr - addr < block_size); + + _status = DTBWaitResponse; if (split_addr > addr) { - PacketPtr pkt1, pkt2; - Fault fault = this->buildSplitPacket(pkt1, pkt2, req, - split_addr, (uint8_t *)(new T), true); - if (fault != NoFault) - return fault; - if (req->getFlags().isSet(Request::NO_ACCESS)) { - dcache_pkt = pkt1; - } else if (handleReadPacket(pkt1)) { - SplitFragmentSenderState * send_state = - dynamic_cast(pkt1->senderState); - send_state->clearFromParent(); - if (handleReadPacket(pkt2)) { - send_state = - dynamic_cast(pkt1->senderState); - send_state->clearFromParent(); - } - } + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)(new T), true); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), false); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), false); } else { - Fault fault = buildPacket(pkt, req, true); - if (fault != NoFault) { - return fault; - } - if (req->getFlags().isSet(Request::NO_ACCESS)) { - dcache_pkt = pkt; - } else { - pkt->dataDynamic(new T); - handleReadPacket(pkt); - } + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)(new T), NULL, true), + false); } if (traceData) { @@ -484,54 +563,25 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) Addr split_addr = roundDown(addr + data_size - 1, block_size); assert(split_addr <= addr || split_addr - addr < block_size); + T *dataP = new T; + *dataP = TheISA::gtoh(data); + _status = DTBWaitResponse; if (split_addr > addr) { - PacketPtr pkt1, pkt2; - T *dataP = new T; - *dataP = data; - Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr, - (uint8_t *)dataP, false); - if (fault != NoFault) - return fault; - dcache_pkt = pkt1; - if (!req->getFlags().isSet(Request::NO_ACCESS)) { - if (handleWritePacket()) { - SplitFragmentSenderState * send_state = - dynamic_cast( - pkt1->senderState); - send_state->clearFromParent(); - dcache_pkt = pkt2; - if (handleReadPacket(pkt2)) { - send_state = - dynamic_cast( - pkt1->senderState); - send_state->clearFromParent(); - } - } - } + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)dataP, false); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), true); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), true); } else { - bool do_access = true; // flag to suppress cache access - - Fault fault = buildPacket(dcache_pkt, req, false); - if (fault != NoFault) - return fault; - - if (!req->getFlags().isSet(Request::NO_ACCESS)) { - if (req->isLocked()) { - do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } - - dcache_pkt->allocate(); - if (req->isMmapedIpr()) - dcache_pkt->set(htog(data)); - else - dcache_pkt->set(data); - - if (do_access) - handleWritePacket(); - } + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)dataP, res, false), + true); } if (traceData) { @@ -620,30 +670,39 @@ TimingSimpleCPU::fetch() if (!fromRom) { Request *ifetch_req = new Request(); ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); - Fault fault = setupFetchRequest(ifetch_req); + setupFetchRequest(ifetch_req); + thread->itb->translateTiming(ifetch_req, tc, + &fetchTranslation); + } else { + _status = IcacheWaitResponse; + completeIfetch(NULL); - ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + } +} + + +void +TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) +{ + if (fault == NoFault) { + ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); ifetch_pkt->dataStatic(&inst); - if (fault == NoFault) { - if (!icachePort.sendTiming(ifetch_pkt)) { - // Need to wait for retry - _status = IcacheRetry; - } else { - // Need to wait for cache to respond - _status = IcacheWaitResponse; - // ownership of packet transferred to memory system - ifetch_pkt = NULL; - } + if (!icachePort.sendTiming(ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; } else { - delete ifetch_req; - delete ifetch_pkt; - // fetch fault: advance directly to next instruction (fault handler) - advanceInst(fault); + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; } } else { - _status = IcacheWaitResponse; - completeIfetch(NULL); + delete req; + // fetch fault: advance directly to next instruction (fault handler) + advanceInst(fault); } numCycles += tickToCycles(curTick - previousTick); @@ -699,28 +758,11 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) Fault fault = curStaticInst->initiateAcc(this, traceData); if (_status != Running) { // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || _status == DcacheRetry); + assert(_status == DcacheWaitResponse || + _status == DcacheRetry || DTBWaitResponse); assert(fault == NoFault); } else { - if (fault == NoFault) { - // Note that ARM can have NULL packets if the instruction gets - // squashed due to predication - // early fail on store conditional: complete now - assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); - - fault = curStaticInst->completeAcc(dcache_pkt, this, - traceData); - if (dcache_pkt != NULL) - { - delete dcache_pkt->req; - delete dcache_pkt; - dcache_pkt = NULL; - } - - // keep an instruction count - if (fault == NoFault) - countInst(); - } else if (traceData) { + if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; traceData = NULL; @@ -843,7 +885,7 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) } } - assert(_status == DcacheWaitResponse); + assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); _status = Running; Fault fault = curStaticInst->completeAcc(pkt, this, traceData); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 0a639a627..a02ec48c9 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -96,9 +96,114 @@ class TimingSimpleCPU : public BaseSimpleCPU } }; - Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req, - Addr split_addr, uint8_t *data, bool read); - Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read); + class FetchTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + + public: + FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu) + {} + + void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendFetch(fault, req, tc); + } + }; + FetchTranslation fetchTranslation; + + class DataTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + uint8_t *data; + uint64_t *res; + bool read; + + public: + DataTranslation(TimingSimpleCPU *_cpu, + uint8_t *_data, uint64_t *_res, bool _read) : + cpu(_cpu), data(_data), res(_res), read(_read) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendData(fault, req, data, res, read); + delete this; + } + }; + + class SplitDataTranslation : public BaseTLB::Translation + { + public: + struct WholeTranslationState + { + public: + int outstanding; + RequestPtr requests[2]; + RequestPtr mainReq; + Fault faults[2]; + uint8_t *data; + bool read; + + WholeTranslationState(RequestPtr req1, RequestPtr req2, + RequestPtr main, uint8_t *_data, bool _read) + { + outstanding = 2; + requests[0] = req1; + requests[1] = req2; + mainReq = main; + faults[0] = faults[1] = NoFault; + data = _data; + read = _read; + } + }; + + TimingSimpleCPU *cpu; + int index; + WholeTranslationState *state; + + SplitDataTranslation(TimingSimpleCPU *_cpu, int _index, + WholeTranslationState *_state) : + cpu(_cpu), index(_index), state(_state) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + assert(state); + assert(state->outstanding); + state->faults[index] = fault; + if (--state->outstanding == 0) { + cpu->sendSplitData(state->faults[0], + state->faults[1], + state->requests[0], + state->requests[1], + state->mainReq, + state->data, + state->read); + delete state; + } + delete this; + } + }; + + void sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read); + void sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + void translationFault(Fault fault); + + void buildPacket(PacketPtr &pkt, RequestPtr req, bool read); + void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); bool handleReadPacket(PacketPtr pkt); // This function always implicitly uses dcache_pkt. @@ -228,8 +333,9 @@ class TimingSimpleCPU : public BaseSimpleCPU Fault write(T data, Addr addr, unsigned flags, uint64_t *res); void fetch(); + void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); void completeIfetch(PacketPtr ); - void completeDataAccess(PacketPtr ); + void completeDataAccess(PacketPtr pkt); void advanceInst(Fault fault); /** -- cgit v1.2.3 From da61c4b3ee4571d43f7133640eeda2cf51e21cd9 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:18:36 -0800 Subject: CPU: Don't fetch when executing a macroop. If the CPL changes mid macroop, the end of the instruction might not be priveleged enough to execute the beginning. --- src/cpu/simple/atomic.cc | 4 ++-- src/cpu/simple/timing.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 2ada12b8d..acda552d9 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -607,7 +607,7 @@ AtomicSimpleCPU::tick() Fault fault = NoFault; bool fromRom = isRomMicroPC(thread->readMicroPC()); - if (!fromRom) { + if (!fromRom && !curMacroStaticInst) { setupFetchRequest(&ifetch_req); fault = thread->itb->translateAtomic(&ifetch_req, tc); } @@ -617,7 +617,7 @@ AtomicSimpleCPU::tick() 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 diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 3f5778138..f398365d3 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -667,7 +667,7 @@ TimingSimpleCPU::fetch() bool fromRom = isRomMicroPC(thread->readMicroPC()); - if (!fromRom) { + if (!fromRom && !curMacroStaticInst) { Request *ifetch_req = new Request(); ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); setupFetchRequest(ifetch_req); -- cgit v1.2.3 From 9940e21fa98950c477c0fb7488376005b2ca71df Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:19:33 -0800 Subject: CPU: Add a flag to identify a read barrier to the static inst class. --- src/cpu/static_inst.hh | 1 + 1 file changed, 1 insertion(+) (limited to 'src/cpu') diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index bf07e06c7..cb32f2333 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -159,6 +159,7 @@ class StaticInstBase : public RefCounted IsSerializeAfter, IsMemBarrier, ///< Is a memory barrier IsWriteBarrier, ///< Is a write barrier + IsReadBarrier, ///< Is a read barrier IsERET, /// <- Causes the IFU to stall (MIPS ISA) IsNonSpeculative, ///< Should not be executed speculatively -- cgit v1.2.3 From 5c546e35046a0b7260dec0b4d979e05f29505785 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:22:36 -0800 Subject: CPU: Only look up the nearest symbol in the kernel if you're actually in kernel code. --- src/cpu/exetrace.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 5897d1dbc..ea53fb6f5 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -71,6 +71,9 @@ Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran) Addr sym_addr; if (debugSymbolTable && IsOn(ExecSymbol) +#if FULL_SYSTEM + && !inUserMode(thread) +#endif && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { if (PC != sym_addr) sym_str += csprintf("+%d", PC - sym_addr); -- cgit v1.2.3 From d447ccb2c61a9225e5663ac29c999ac0a52a412f Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Thu, 26 Feb 2009 19:29:17 -0500 Subject: CPA: Add code to automatically record function symbols as CPU executes. --- src/cpu/o3/commit_impl.hh | 7 +++++++ src/cpu/o3/dyn_inst_impl.hh | 5 +++++ src/cpu/simple/base.cc | 5 +++++ 3 files changed, 17 insertions(+) (limited to 'src/cpu') diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index e215fe49e..7cd88b49b 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -36,6 +36,7 @@ #include #include "arch/utility.hh" +#include "base/cp_annotate.hh" #include "base/loader/symtab.hh" #include "base/timebuf.hh" #include "cpu/exetrace.hh" @@ -1097,6 +1098,12 @@ DefaultCommit::commitHead(DynInstPtr &head_inst, unsigned inst_num) if (node) thread[tid]->profileNode = node; } + if (CPA::available()) { + if (head_inst->isControl()) { + ThreadContext *tc = thread[tid]->getTC(); + CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC()); + } + } #endif if (head_inst->traceData) { diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 6398a3afe..8d391ceaf 100644 --- a/src/cpu/o3/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -28,6 +28,7 @@ * Authors: Kevin Lim */ +#include "base/cp_annotate.hh" #include "cpu/o3/dyn_inst.hh" template @@ -136,6 +137,10 @@ BaseO3DynInst::hwrei() // Set the next PC based on the value of the EXC_ADDR IPR. this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, this->threadNumber)); + if (CPA::available()) { + ThreadContext *tc = this->cpu->tcBase(this->threadNumber); + CPA::cpa()->swAutoBegin(tc, this->readNextPC()); + } // Tell CPU to clear any state it needs to if a hwrei is taken. this->cpu->hwrei(this->threadNumber); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 9372ff43d..348d2392f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -31,6 +31,7 @@ #include "arch/utility.hh" #include "arch/faults.hh" #include "base/cprintf.hh" +#include "base/cp_annotate.hh" #include "base/inifile.hh" #include "base/loader/symtab.hh" #include "base/misc.hh" @@ -450,6 +451,10 @@ BaseSimpleCPU::postExecute() comLoadEventQueue[0]->serviceEvents(numLoad); } + if (CPA::available()) { + CPA::cpa()->swAutoBegin(tc, thread->readNextPC()); + } + traceFunctions(thread->readPC()); if (traceData) { -- cgit v1.2.3 From 9a000c51736d97c1109be296ea7d1fd41d84debb Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 27 Feb 2009 09:22:14 -0800 Subject: Processes: Make getting and setting system call arguments part of a process object. --- src/cpu/checker/thread_context.hh | 15 --------------- src/cpu/inorder/cpu.cc | 26 -------------------------- src/cpu/inorder/cpu.hh | 9 --------- src/cpu/inorder/thread_context.cc | 18 ------------------ src/cpu/inorder/thread_context.hh | 9 --------- src/cpu/o3/cpu.cc | 35 ----------------------------------- src/cpu/o3/cpu.hh | 11 ----------- src/cpu/o3/thread_context.hh | 9 --------- src/cpu/o3/thread_context_impl.hh | 25 ------------------------- src/cpu/ozone/cpu.hh | 17 ----------------- src/cpu/ozone/cpu_impl.hh | 20 -------------------- src/cpu/simple_thread.hh | 28 ---------------------------- src/cpu/thread_context.hh | 17 ----------------- 13 files changed, 239 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 524e87cd4..3c87f841f 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -277,21 +277,6 @@ class CheckerThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { - checkerTC->setSyscallArg(i, val); - actualTC->setSyscallArg(i, val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - checkerTC->setSyscallReturn(return_value); - actualTC->setSyscallReturn(return_value); - } - Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif }; diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index adbf645f4..c22dd1154 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -1281,32 +1281,6 @@ InOrderCPU::syscall(int64_t callnum, int tid) nonSpecInstActive[tid] = false; } -IntReg -InOrderCPU::getSyscallArg(int idx, int tid) -{ - return readIntReg(ArgumentReg0 + idx, tid); -} - -void -InOrderCPU::setSyscallArg(int idx, IntReg val, int tid) -{ - setIntReg(ArgumentReg0 + idx, val, tid); -} - -void -InOrderCPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - if (return_value.successful()) { - // no error - setIntReg(SyscallSuccessReg, 0, tid); - setIntReg(ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - setIntReg(SyscallSuccessReg, (IntReg) -1, tid); - setIntReg(ReturnValueReg, -return_value.value(), tid); - } -} - Fault InOrderCPU::read(DynInstPtr inst) { diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 4a7dfb404..e27687a72 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -511,15 +511,6 @@ class InOrderCPU : public BaseCPU /** Executes a syscall.*/ void syscall(int64_t callnum, int tid); - /** Gets a syscall argument. */ - IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); - public: /** Per-Thread List of all the instructions in flight. */ std::list instList[ThePipeline::MaxThreads]; diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc index 2470ee676..13f8ecdad 100644 --- a/src/cpu/inorder/thread_context.cc +++ b/src/cpu/inorder/thread_context.cc @@ -262,21 +262,3 @@ InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val) { cpu->setMiscReg(misc_reg, val, thread->readTid()); } - -TheISA::IntReg -InOrderThreadContext::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->readTid()); -} - -void -InOrderThreadContext::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->readTid()); -} - -void -InOrderThreadContext::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->readTid()); -} diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh index 708dcf6b3..dce150b47 100644 --- a/src/cpu/inorder/thread_context.hh +++ b/src/cpu/inorder/thread_context.hh @@ -236,15 +236,6 @@ class InOrderThreadContext : public ThreadContext * misspeculating, this is set as false. */ virtual bool misspeculating() { return false; } - /** Gets a syscall argument by index. */ - virtual IntReg getSyscallArg(int i); - - /** Sets a syscall argument. */ - virtual void setSyscallArg(int i, IntReg val); - - /** Sets the syscall return value. */ - virtual void setSyscallReturn(SyscallReturn return_value); - /** Executes a syscall in SE mode. */ virtual void syscall(int64_t callnum) { return cpu->syscall(callnum, thread->readTid()); } diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 4f6d5d41c..1d7fb97c0 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -420,34 +420,6 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) lockFlag = false; } -#if !FULL_SYSTEM - -template -TheISA::IntReg -FullO3CPU::getSyscallArg(int i, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - TheISA::ArgumentReg[i]); - TheISA::IntReg val = this->readArchIntReg(idx, tid); -#if THE_ISA == SPARC_ISA - if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3)) - val = bits(val, 31, 0); -#endif - return val; -} - -template -void -FullO3CPU::setSyscallArg(int i, TheISA::IntReg val, int tid) -{ - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), - TheISA::ArgumentReg[i]); - this->setArchIntReg(idx, val, tid); -} -#endif - template FullO3CPU::~FullO3CPU() { @@ -1000,13 +972,6 @@ FullO3CPU::syscall(int64_t callnum, int tid) --(this->thread[tid]->funcExeInst); } -template -void -FullO3CPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - TheISA::setSyscallReturn(return_value, this->tcBase(tid)); -} - #endif template diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 683e4284f..f4ed28e8e 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -193,13 +193,6 @@ class FullO3CPU : public BaseO3CPU activateThreadEvent[tid].squash(); } -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, TheISA::IntReg val, int tid); -#endif - /** The tick event used for scheduling CPU ticks. */ ActivateThreadEvent activateThreadEvent[Impl::MaxThreads]; @@ -354,10 +347,6 @@ class FullO3CPU : public BaseO3CPU * @todo: Determine if this needs to be virtual. */ void syscall(int64_t callnum, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); - #endif /** Starts draining the CPU's pipeline of all instructions in diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 6de773ff1..f3058925d 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -247,15 +247,6 @@ class O3ThreadContext : public ThreadContext virtual bool misspeculating() { return false; } #if !FULL_SYSTEM - /** Gets a syscall argument by index. */ - virtual IntReg getSyscallArg(int i); - - /** Sets a syscall argument. */ - virtual void setSyscallArg(int i, IntReg val); - - /** Sets the syscall return value. */ - virtual void setSyscallReturn(SyscallReturn return_value); - /** Executes a syscall in SE mode. */ virtual void syscall(int64_t callnum) { return cpu->syscall(callnum, thread->threadId()); } diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 12b2d1b31..fc8b66b83 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -482,28 +482,3 @@ O3ThreadContext::setMiscReg(int misc_reg, } } -#if !FULL_SYSTEM - -template -TheISA::IntReg -O3ThreadContext::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->threadId()); -} - -template -void -O3ThreadContext::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->threadId()); -} - -template -void -O3ThreadContext::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->threadId()); -} - -#endif // FULL_SYSTEM - diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 0eb4b31f7..054fc1aa1 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -246,22 +246,6 @@ class OzoneCPU : public BaseCPU bool misspeculating() { return false; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - return thread->renameTable[TheISA::ArgumentReg[i]]->readIntResult(); - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - thread->renameTable[TheISA::ArgumentReg[i]]->setIntResult(i); - } - - void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->threadId()); } - Counter readFuncExeInst() { return thread->funcExeInst; } void setFuncExeInst(Counter new_val) @@ -468,7 +452,6 @@ class OzoneCPU : public BaseCPU void processInterrupts(); #else void syscall(uint64_t &callnum); - void setSyscallReturn(SyscallReturn return_value, int tid); #endif ThreadContext *tcBase() { return tc; } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 84ee69464..aa76c8aa6 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -648,26 +648,6 @@ OzoneCPU::syscall(uint64_t &callnum) frontEnd->renameTable.copyFrom(thread.renameTable); backEnd->renameTable.copyFrom(thread.renameTable); } - -template -void -OzoneCPU::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - thread.renameTable[SyscallSuccessReg]->setIntResult(0); - thread.renameTable[ReturnValueReg]->setIntResult( - return_value.value()); - } else { - // got an error, return details - thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1); - thread.renameTable[ReturnValueReg]->setIntResult( - -return_value.value()); - } -} #else template Fault diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 4eba493c3..73929d362 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -34,7 +34,6 @@ #include "arch/isa_traits.hh" #include "arch/regfile.hh" -#include "arch/syscallreturn.hh" #include "arch/tlb.hh" #include "config/full_system.hh" #include "cpu/thread_context.hh" @@ -367,33 +366,6 @@ class SimpleThread : public ThreadState { storeCondFailures = sc_failures; } #if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - assert(i < TheISA::NumArgumentRegs); - TheISA::IntReg val = regs.readIntReg( - TheISA::flattenIntIndex(getTC(), TheISA::ArgumentReg[i])); -#if THE_ISA == SPARC_ISA - if (bits(this->readMiscRegNoEffect( - SparcISA::MISCREG_PSTATE), 3, 3)) { - val = bits(val, 31, 0); - } -#endif - return val; - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - assert(i < TheISA::NumArgumentRegs); - regs.setIntReg(TheISA::flattenIntIndex(getTC(), - TheISA::ArgumentReg[i]), val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, getTC()); - } - void syscall(int64_t callnum) { process->syscall(callnum, tc); diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 7c3f11c12..700f1571e 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -38,7 +38,6 @@ #include "sim/faults.hh" #include "sim/host.hh" #include "sim/serialize.hh" -#include "sim/syscallreturn.hh" #include "sim/byteswap.hh" // @todo: Figure out a more architecture independent way to obtain the ITB and @@ -258,13 +257,6 @@ class ThreadContext virtual bool misspeculating() = 0; #if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i) = 0; - - // used to shift args for indirect syscall - virtual void setSyscallArg(int i, IntReg val) = 0; - - virtual void setSyscallReturn(SyscallReturn return_value) = 0; - // Same with st cond failures. virtual Counter readFuncExeInst() = 0; @@ -457,15 +449,6 @@ class ProxyThreadContext : public ThreadContext bool misspeculating() { return actualTC->misspeculating(); } #if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualTC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualTC->setSyscallReturn(return_value); } - void syscall(int64_t callnum) { actualTC->syscall(callnum); } -- cgit v1.2.3 From 9ee8e685a46ccd5314b93fec178cd73957c5b406 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Wed, 4 Mar 2009 09:25:53 -0500 Subject: O3: Make numThreads error message more helpful. --- src/cpu/o3/fetch_impl.hh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 06df46c2b..79a4f2b7a 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -132,7 +132,9 @@ DefaultFetch::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) switchedOut(false) { if (numThreads > Impl::MaxThreads) - fatal("numThreads is not a valid value\n"); + fatal("numThreads (%d) is larger than compiled limit (%d),\n" + "\tincrease MaxThreads in src/cpu/o3/impl.hh\n", + numThreads, static_cast(Impl::MaxThreads)); // Set fetch stage's status to inactive. _status = Inactive; -- cgit v1.2.3 From e4aa4ca40c0a5ab5946914cc997e0a9bd288c861 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:16:48 -0500 Subject: use numCycles instead of simTicks to determine CPI stat in InOrder --- src/cpu/inorder/cpu.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index c22dd1154..94a6efce9 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -355,7 +355,7 @@ InOrderCPU::regStats() .name(name() + ".cpi_total") .desc("CPI: Total CPI of All Threads") .precision(6); - totalCpi = simTicks / totalCommittedInsts; + totalCpi = numCycles / totalCommittedInsts; ipc .name(name() + ".ipc") @@ -373,7 +373,7 @@ InOrderCPU::regStats() .name(name() + ".ipc_total") .desc("IPC: Total IPC of All Threads") .precision(6); - totalIpc = totalCommittedInsts / simTicks; + totalIpc = totalCommittedInsts / numCycles; BaseCPU::regStats(); } -- cgit v1.2.3 From 846f953c2bc8f9922afe62c30e60f9b5b531d09e Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:16:49 -0500 Subject: Give TimeBuffer an ID that can be set. Necessary because InOrder uses generic stages so w/o an ID there is no way to differentiate buffers when debugging --- src/cpu/inorder/cpu.cc | 4 +--- src/cpu/inorder/pipeline_stage.cc | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 94a6efce9..1836989af 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -230,11 +230,9 @@ InOrderCPU::InOrderCPU(Params *params) } // Initialize TimeBuffer Stage Queues - // For now just have these time buffers be pretty big. - // @note: This could be statically allocated but changes - // would have to be made to the standard time buffer class. for (int stNum=0; stNum < NumStages - 1; stNum++) { stageQueue[stNum] = new StageQueue(NumStages, NumStages); + stageQueue[stNum]->id(stNum); } diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 547b42537..f356c0e1a 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -556,8 +556,8 @@ PipelineStage::sortInsts() if (prevStageValid) { int insts_from_prev_stage = prevStage->size; - DPRINTF(InOrderStage, "%i insts available from previous stage.\n", - insts_from_prev_stage); + DPRINTF(InOrderStage, "%i insts available from stage buffer %i.\n", + insts_from_prev_stage, prevStageQueue->id()); for (int i = 0; i < insts_from_prev_stage; ++i) { @@ -985,8 +985,9 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " - "index %i stage %i queue.\n", - tid, inst->seqNum, toNextStageIndex, inst->nextStage); + "index %i of stage buffer %i queue.\n", + tid, inst->seqNum, toNextStageIndex, + cpu->pipelineStage[prev_stage]->nextStageQueue->id()); int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size; -- cgit v1.2.3 From f98e9161a83cd9bafbe7e5612db344a8b5cb2ae1 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:17:05 -0500 Subject: InOrder didnt have all it's params set to a default value, which is now required for M5 objects; Also, a # of values need to be reset to 0 (or the appropriate value) before we assume they are OK for use. --- src/cpu/inorder/InOrderCPU.py | 5 ++--- src/cpu/inorder/comm.hh | 8 ++++++++ src/cpu/inorder/inorder_dyn_inst.cc | 5 ++++- src/cpu/inorder/pipeline_stage.cc | 32 +++++------------------------- src/cpu/inorder/resources/mult_div_unit.cc | 5 +++++ 5 files changed, 24 insertions(+), 31 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py index a5e81a090..9faadc68c 100644 --- a/src/cpu/inorder/InOrderCPU.py +++ b/src/cpu/inorder/InOrderCPU.py @@ -34,9 +34,8 @@ from BaseCPU import BaseCPU class InOrderCPU(BaseCPU): type = 'InOrderCPU' activity = Param.Unsigned(0, "Initial count") - numThreads = Param.Unsigned(1, "number of HW thread contexts") - cachePorts = Param.Unsigned("Cache Ports") + cachePorts = Param.Unsigned(2, "Cache Ports") stageWidth = Param.Unsigned(1, "Stage width") fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from") @@ -66,7 +65,7 @@ class InOrderCPU(BaseCPU): functionTraceStart = Param.Tick(0, "Cycle to start function trace") stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU") - memBlockSize = Param.Unsigned("Memory Block Size") + memBlockSize = Param.Unsigned(64, "Memory Block Size") multLatency = Param.Unsigned(1, "Latency for Multiply Operations") multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations") diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh index c687a9ab4..18bb24169 100644 --- a/src/cpu/inorder/comm.hh +++ b/src/cpu/inorder/comm.hh @@ -53,6 +53,14 @@ struct InterStageStruct { uint64_t nextPC; InstSeqNum squashedSeqNum; bool includeSquashInst; + + InterStageStruct() + :size(0), squash(false), + branchMispredict(false), branchTaken(false), + mispredPC(0), nextPC(0), + squashedSeqNum(0), includeSquashInst(false) + { } + }; /** Turn This into a Class */ diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index 3a45bd01e..e5fac7141 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -84,7 +84,10 @@ InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst) InOrderDynInst::InOrderDynInst() : traceData(NULL), cpu(cpu) -{ initVars(); } +{ + seqNum = 0; + initVars(); +} int InOrderDynInst::instcount = 0; diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index f356c0e1a..4ded50bf0 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -38,35 +38,10 @@ using namespace std; using namespace ThePipeline; PipelineStage::PipelineStage(Params *params, unsigned stage_num) - : numThreads(ThePipeline::MaxThreads) { - stageNum = stage_num; - stageWidth = ThePipeline::StageWidth; - - _status = Inactive; - - prevStageValid = false; - nextStageValid = false; - - // Init. structures - for(int tid=0; tid < numThreads; tid++) { - stageStatus[tid] = Idle; - - for (int stNum = 0; stNum < NumStages; stNum++) { - stalls[tid].stage[stNum] = false; - } - stalls[tid].resources.clear(); - - if (stageNum < BackEndStartStage) - lastStallingStage[tid] = BackEndStartStage - 1; - else - lastStallingStage[tid] = NumStages - 1; - } - - stageBufferMax = ThePipeline::interStageBuffSize[stage_num]; + init(params, stage_num); } - void PipelineStage::init(Params *params, unsigned stage_num) { @@ -189,7 +164,7 @@ PipelineStage::setNextStageQueue(TimeBuffer *next_stage_ptr) // Setup wire to write information to proper place in stage queue. nextStage = nextStageQueue->getWire(0); - + nextStage->size = 0; nextStageValid = true; } @@ -682,6 +657,9 @@ PipelineStage::tick() bool status_change = false; + if (nextStageValid) + nextStage->size = 0; + toNextStageIndex = 0; sortInsts(); diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc index abef11247..e98e97be7 100644 --- a/src/cpu/inorder/resources/mult_div_unit.cc +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -57,6 +57,8 @@ MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, div32RepeatRate = params->div32RepeatRate; div32Latency = params->div32Latency; + + lastMDUCycle = 0; } void @@ -150,6 +152,9 @@ MultDivUnit::getSlot(DynInstPtr inst) rval); if (rval != -1) { + lastMDUCycle = curTick; + lastOpType = inst->opClass(); + lastInstName = inst->staticInst->getName(); } return rval; -- cgit v1.2.3 From f69b018571a6396d0e679d4d0eceb47ef4496530 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:17:07 -0500 Subject: make handling of interstage buffers (i.e. StageQueues) more consistent: (1)number from 0-n, not 1-n+1, (2) always check nextStageValid before a stageNum+1 and prevStageValid for a stageNum-1 reference (3) add skidSize() to get StageQueue size for all threads --- src/cpu/inorder/cpu.cc | 4 +- src/cpu/inorder/first_stage.cc | 2 +- src/cpu/inorder/pipeline_stage.cc | 85 +++++++++++++++++++++++++-------------- src/cpu/inorder/pipeline_stage.hh | 5 ++- 4 files changed, 62 insertions(+), 34 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 1836989af..9c957487d 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -250,8 +250,8 @@ InOrderCPU::InOrderCPU(Params *params) // Take Care of 1st/Nth stages if (stNum > 0) pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]); - if (stNum < NumStages - 2) - pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum + 1]); + if (stNum < NumStages - 1) + pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]); } // Initialize thread specific variables diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc index ce30f8466..be4431a03 100644 --- a/src/cpu/inorder/first_stage.cc +++ b/src/cpu/inorder/first_stage.cc @@ -127,7 +127,7 @@ FirstStage::processInsts(unsigned tid) { bool all_reqs_completed = true; - for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToNextStage(); insts_fetched++) { + for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) { DynInstPtr inst; bool new_inst = false; diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 4ded50bf0..1c8da2b13 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -229,7 +229,7 @@ PipelineStage::checkStall(unsigned tid) const bool ret_val = false; // Only check pipeline stall from stage directly following this stage - if (stalls[tid].stage[stageNum + 1]) { + if (nextStageValid && stalls[tid].stage[stageNum + 1]) { DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n", tid, stageNum + 1); ret_val = true; @@ -422,26 +422,28 @@ PipelineStage::stageBufferAvail() } int incoming_insts = (prevStageValid) ? - cpu->pipelineStage[stageNum-1]->nextStage->size : + cpu->pipelineStage[stageNum]->prevStage->size : 0; - int avail = stageBufferMax - total - incoming_insts; + int avail = stageBufferMax - total -0;// incoming_insts; - assert(avail >= 0); + if (avail < 0) + fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i", + stageNum, stageBufferMax, total, incoming_insts, avail); return avail; } bool -PipelineStage::canSendInstToNextStage() +PipelineStage::canSendInstToStage(unsigned stage_num) { bool buffer_avail = false; - if (nextStageValid) { - buffer_avail = (cpu->pipelineStage[stageNum+1]->stageBufferAvail() >= 1); + if (cpu->pipelineStage[stage_num]->prevStageValid) { + buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() >= 1; } - if (!buffer_avail && nextStageValid) { + if (!buffer_avail && nextStageQueueValid(stage_num)) { DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1); } @@ -468,6 +470,17 @@ PipelineStage::skidInsert(unsigned tid) } +int +PipelineStage::skidSize() +{ + int total = 0; + + for (int i=0; i < ThePipeline::MaxThreads; i++) { + total += skidBuffer[i].size(); + } + + return total; +} bool PipelineStage::skidsEmpty() @@ -743,8 +756,11 @@ PipelineStage::processStage(bool &status_change) nextStage->size, stageNum + 1); } - DPRINTF(InOrderStage, "%i insts left in stage buffer.\n", stageBufferMax - stageBufferAvail()); + DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(), + stageNum); + DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(), + stageNum); } void @@ -814,14 +830,10 @@ PipelineStage::processInsts(unsigned tid) int insts_processed = 0; - DPRINTF(InOrderStage, "[tid:%u]: Sending instructions to stage %u.\n", tid, - stageNum+1); - - //Keep processing instructions while ... these ?s are true: - while (insts_available > 0 && //1. are there instructions to process - insts_processed < stageWidth && //2. can the stage still process this - (canSendInstToNextStage() || !nextStageValid) && //3. is there room in next stage - last_req_completed) { //4. was the last instruction completed + while (insts_available > 0 && + insts_processed < stageWidth && + (!nextStageValid || canSendInstToStage(stageNum+1)) && + last_req_completed) { assert(!insts_to_stage.empty()); inst = insts_to_stage.front(); @@ -847,23 +859,21 @@ PipelineStage::processInsts(unsigned tid) last_req_completed = processInstSchedule(inst); - - insts_processed++; - // Don't let instruction pass to next stage if it hasnt completed // all of it's requests for this stage. if (!last_req_completed && !outOfOrderValid()) continue; - insts_to_stage.pop(); - - DPRINTF(InOrderStage, "Marking [tid:%i] [sn:%i] for insertion into next stage buffer.\n", - tid, inst->seqNum); - // Send to Next Stage or Break Loop - if (!sendInstToNextStage(inst)) - break;; + if (nextStageValid && !sendInstToNextStage(inst)) { + DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n", + tid, inst->seqNum,inst->nextStage); + break; + } + insts_processed++; + + insts_to_stage.pop(); //++stageProcessedInsts; --insts_available; @@ -871,8 +881,6 @@ PipelineStage::processInsts(unsigned tid) // If we didn't process all instructions, then we will need to block // and put all those instructions into the skid buffer. - // @TODO:-IN-PROGRESS-:Evaluating when stages should block/unblock - // for stage stalls... if (!insts_to_stage.empty()) { blockDueToBuffer(tid); } @@ -945,6 +953,8 @@ bool PipelineStage::sendInstToNextStage(DynInstPtr inst) { // Update Next Stage Variable in Instruction + // NOTE: Some Resources will update this nextStage var. to + // for bypassing, so can't always assume nextStage=stageNum+1 if (inst->nextStage == stageNum) inst->nextStage++; @@ -953,14 +963,29 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) int next_stage = inst->nextStage; int prev_stage = next_stage - 1; + assert(next_stage >= 1); + assert(prev_stage >= 0); + + DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid, + stageNum+1); + + if (!canSendInstToStage(inst->nextStage)) { + DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid, + stageNum+1); + return false; + } + + if (nextStageQueueValid(inst->nextStage - 1)) { if (inst->seqNum > cpu->squashSeqNum[tid] && curTick == cpu->lastSquashCycle[tid]) { DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion " "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage); } else { - DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", + if (nextStageValid) { + DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n", tid, cpu->pipelineStage[next_stage]->stageBufferAvail()); + } DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into " "index %i of stage buffer %i queue.\n", diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 833547704..17ca32595 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -184,7 +184,7 @@ class PipelineStage virtual bool processInstSchedule(DynInstPtr inst); /** Is there room in the next stage buffer for this instruction? */ - virtual bool canSendInstToNextStage(); + virtual bool canSendInstToStage(unsigned stage_num); /** Send an instruction to the next stage buffer */ virtual bool sendInstToNextStage(DynInstPtr inst); @@ -194,6 +194,9 @@ class PipelineStage */ virtual void skidInsert(unsigned tid); + /** Total size of all skid buffers */ + int skidSize(); + /** Returns if all of the skid buffers are empty. */ bool skidsEmpty(); -- cgit v1.2.3 From 30cd2d21fad6c12e2540672f315f561c9a1643ec Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:17:08 -0500 Subject: Remove unused functions/comments cluttering up the code. --- src/cpu/inorder/SConscript | 2 +- src/cpu/inorder/cpu.cc | 45 ++----------------------- src/cpu/inorder/cpu.hh | 25 ++------------ src/cpu/inorder/inorder_cpu_builder.cc | 1 - src/cpu/inorder/inorder_dyn_inst.cc | 59 ++------------------------------- src/cpu/inorder/inorder_dyn_inst.hh | 4 --- src/cpu/inorder/params.hh | 2 +- src/cpu/inorder/pipeline_stage.cc | 13 ++------ src/cpu/inorder/pipeline_stage.hh | 3 -- src/cpu/inorder/pipeline_traits.hh | 7 ---- src/cpu/inorder/resource.hh | 3 -- src/cpu/inorder/resources/cache_unit.cc | 6 ++-- src/cpu/inorder/thread_context.hh | 3 -- 13 files changed, 14 insertions(+), 159 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript index dc5ff6f46..a987c4e05 100644 --- a/src/cpu/inorder/SConscript +++ b/src/cpu/inorder/SConscript @@ -47,7 +47,7 @@ if 'InOrderCPU' in env['CPU_MODELS']: TraceFlag('RefCount') CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', - 'InOrderMDU', 'RegDepMap', 'Resource']) + 'InOrderMDU', 'InOrderCachePort', 'RegDepMap', 'Resource']) Source('pipeline_traits.cc') Source('inorder_dyn_inst.cc') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 9c957487d..7dafd826f 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -46,7 +46,6 @@ #include "cpu/inorder/resource_pool.hh" #include "mem/translating_port.hh" #include "sim/process.hh" -//#include "sim/root.hh" #include "sim/stat_control.hh" #include @@ -162,7 +161,6 @@ InOrderCPU::InOrderCPU(Params *params) cpu_params = params; resPool = new ResourcePool(this, params); -// resPool->init(); coreType = "default"; // eventually get this from params @@ -191,13 +189,9 @@ InOrderCPU::InOrderCPU(Params *params) } - /* Use this port to for syscall emulation writes to memory. */ - //Port *mem_port = NULL; - //TranslatingPort *trans_port = NULL; - for (int i = 0; i < numThreads; ++i) { if (i < params->workload.size()) { - DPRINTF(InOrderCPU, "Workload[%i] process is %#x", + DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n", i, this->thread[i]); this->thread[i] = new Thread(this, i, params->workload[i], i); @@ -208,11 +202,8 @@ InOrderCPU::InOrderCPU(Params *params) } else { //Allocate Empty thread so M5 can use later //when scheduling threads to CPU - Process* dummy_proc = params->workload[0]; //LiveProcess::createDummy(); + Process* dummy_proc = params->workload[0]; this->thread[i] = new Thread(this, i, dummy_proc, i); - - // Set Up Syscall Emulation Port - //this->thread[i]->setMemPort(trans_port); } // Setup the TC that will serve as the interface to the threads/CPU. @@ -790,8 +781,6 @@ InOrderCPU::deallocateThread(unsigned tid) { DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid); - //removeThread(tid); - removeFromCurrentThreads(tid); deactivateThread(tid); @@ -840,19 +829,6 @@ InOrderCPU::activateWhenReady(int tid) } -void -InOrderCPU::signalSwitched() -{ - panic("Unimplemented Function\n."); -} - - -void -InOrderCPU::takeOverFrom(BaseCPU *oldCPU) -{ - panic("Take Over From Another CPU\n."); -} - uint64_t InOrderCPU::readPC(unsigned tid) { @@ -1205,14 +1181,6 @@ InOrderCPU::cleanUpRemovedEvents() } } -/* - -void -InOrderCPU::removeAllInsts() -{ - instList.clear(); -} -*/ void InOrderCPU::dumpInsts() @@ -1233,14 +1201,6 @@ InOrderCPU::dumpInsts() ++num; } } -/* - -void -InOrderCPU::wakeDependents(DynInstPtr &inst) -{ - iew.wakeDependents(inst); -} -*/ void InOrderCPU::wakeCPU() @@ -1252,6 +1212,7 @@ InOrderCPU::wakeCPU() DPRINTF(Activity, "Waking up CPU\n"); + //@todo: figure out how to count idleCycles correctly //idleCycles += (curTick - 1) - lastRunningCycle; mainEventQueue.schedule(&tickEvent, curTick); diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index e27687a72..36c90a0e9 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -249,9 +249,6 @@ class InOrderCPU : public BaseCPU TheISA::IntReg nextNPC[ThePipeline::MaxThreads]; /** The Register File for the CPU */ - /** @TODO: This regFile wont be a sufficient solution for out-of-order, add register - * files as a resource in order to handle ths problem - */ TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];; TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];; TheISA::MiscRegFile miscRegFile; @@ -362,15 +359,6 @@ class InOrderCPU : public BaseCPU void switchToActive(int stage_idx) { /*pipelineStage[stage_idx]->switchToActive();*/ } - /** Switches out this CPU. (Unused currently) */ - //void switchOut(Sampler *sampler); - - /** Signals to this CPU that a stage has completed switching out. (Unused currently)*/ - void signalSwitched(); - - /** Takes over from another CPU. (Unused currently)*/ - void takeOverFrom(BaseCPU *oldCPU); - /** Get the current instruction sequence number, and increment it. */ InstSeqNum getAndIncrementInstSeq(unsigned tid) { return globalSeqNum[tid]++; } @@ -389,6 +377,7 @@ class InOrderCPU : public BaseCPU globalSeqNum[tid] = seq_num; } + /** Get & Update Next Event Number */ InstSeqNum getNextEventNum() { return cpuEventNum++; @@ -463,9 +452,6 @@ class InOrderCPU : public BaseCPU /** Sets the next NPC of a specific thread. */ void setNextNPC(uint64_t val, unsigned tid); - /** Add Destination Register To Dependency Maps */ - //void addToRegDepMap(DynInstPtr &inst); - /** Function to add instruction onto the head of the list of the * instructions. Used when new instructions are fetched. */ @@ -530,13 +516,6 @@ class InOrderCPU : public BaseCPU */ std::queue cpuEventRemoveList; -#ifdef DEBUG - /** Debug structure to keep track of the sequence numbers still in - * flight. - */ - std::set snList; -#endif - /** Records if instructions need to be removed this cycle due to * being retired or squashed. */ @@ -610,7 +589,6 @@ class InOrderCPU : public BaseCPU unsigned readStCondFailures() { return stCondFails; } unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; } - public: /** Returns a pointer to a thread context. */ ThreadContext *tcBase(unsigned tid = 0) { @@ -631,6 +609,7 @@ class InOrderCPU : public BaseCPU /** Pointer to the icache interface. */ MemInterface *icacheInterface; + /** Pointer to the dcache interface. */ MemInterface *dcacheInterface; diff --git a/src/cpu/inorder/inorder_cpu_builder.cc b/src/cpu/inorder/inorder_cpu_builder.cc index b1b4bea80..0088a3bd9 100644 --- a/src/cpu/inorder/inorder_cpu_builder.cc +++ b/src/cpu/inorder/inorder_cpu_builder.cc @@ -35,7 +35,6 @@ #include "cpu/inst_seq.hh" #include "cpu/static_inst.hh" #include "cpu/inorder/cpu.hh" -//#include "cpu/inorder/params.hh" #include "cpu/inorder/inorder_dyn_inst.hh" #include "cpu/inorder/pipeline_traits.hh" #include "params/InOrderCPU.hh" diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index e5fac7141..d292d72f0 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -167,10 +167,6 @@ InOrderDynInst::initVars() DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n", threadNumber, seqNum, instcount); - -#ifdef DEBUG - cpu->snList.insert(seqNum); -#endif } @@ -192,9 +188,6 @@ InOrderDynInst::~InOrderDynInst() DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n", threadNumber, seqNum, instcount); -#ifdef DEBUG - cpu->snList.erase(seqNum); -#endif } void @@ -305,44 +298,13 @@ InOrderDynInst::syscall(int64_t callnum) void InOrderDynInst::prefetch(Addr addr, unsigned flags) { - // This is the "functional" implementation of prefetch. Not much - // happens here since prefetches don't affect the architectural - // state. -/* - // Generate a MemReq so we can translate the effective address. - MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); - req->asid = asid; - - // Prefetches never cause faults. - fault = NoFault; - - // note this is a local, not InOrderDynInst::fault - Fault trans_fault = cpu->translateDataReadReq(req); - - if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { - // It's a valid address to cacheable space. Record key MemReq - // parameters so we can generate another one just like it for - // the timing access without calling translate() again (which - // might mess up the TLB). - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - } else { - // Bogus address (invalid or uncacheable space). Mark it by - // setting the eff_addr to InvalidAddr. - effAddr = physEffAddr = MemReq::inval_addr; - } - - if (traceData) { - traceData->setAddr(addr); - } -*/ + panic("Prefetch Unimplemented\n"); } void InOrderDynInst::writeHint(Addr addr, int size, unsigned flags) { - // Not currently supported. + panic("Write-Hint Unimplemented\n"); } /** @@ -762,20 +724,3 @@ my_hash_t; my_hash_t thishash; #endif - -#ifdef DEBUG - -void -InOrderDynInst::dumpSNList() -{ - std::set::iterator sn_it = cpu->snList.begin(); - - int count = 0; - while (sn_it != cpu->snList.end()) { - cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it)); - count++; - sn_it++; - } -} -#endif - diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh index 9f52f954f..55c61ffb9 100644 --- a/src/cpu/inorder/inorder_dyn_inst.hh +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -957,10 +957,6 @@ class InOrderDynInst : public FastAlloc, public RefCounted /** Count of total number of dynamic instructions. */ static int instcount; -#ifdef DEBUG - void dumpSNList(); -#endif - /** Dumps out contents of this BaseDynInst. */ void dump(); diff --git a/src/cpu/inorder/params.hh b/src/cpu/inorder/params.hh index 67f8f47f0..51b7409ad 100644 --- a/src/cpu/inorder/params.hh +++ b/src/cpu/inorder/params.hh @@ -121,4 +121,4 @@ class InOrderParams : public BaseCPU::Params }; -#endif // __CPU_O3_CPU_INORDER_PARAMS_HH__ +#endif // _CPU_INORDER_PARAMS_HH__ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 1c8da2b13..ab7328f4a 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -193,7 +193,7 @@ void PipelineStage::switchOut() { // Stage can immediately switch out. - cpu->signalSwitched(); + panic("Switching Out of Stages Unimplemented"); } @@ -691,13 +691,6 @@ PipelineStage::tick() DPRINTF(InOrderStage, "\n\n"); } -bool -PipelineStage::outOfOrderValid() -{ - //@TODO: Define this function when OOO is valid - return false; -} - void PipelineStage::setResStall(ResReqPtr res_req, unsigned tid) { @@ -861,7 +854,7 @@ PipelineStage::processInsts(unsigned tid) // Don't let instruction pass to next stage if it hasnt completed // all of it's requests for this stage. - if (!last_req_completed && !outOfOrderValid()) + if (!last_req_completed) continue; // Send to Next Stage or Break Loop @@ -1018,7 +1011,7 @@ PipelineStage::sendInstToNextStage(DynInstPtr inst) void PipelineStage::dumpInsts() { - std::cerr << "Insts in Stage " << stageNum << " skidbuffers:" << endl; + cprintf("Insts in Stage %i skidbuffers\n",stageNum); for (int tid=0; tid < ThePipeline::MaxThreads; tid++) { diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 17ca32595..19bf8154f 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -147,9 +147,6 @@ class PipelineStage */ virtual void tick(); - /** Is out of order processing valid? */ - bool outOfOrderValid(); - /** Set a resource stall in the pipeline-stage */ void setResStall(ResReqPtr res_req, unsigned tid); diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh index c5e4bb228..3c49143bc 100644 --- a/src/cpu/inorder/pipeline_traits.hh +++ b/src/cpu/inorder/pipeline_traits.hh @@ -38,7 +38,6 @@ #include "arch/isa_traits.hh" #include "cpu/base.hh" -//#include "cpu/inorder/params.hh" #include "params/InOrderCPU.hh" @@ -122,12 +121,6 @@ namespace ThePipeline { if (lhs->stageNum > rhs->stageNum) { return true; } else if (lhs->stageNum == rhs->stageNum) { - /*if (lhs->resNum > rhs->resNum) { - return true; - } else { - return false; - }*/ - if (lhs->priority > rhs->priority) { return true; } else { diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index e3536258d..9b9e3c3dc 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -79,9 +79,6 @@ class Resource { virtual void init(); virtual void initSlots(); - /** Tasks to perform when simulation starts */ - //virtual void startup() { } - /** Register Stats for this resource */ virtual void regStats(); diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 6b62c864a..6fd7ae36c 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -454,12 +454,10 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) findRequest(cache_pkt->cacheReq->getInst())); assert(cache_req); -#if TRACING_ON + // Get resource request info + // @todo: SMT needs to figure out where to get thread # from. unsigned tid = 0; -#endif - - //tid = pkt->req->getThreadNum(); unsigned stage_num = cache_req->getStageNum(); DynInstPtr inst = cache_req->inst; diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh index dce150b47..8b3b47290 100644 --- a/src/cpu/inorder/thread_context.hh +++ b/src/cpu/inorder/thread_context.hh @@ -111,9 +111,6 @@ class InOrderThreadContext : public ThreadContext virtual void setStatus(Status new_status) { thread->setStatus(new_status); } - /** Returns a pointer to the last graduated/committed instruction in the thread */ - //DynInstPtr getLastGradInst() { return thread->getLastGradInst(); } - /** Set the status to Active. Optional delay indicates number of * cycles to wait before beginning execution. */ virtual void activate(int delay = 1); -- cgit v1.2.3 From 7c8d54421665ccbc204487cb6a9faa31c1b3c243 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 13:17:09 -0500 Subject: Give each resource in InOrder it's own TraceFlag instead of just standard 'Resource' flag --- src/cpu/inorder/SConscript | 17 +++++++++-- src/cpu/inorder/resources/agen_unit.cc | 8 ++--- src/cpu/inorder/resources/branch_predictor.cc | 10 +++---- src/cpu/inorder/resources/branch_predictor.hh | 1 - src/cpu/inorder/resources/decode_unit.cc | 4 +-- src/cpu/inorder/resources/execution_unit.cc | 16 +++++----- src/cpu/inorder/resources/fetch_seq_unit.cc | 28 +++++++++--------- src/cpu/inorder/resources/graduation_unit.cc | 6 ++-- src/cpu/inorder/resources/inst_buffer.cc | 20 ++++++------- src/cpu/inorder/resources/tlb_unit.cc | 12 ++++---- src/cpu/inorder/resources/use_def.cc | 42 +++++++++++++-------------- 11 files changed, 87 insertions(+), 77 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript index a987c4e05..af237a777 100644 --- a/src/cpu/inorder/SConscript +++ b/src/cpu/inorder/SConscript @@ -36,18 +36,29 @@ if 'InOrderCPU' in env['CPU_MODELS']: TraceFlag('ResReqCount') TraceFlag('FreeList') - TraceFlag('InOrderCachePort') TraceFlag('InOrderStage') TraceFlag('InOrderStall') TraceFlag('InOrderCPU') - TraceFlag('InOrderMDU') TraceFlag('RegDepMap') TraceFlag('InOrderDynInst') TraceFlag('Resource') + TraceFlag('InOrderAGEN') + TraceFlag('InOrderFetchSeq') + TraceFlag('InOrderTLB') + TraceFlag('InOrderCachePort') + TraceFlag('InOrderBPred') + TraceFlag('InOrderDecode') + TraceFlag('InOrderExecute') + TraceFlag('InOrderInstBuffer') + TraceFlag('InOrderUseDef') + TraceFlag('InOrderMDU') + TraceFlag('InOrderGraduation') TraceFlag('RefCount') CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', - 'InOrderMDU', 'InOrderCachePort', 'RegDepMap', 'Resource']) + 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred', + 'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef', + 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource']) Source('pipeline_traits.cc') Source('inorder_dyn_inst.cc') diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc index 8e3d25656..f462b12ea 100644 --- a/src/cpu/inorder/resources/agen_unit.cc +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -54,7 +54,7 @@ AGENUnit::execute(int slot_num) { // Load/Store Instruction if (inst->isMemRef()) { - DPRINTF(Resource, "[tid:%i] Generating Address for [sn:%i] (%s).\n", + DPRINTF(InOrderAGEN, "[tid:%i] Generating Address for [sn:%i] (%s).\n", tid, inst->seqNum, inst->staticInst->getName()); @@ -67,13 +67,13 @@ AGENUnit::execute(int slot_num) inst->setMemAddr(inst->getEA()); //inst->setExecuted(); - DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: " + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " "%#x.\n", tid, inst->seqNum, inst->getEA()); } else if (inst->isStore()) { fault = inst->calcEA(); inst->setMemAddr(inst->getEA()); - DPRINTF(Resource, "[tid:%i] [sn:%i] Effective address calculated to be: " + DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: " "%#x.\n", tid, inst->seqNum, inst->getEA()); } else { panic("Unexpected memory type!\n"); @@ -86,7 +86,7 @@ AGENUnit::execute(int slot_num) } } } else { - DPRINTF(Resource, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num); + DPRINTF(InOrderAGEN, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num); agen_req->done(); } } diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc index b563a3057..511a0ac82 100644 --- a/src/cpu/inorder/resources/branch_predictor.cc +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -90,7 +90,7 @@ BranchPredictor::execute(int slot_num) predictedTaken++; } else { - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted false.\n", + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n", tid, seq_num); if (inst->isCondDelaySlot()) @@ -105,11 +105,11 @@ BranchPredictor::execute(int slot_num) inst->setBranchPred(predict_taken); - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n", + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n", tid, seq_num, pred_PC); } else { - DPRINTF(Resource, "[tid:%i]: Ignoring [sn:%i] because this isn't " + DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't " "a control instruction.\n", tid, seq_num); } @@ -119,7 +119,7 @@ BranchPredictor::execute(int slot_num) case UpdatePredictor: { - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n", + DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n", tid, seq_num); @@ -138,7 +138,7 @@ void BranchPredictor::squash(DynInstPtr inst, int squash_stage, InstSeqNum squash_seq_num, unsigned tid) { - DPRINTF(Resource, "Squashing...\n"); + DPRINTF(InOrderBPred, "Squashing...\n"); branchPred.squash(squash_seq_num, tid); } diff --git a/src/cpu/inorder/resources/branch_predictor.hh b/src/cpu/inorder/resources/branch_predictor.hh index 66eb1afe8..57745343c 100644 --- a/src/cpu/inorder/resources/branch_predictor.hh +++ b/src/cpu/inorder/resources/branch_predictor.hh @@ -41,7 +41,6 @@ #include "cpu/inorder/pipeline_traits.hh" #include "cpu/inorder/resources/bpred_unit.hh" #include "cpu/inorder/cpu.hh" -//#include "cpu/inorder/params.hh" class BranchPredictor : public Resource { public: diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc index 1628c32d0..d95b1d4bb 100644 --- a/src/cpu/inorder/resources/decode_unit.cc +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -63,7 +63,7 @@ DecodeUnit::execute(int slot_num) bool done_sked = ThePipeline::createBackEndSchedule(inst); if (done_sked) { - DPRINTF(Resource, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", + DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", tid, seq_num); regDepMap[tid]->insert(inst); decode_req->done(); @@ -85,7 +85,7 @@ DecodeUnit::execute(int slot_num) void DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) { - DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n", + DPRINTF(InOrderDecode, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n", tid, stage_num, squash_seq_num); //cpu->removeInstsUntil(squash_seq_num, tid); diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc index e41291103..843adb5b0 100644 --- a/src/cpu/inorder/resources/execution_unit.cc +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -68,7 +68,7 @@ ExecutionUnit::execute(int slot_num) exec_req->fault = NoFault; - DPRINTF(Resource, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n", + DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n", tid, seq_num, inst->readPC()); switch (exec_req->cmd) @@ -99,7 +99,7 @@ ExecutionUnit::execute(int slot_num) inst->bdelaySeqNum = seq_num; inst->setPredTarg(inst->nextPC); - DPRINTF(Resource, "[tid:%i]: Conditional branch inst" + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst" "[sn:%i] PC %#x mispredicted as taken.\n", tid, seq_num, inst->PC); } else if (!inst->predTaken() && inst->isCondDelaySlot()) { @@ -107,13 +107,13 @@ ExecutionUnit::execute(int slot_num) inst->setPredTarg(inst->nextPC); inst->procDelaySlotOnMispred = true; - DPRINTF(Resource, "[tid:%i]: Conditional branch inst." + DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst." "[sn:%i] PC %#x mispredicted as not taken.\n", tid, seq_num, inst->PC); } else { inst->bdelaySeqNum = seq_num + 1; - DPRINTF(Resource, "[tid:%i]: Misprediction detected at " + DPRINTF(InOrderExecute, "[tid:%i]: Misprediction detected at " "[sn:%i] PC %#x,\n\t squashing after delay slot " "instruction [sn:%i].\n", tid, seq_num, inst->PC, inst->bdelaySeqNum); @@ -122,20 +122,20 @@ ExecutionUnit::execute(int slot_num) inst->setPredTarg(inst->nextNPC); } - DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid, + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, inst->readPredTarg()); } else if(inst->isIndirectCtrl()){ inst->setPredTarg(inst->nextNPC); inst->bdelaySeqNum = seq_num + 1; - DPRINTF(Resource, "[tid:%i] Redirecting fetch to %#x.\n", tid, + DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid, inst->readPredTarg()); } else { panic("Non-control instruction (%s) mispredicting?!!", inst->staticInst->getName()); } - DPRINTF(Resource, "[tid:%i] Squashing will start from stage %i.\n", + DPRINTF(InOrderExecute, "[tid:%i] Squashing will start from stage %i.\n", tid, stage_num); cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid); @@ -164,7 +164,7 @@ ExecutionUnit::execute(int slot_num) inst->setExecuted(); exec_req->done(); - DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", + DPRINTF(InOrderExecute, "[tid:%i]: The result of execution is 0x%x.\n", inst->readTid(), inst->readIntResult(0)); } else { warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index 00f76f74b..36cf714c9 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -90,7 +90,7 @@ FetchSeqUnit::execute(int slot_num) delaySlotInfo[tid].targetReady = false; - DPRINTF(Resource, "[tid:%i]: Setting PC to delay slot target\n",tid); + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to delay slot target\n",tid); } inst->setPC(PC[tid]); @@ -102,7 +102,7 @@ FetchSeqUnit::execute(int slot_num) inst->setMemAddr(PC[tid]); inst->setSeqNum(cpu->getAndIncrementInstSeq(tid)); - DPRINTF(Resource, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid, + DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid, inst->seqNum, inst->readPC()); if (delaySlotInfo[tid].numInsts > 0) { @@ -113,7 +113,7 @@ FetchSeqUnit::execute(int slot_num) delaySlotInfo[tid].targetReady = true; } - DPRINTF(Resource, "[tid:%i]: %i delay slot inst(s) left to" + DPRINTF(InOrderFetchSeq, "[tid:%i]: %i delay slot inst(s) left to" " process.\n", tid, delaySlotInfo[tid].numInsts); } @@ -139,11 +139,11 @@ FetchSeqUnit::execute(int slot_num) pcBlockStage[tid] = stage_num; } else if (inst->isCondDelaySlot() && !inst->predTaken()) { // Not-Taken AND Conditional Control - DPRINTF(Resource, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. " + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. " "Delay inst. Skipping delay slot and Updating PC to %08p\n", tid, inst->seqNum, inst->readPC(), inst->readPredTarg()); - DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", tid, stage_num, seq_num); inst->bdelaySeqNum = seq_num; @@ -152,7 +152,7 @@ FetchSeqUnit::execute(int slot_num) squashAfterInst(inst, stage_num, tid); } else if (!inst->isCondDelaySlot() && !inst->predTaken()) { // Not-Taken Control - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control " + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control " "inst. updating PC to %08p\n", tid, inst->seqNum, inst->readNextPC()); @@ -166,11 +166,11 @@ FetchSeqUnit::execute(int slot_num) delaySlotInfo[tid].targetReady = false; delaySlotInfo[tid].targetAddr = inst->readPredTarg(); - DPRINTF(Resource, "[tid:%i]: [sn:%i] Updating delay slot target " + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay slot target " "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg()); // Set-Up Squash Through-Out Pipeline - DPRINTF(Resource, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", + DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n", tid, stage_num, seq_num + 1); inst->bdelaySeqNum = seq_num + 1; inst->squashingStage = stage_num; @@ -179,7 +179,7 @@ FetchSeqUnit::execute(int slot_num) squashAfterInst(inst, stage_num, tid); } } else { - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Ignoring branch target update " + DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch target update " "since then is not a control instruction.\n", tid, inst->seqNum); } @@ -209,7 +209,7 @@ void FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, InstSeqNum squash_seq_num, unsigned tid) { - DPRINTF(Resource, "[tid:%i]: Updating due to squash from stage %i.\n", + DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from stage %i.\n", tid, squash_stage); InstSeqNum done_seq_num = inst->bdelaySeqNum; @@ -217,7 +217,7 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, if (squashSeqNum[tid] <= done_seq_num && lastSquashCycle[tid] == curTick) { - DPRINTF(Resource, "[tid:%i]: Ignoring squash from stage %i, since" + DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, since" "there is an outstanding squash that is older.\n", tid, squash_stage); } else { @@ -237,7 +237,7 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage, nextPC[tid] = new_PC + instSize; nextNPC[tid] = new_PC + (2 * instSize); - DPRINTF(Resource, "[tid:%i]: Setting PC to %08p.\n", + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %08p.\n", tid, PC[tid]); } else { delaySlotInfo[tid].numInsts = 1; @@ -278,7 +278,7 @@ FetchSeqUnit::FetchSeqEvent::process() fs_res->PC[i] = fs_res->cpu->readPC(i); fs_res->nextPC[i] = fs_res->cpu->readNextPC(i); fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i); - DPRINTF(Resource, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n", + DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n", fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]); fs_res->pcValid[i] = true; @@ -299,7 +299,7 @@ FetchSeqUnit::activateThread(unsigned tid) cpu->fetchPriorityList.push_back(tid); - DPRINTF(Resource, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n", + DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n", tid, PC[tid], nextPC[tid], nextNPC[tid]); } diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc index f4bbf3f5d..701da5996 100644 --- a/src/cpu/inorder/resources/graduation_unit.cc +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -71,14 +71,14 @@ GraduationUnit::execute(int slot_num) lastCycleGrad = curTick; numCycleGrad = 0; } else if (numCycleGrad > width) { - DPRINTF(Resource, "Graduation bandwidth reached for this cycle.\n"); + DPRINTF(InOrderGraduation, "Graduation bandwidth reached for this cycle.\n"); return; } // Make sure this is the last thing on the resource schedule assert(inst->resSched.size() == 1); - DPRINTF(Resource, "[tid:%i] Graduating instruction [sn:%i].\n", + DPRINTF(InOrderGraduation, "[tid:%i] Graduating instruction [sn:%i].\n", tid, seq_num); DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/); @@ -88,7 +88,7 @@ GraduationUnit::execute(int slot_num) // @TODO: Fix this functionality. Probably too conservative. if (inst->isNonSpeculative()) { *nonSpecInstActive[tid] = false; - DPRINTF(Resource, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n", + DPRINTF(InOrderGraduation, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n", tid, seq_num); } diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc index 97924d2d3..fafff1fa7 100644 --- a/src/cpu/inorder/resources/inst_buffer.cc +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -76,21 +76,21 @@ InstBuffer::execute(int slot_idx) bool do_bypass = true; if (!instList.empty()) { - DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n", + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n", inst->seqNum, next_stage); do_bypass = false; } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) { - DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n", + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n", inst->seqNum, next_stage); do_bypass = false; } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) { - DPRINTF(Resource, "[sn:%i] cannot bypass stage %i because there is no room in " + DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because there is no room in " "stage %i incoming stage buffer.\n", inst->seqNum, next_stage); do_bypass = false; } if (!do_bypass) { // SCHEDULE USAGE OF BUFFER - DPRINTF(Resource, "Scheduling [sn:%i] for buffer insertion in stage %i\n", + DPRINTF(InOrderInstBuffer, "Scheduling [sn:%i] for buffer insertion in stage %i\n", inst->seqNum, next_stage); // Add to schedule: Insert into buffer in next stage @@ -105,7 +105,7 @@ InstBuffer::execute(int slot_idx) inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id, InstBuffer::RemoveInst)); } else { // BYPASS BUFFER & NEXT STAGE - DPRINTF(Resource, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n", + DPRINTF(InOrderInstBuffer, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n", inst->seqNum, next_stage, bypass_stage); inst->setNextStage(bypass_stage); instsBypassed++; @@ -120,12 +120,12 @@ InstBuffer::execute(int slot_idx) bool inserted = false; if (instList.size() < width) { - DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", + DPRINTF(InOrderInstBuffer, "[tid:%i]: Inserting [sn:%i] into buffer.\n", tid, seq_num); insert(inst); inserted = true; } else { - DPRINTF(Resource, "[tid:%i]: Denying [sn:%i] request because " + DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request because " "buffer is full.\n", tid, seq_num); @@ -144,7 +144,7 @@ InstBuffer::execute(int slot_idx) case RemoveInst: { - DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing [sn:%i] from buffer.\n", tid, seq_num); remove(inst); ib_req->done(); @@ -155,7 +155,7 @@ InstBuffer::execute(int slot_idx) fatal("Unrecognized command to %s", resName); } - DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); + DPRINTF(InOrderInstBuffer, "Buffer now contains %i insts.\n", instList.size()); } void @@ -212,7 +212,7 @@ InstBuffer::squash(DynInstPtr inst, int stage_num, // Removed Instructions from InstList & Clear Remove List while (!remove_list.empty()) { - DPRINTF(Resource, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n", + DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n", tid, (*remove_list.front())->seqNum); instList.erase(remove_list.front()); remove_list.pop(); diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc index 321ac90f8..8f8ba144e 100644 --- a/src/cpu/inorder/resources/tlb_unit.cc +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -102,7 +102,7 @@ TLBUnit::execute(int slot_idx) cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { - DPRINTF(Resource, "[tid:%i]: %s encountered while translating " + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), tlb_req->memReq->getVaddr(), seq_num); //insert(inst); @@ -114,7 +114,7 @@ TLBUnit::execute(int slot_idx) // Let CPU handle the fault cpu->trap(tlb_req->fault, tid); } else { - DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated " + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " "to phys. addr:%08p.\n", tid, seq_num, tlb_req->memReq->getVaddr(), tlb_req->memReq->getPaddr()); @@ -125,7 +125,7 @@ TLBUnit::execute(int slot_idx) case DataLookup: { - DPRINTF(Resource, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n", + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n", tid, seq_num, tlb_req->memReq->getVaddr()); tlb_req->fault = @@ -133,7 +133,7 @@ TLBUnit::execute(int slot_idx) cpu->thread[tid]->getTC()); if (tlb_req->fault != NoFault) { - DPRINTF(Resource, "[tid:%i]: %s encountered while translating " + DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating " "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(), tlb_req->memReq->getVaddr(), seq_num); //insert(inst); @@ -144,7 +144,7 @@ TLBUnit::execute(int slot_idx) // Let CPU handle the fault cpu->trap(tlb_req->fault, tid); } else { - DPRINTF(Resource, "[tid:%i]: [sn:%i] virt. addr %08p translated " + DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated " "to phys. addr:%08p.\n", tid, seq_num, tlb_req->memReq->getVaddr(), tlb_req->memReq->getPaddr()); @@ -169,7 +169,7 @@ TLBUnitEvent::process() int stage_num = resource->reqMap[slotIdx]->getStageNum(); int tid = inst->threadNumber; - DPRINTF(Resource, "Waking up from TLB Miss caused by [sn:%i].\n", + DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n", inst->seqNum); TLBUnit* tlb_res = dynamic_cast(resource); diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc index ed697c4ca..a9281a18c 100644 --- a/src/cpu/inorder/resources/use_def.cc +++ b/src/cpu/inorder/resources/use_def.cc @@ -104,7 +104,7 @@ UseDefUnit::execute(int slot_idx) // in the pipeline then stall instructions here if (*nonSpecInstActive[tid] == true && seq_num > *nonSpecSeqNum[tid]) { - DPRINTF(Resource, "[tid:%i]: [sn:%i] cannot execute because there is " + DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because there is " "non-speculative instruction [sn:%i] has not graduated.\n", tid, seq_num, *nonSpecSeqNum[tid]); return; @@ -119,7 +119,7 @@ UseDefUnit::execute(int slot_idx) { int reg_idx = inst->_srcRegIdx[ud_idx]; - DPRINTF(Resource, "[tid:%i]: Attempting to read source register idx %i.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to read source register idx %i.\n", tid, ud_idx); // Ask register dependency map if it is OK to read from Arch. Reg. File @@ -127,19 +127,19 @@ UseDefUnit::execute(int slot_idx) // Read From Register File if (inst->seqNum <= outReadSeqNum[tid]) { if (reg_idx <= FP_Base_DepTag) { - DPRINTF(Resource, "[tid:%i]: Reading Int Reg %i from Register File.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Int Reg %i from Register File.\n", tid, reg_idx); inst->setIntSrc(ud_idx, cpu->readIntReg(reg_idx,inst->readTid())); } else if (reg_idx <= Ctrl_Base_DepTag) { reg_idx -= FP_Base_DepTag; - DPRINTF(Resource, "[tid:%i]: Reading Float Reg %i from Register File.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Float Reg %i from Register File.\n", tid, reg_idx); inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now cpu->readFloatRegBits(reg_idx, inst->readTid())); } else { reg_idx -= Ctrl_Base_DepTag; - DPRINTF(Resource, "[tid:%i]: Reading Misc Reg %i from Register File.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Reading Misc Reg %i from Register File.\n", tid, reg_idx); inst->setIntSrc(ud_idx, cpu->readMiscReg(reg_idx, inst->readTid())); @@ -149,7 +149,7 @@ UseDefUnit::execute(int slot_idx) ud_req->done(); } else { - DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" " registers yet.\n", tid, outReadSeqNum[tid]); DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n", tid, outReadSeqNum[tid]); @@ -164,19 +164,19 @@ UseDefUnit::execute(int slot_idx) int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx); if (reg_idx <= FP_Base_DepTag) { - DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " "[sn:%i] to [sn:%i] source #%i.\n", tid, forward_inst->readIntResult(dest_reg_idx) , forward_inst->seqNum, inst->seqNum, ud_idx); inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx)); } else if (reg_idx <= Ctrl_Base_DepTag) { - DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " "[sn:%i] to [sn:%i] source #%i.\n", tid, forward_inst->readFloatResult(dest_reg_idx) , forward_inst->seqNum, inst->seqNum, ud_idx); inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx)); } else { - DPRINTF(Resource, "[tid:%i]: Forwarding dest. reg value 0x%x from " + DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from " "[sn:%i] to [sn:%i] source #%i.\n", tid, forward_inst->readIntResult(dest_reg_idx) , forward_inst->seqNum, inst->seqNum, ud_idx); @@ -187,13 +187,13 @@ UseDefUnit::execute(int slot_idx) ud_req->done(); } else { - DPRINTF(Resource, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's" " registers yet.\n", tid, outReadSeqNum[tid]); DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n", tid, outReadSeqNum[tid]); } } else { - DPRINTF(Resource, "[tid:%i]: Source register idx: %i is not ready to read.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i is not ready to read.\n", tid, reg_idx); DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n", tid, reg_idx); @@ -208,12 +208,12 @@ UseDefUnit::execute(int slot_idx) int reg_idx = inst->_destRegIdx[ud_idx]; if (regDepMap[tid]->canWrite(reg_idx, inst)) { - DPRINTF(Resource, "[tid:%i]: Attempting to write to Register File.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to write to Register File.\n", tid); if (inst->seqNum <= outReadSeqNum[tid]) { if (reg_idx <= FP_Base_DepTag) { - DPRINTF(Resource, "[tid:%i]: Writing 0x%x to register idx %i.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Writing 0x%x to register idx %i.\n", tid, inst->readIntResult(ud_idx), reg_idx); // Remove Dependencies @@ -246,13 +246,13 @@ UseDefUnit::execute(int slot_idx) ud_req->done(); } else { - DPRINTF(Resource, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's" + DPRINTF(InOrderUseDef, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's" " registers yet.\n", tid, outReadSeqNum); DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n", tid, outReadSeqNum); } } else { - DPRINTF(Resource, "[tid:%i]: Dest. register idx: %i is not ready to write.\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Dest. register idx: %i is not ready to write.\n", tid, reg_idx); DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n", tid, reg_idx); @@ -270,7 +270,7 @@ UseDefUnit::execute(int slot_idx) void UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) { - DPRINTF(Resource, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", tid, squash_seq_num); std::vector slot_remove_list; @@ -285,7 +285,7 @@ UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, un req_ptr->getInst()->readTid() == tid && req_ptr->getInst()->seqNum > squash_seq_num) { - DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + DPRINTF(InOrderUseDef, "[tid:%i]: Squashing [sn:%i].\n", req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); @@ -309,18 +309,18 @@ UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, un } if (outReadSeqNum[tid] >= squash_seq_num) { - DPRINTF(Resource, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid); + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid); outReadSeqNum[tid] = maxSeqNum; } else if (outReadSeqNum[tid] != maxSeqNum) { - DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n", + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n", tid, outReadSeqNum[tid]); } if (outWriteSeqNum[tid] >= squash_seq_num) { - DPRINTF(Resource, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid); + DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid); outWriteSeqNum[tid] = maxSeqNum; } else if (outWriteSeqNum[tid] != maxSeqNum) { - DPRINTF(Resource, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n", + DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n", tid, outWriteSeqNum[tid]); } } -- cgit v1.2.3 From 9e1dc7f20549e9590c5b1450be17ff03057e346f Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Wed, 4 Mar 2009 22:37:45 -0500 Subject: InOrderCPU: Clean up Constructors to initialize variables correctly (i.e. in a way for the compiler to play *nice*) --- src/cpu/inorder/cpu.cc | 6 ++---- src/cpu/inorder/first_stage.cc | 7 ++----- src/cpu/inorder/inorder_dyn_inst.cc | 6 ++---- src/cpu/inorder/pipeline_stage.cc | 21 ++++++--------------- src/cpu/inorder/pipeline_stage.hh | 2 +- src/cpu/inorder/resources/cache_unit.cc | 7 +------ src/cpu/inorder/resources/fetch_seq_unit.cc | 5 ++--- src/cpu/inorder/resources/graduation_unit.cc | 7 +++---- src/cpu/inorder/resources/mult_div_unit.cc | 27 ++++++++------------------- src/cpu/inorder/resources/mult_div_unit.hh | 10 +++++----- src/cpu/inorder/thread_context.hh | 1 + 11 files changed, 33 insertions(+), 66 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 7dafd826f..70877aae4 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -147,6 +147,8 @@ InOrderCPU::CPUEvent::unscheduleEvent() InOrderCPU::InOrderCPU(Params *params) : BaseCPU(params), cpu_id(params->cpu_id), + coreType("default"), + _status(Idle), tickEvent(this), miscRegFile(this), timeBuffer(2 , 2), @@ -162,10 +164,6 @@ InOrderCPU::InOrderCPU(Params *params) resPool = new ResourcePool(this, params); - coreType = "default"; // eventually get this from params - - _status = Idle; - // Resize for Multithreading CPUs thread.resize(numThreads); diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc index be4431a03..5e389b256 100644 --- a/src/cpu/inorder/first_stage.cc +++ b/src/cpu/inorder/first_stage.cc @@ -40,15 +40,12 @@ using namespace std; using namespace ThePipeline; FirstStage::FirstStage(Params *params, unsigned stage_num) - : PipelineStage(params, stage_num) + : PipelineStage(params, stage_num), numFetchingThreads(1), + fetchPolicy(FirstStage::RoundRobin) { for(int tid=0; tid < this->numThreads; tid++) { stageStatus[tid] = Running; } - - numFetchingThreads = 1; - - fetchPolicy = RoundRobin; } void diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index d292d72f0..ceb3cbe51 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -76,16 +76,14 @@ InOrderDynInst::InOrderDynInst(InOrderCPU *cpu, } InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst) - : staticInst(_staticInst), traceData(NULL) + : seqNum(0), staticInst(_staticInst), traceData(NULL) { - seqNum = 0; initVars(); } InOrderDynInst::InOrderDynInst() - : traceData(NULL), cpu(cpu) + : seqNum(0), traceData(NULL), cpu(cpu) { - seqNum = 0; initVars(); } diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index ab7328f4a..cb69464b0 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -38,24 +38,17 @@ using namespace std; using namespace ThePipeline; PipelineStage::PipelineStage(Params *params, unsigned stage_num) + : stageNum(stage_num), stageWidth(ThePipeline::StageWidth), + numThreads(ThePipeline::MaxThreads), _status(Inactive), + stageBufferMax(ThePipeline::interStageBuffSize[stage_num]), + prevStageValid(false), nextStageValid(false) { - init(params, stage_num); + init(params); } void -PipelineStage::init(Params *params, unsigned stage_num) +PipelineStage::init(Params *params) { - stageNum = stage_num; - stageWidth = ThePipeline::StageWidth; - - _status = Inactive; - - numThreads = ThePipeline::MaxThreads; - - prevStageValid = false; - nextStageValid = false; - - // Init. structures for(int tid=0; tid < numThreads; tid++) { stageStatus[tid] = Idle; @@ -69,8 +62,6 @@ PipelineStage::init(Params *params, unsigned stage_num) else lastStallingStage[tid] = NumStages - 1; } - - stageBufferMax = ThePipeline::interStageBuffSize[stage_num]; } diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 19bf8154f..2fd8f2215 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -97,7 +97,7 @@ class PipelineStage virtual ~PipelineStage() { } /** PipelineStage initialization. */ - void init(Params *params, unsigned stage_num); + void init(Params *params); /** Returns the name of stage. */ std::string name() const; diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 6fd7ae36c..57bcb10ef 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -81,14 +81,9 @@ CacheUnit::CachePort::recvRetry() CacheUnit::CacheUnit(string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), - retryPkt(NULL), retrySlot(-1) + retryPkt(NULL), retrySlot(-1), cacheBlocked(false) { - //cacheData.resize(res_width); - //slotStatus = new CachePortStatus[width]; - //fetchPC = new Addr[width]; cachePort = new CachePort(this); - - cacheBlocked = false; } Port * diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index 36cf714c9..444252e1b 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -38,10 +38,9 @@ using namespace ThePipeline; FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) - : Resource(res_name, res_id, res_width, res_latency, _cpu) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + instSize(sizeof(MachInst)) { - instSize = sizeof(MachInst); - for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { delaySlotInfo[tid].numInsts = 0; delaySlotInfo[tid].targetReady = false; diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc index 701da5996..569401e4f 100644 --- a/src/cpu/inorder/resources/graduation_unit.cc +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -35,11 +35,10 @@ using namespace ThePipeline; GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) - : Resource(res_name, res_id, res_width, res_latency, _cpu) + : Resource(res_name, res_id, res_width, res_latency, _cpu), + lastCycleGrad(0), numCycleGrad(0) + { - lastCycleGrad = 0; - numCycleGrad = 0; - for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) { nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid]; diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc index e98e97be7..b31d60ad5 100644 --- a/src/cpu/inorder/resources/mult_div_unit.cc +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -41,25 +41,14 @@ using namespace ThePipeline; MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) - : Resource(res_name, res_id, res_width, res_latency, _cpu) -{ - multRepeatRate = params->multRepeatRate; - multLatency = params->multLatency; - - div8RepeatRate = params->div8RepeatRate; - div8Latency = params->div8Latency; - - div16RepeatRate = params->div16RepeatRate; - div16Latency = params->div16Latency; - - div24RepeatRate = params->div24RepeatRate; - div24Latency = params->div24Latency; - - div32RepeatRate = params->div32RepeatRate; - div32Latency = params->div32Latency; - - lastMDUCycle = 0; -} + : Resource(res_name, res_id, res_width, res_latency, _cpu), + multRepeatRate(params->multRepeatRate), multLatency(params->multLatency), + div8RepeatRate(params->div8RepeatRate), div8Latency(params->div8Latency), + div16RepeatRate(params->div16RepeatRate), div16Latency(params->div16Latency), + div24RepeatRate(params->div24RepeatRate), div24Latency(params->div24Latency), + div32RepeatRate(params->div32RepeatRate), div32Latency(params->div32Latency), + lastMDUCycle(0) +{ } void MultDivUnit::regStats() diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh index 762442c4b..003f6fbb1 100644 --- a/src/cpu/inorder/resources/mult_div_unit.hh +++ b/src/cpu/inorder/resources/mult_div_unit.hh @@ -84,24 +84,24 @@ class MultDivUnit : public Resource { protected: /** Latency & Repeat Rate for Multiply Insts */ - unsigned multLatency; unsigned multRepeatRate; + unsigned multLatency; /** Latency & Repeat Rate for 8-bit Divide Insts */ - unsigned div8Latency; unsigned div8RepeatRate; + unsigned div8Latency; /** Latency & Repeat Rate for 16-bit Divide Insts */ - unsigned div16Latency; unsigned div16RepeatRate; + unsigned div16Latency; /** Latency & Repeat Rate for 24-bit Divide Insts */ - unsigned div24Latency; unsigned div24RepeatRate; + unsigned div24Latency; /** Latency & Repeat Rate for 32-bit Divide Insts */ - unsigned div32Latency; unsigned div32RepeatRate; + unsigned div32Latency; /** Last cycle that MDU was used */ Tick lastMDUCycle; diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh index 8b3b47290..2fb2ed85f 100644 --- a/src/cpu/inorder/thread_context.hh +++ b/src/cpu/inorder/thread_context.hh @@ -132,6 +132,7 @@ class InOrderThreadContext : public ThreadContext /** Serializes state. */ virtual void serialize(std::ostream &os); + /** Unserializes state. */ virtual void unserialize(Checkpoint *cp, const std::string §ion); -- cgit v1.2.3 From e3d6e8882e02d607ed69108d4bc1301de9c2de56 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Thu, 5 Mar 2009 17:15:31 -0800 Subject: Get rid of 'using namespace' declarations in headers. --- src/cpu/inorder/resources/fetch_seq_unit.hh | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh index 2b074bbaa..1885d1f11 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.hh +++ b/src/cpu/inorder/resources/fetch_seq_unit.hh @@ -41,8 +41,6 @@ #include "cpu/inorder/pipeline_traits.hh" #include "cpu/inorder/cpu.hh" -using namespace ThePipeline; - class FetchSeqUnit : public Resource { public: typedef ThePipeline::DynInstPtr DynInstPtr; -- cgit v1.2.3 From cc95b5739097e31fdaa36a3ff443861969e338b1 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 5 Mar 2009 19:09:53 -0800 Subject: stats: Fix all stats usages to deal with template fixes --- src/cpu/base.hh | 2 +- src/cpu/inorder/cpu.hh | 14 ++-- src/cpu/inorder/pipeline_stage.hh | 14 ++-- src/cpu/inorder/resource.hh | 2 +- src/cpu/inorder/resources/bpred_unit.hh | 16 ++--- src/cpu/inorder/resources/branch_predictor.hh | 4 +- src/cpu/inorder/resources/execution_unit.hh | 4 +- src/cpu/inorder/resources/inst_buffer.hh | 2 +- src/cpu/inorder/resources/mult_div_unit.hh | 4 +- src/cpu/memtest/memtest.hh | 6 +- src/cpu/o3/bpred_unit.hh | 16 ++--- src/cpu/o3/commit.hh | 28 ++++---- src/cpu/o3/cpu.hh | 8 +-- src/cpu/o3/decode.hh | 20 +++--- src/cpu/o3/fetch.hh | 24 +++---- src/cpu/o3/iew.hh | 54 ++++++++-------- src/cpu/o3/inst_queue.hh | 38 +++++------ src/cpu/o3/lsq_unit.hh | 20 +++--- src/cpu/o3/mem_dep_unit.hh | 8 +-- src/cpu/o3/rename.hh | 38 +++++------ src/cpu/ozone/back_end.hh | 92 +++++++++++++-------------- src/cpu/ozone/cpu.hh | 4 +- src/cpu/ozone/front_end.hh | 40 ++++++------ src/cpu/ozone/inorder_back_end.hh | 2 +- src/cpu/ozone/inst_queue.hh | 32 +++++----- src/cpu/ozone/lsq_unit.hh | 2 +- src/cpu/ozone/lw_back_end.hh | 84 ++++++++++++------------ src/cpu/ozone/lw_lsq.hh | 4 +- src/cpu/simple/base.hh | 14 ++-- src/cpu/thread_state.hh | 4 +- 30 files changed, 300 insertions(+), 300 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/base.hh b/src/cpu/base.hh index c8215e047..8af3295eb 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -304,7 +304,7 @@ class BaseCPU : public MemObject public: // Number of CPU cycles simulated - Stats::Scalar<> numCycles; + Stats::Scalar numCycles; }; #endif // __CPU_BASE_HH__ diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 36c90a0e9..adcd28019 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -638,25 +638,25 @@ class InOrderCPU : public BaseCPU inline void tickThreadStats(); /** Per-Thread Tick */ - Stats::Vector<> threadCycles; + Stats::Vector threadCycles; /** Tick for SMT */ - Stats::Scalar<> smtCycles; + Stats::Scalar smtCycles; /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; + Stats::Scalar timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; + Stats::Scalar idleCycles; /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; + Stats::Vector committedInsts; /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> smtCommittedInsts; + Stats::Vector smtCommittedInsts; /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; + Stats::Scalar totalCommittedInsts; /** Stat for the CPI per thread. */ Stats::Formula cpi; diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 2fd8f2215..b074639fb 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -340,19 +340,19 @@ class PipelineStage //@TODO: Use Stats for the pipeline stages /** Stat for total number of idle cycles. */ - //Stats::Scalar<> stageIdleCycles; + //Stats::Scalar stageIdleCycles; /** Stat for total number of blocked cycles. */ - //Stats::Scalar<> stageBlockedCycles; + //Stats::Scalar stageBlockedCycles; /** Stat for total number of normal running cycles. */ - //Stats::Scalar<> stageRunCycles; + //Stats::Scalar stageRunCycles; /** Stat for total number of unblocking cycles. */ - //Stats::Scalar<> stageUnblockCycles; + //Stats::Scalar stageUnblockCycles; /** Stat for total number of squashing cycles. */ - //Stats::Scalar<> stageSquashCycles; + //Stats::Scalar stageSquashCycles; /** Stat for total number of staged instructions. */ - //Stats::Scalar<> stageProcessedInsts; + //Stats::Scalar stageProcessedInsts; /** Stat for total number of squashed instructions. */ - //Stats::Scalar<> stageSquashedInsts; + //Stats::Scalar stageSquashedInsts; }; #endif diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 9b9e3c3dc..b857e59ed 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -232,7 +232,7 @@ class Resource { // ///////////////////////////////////////////////////////////////// /** Number of Instruction Requests the Resource Processes */ - Stats::Scalar<> instReqsProcessed; + Stats::Scalar instReqsProcessed; }; class ResourceEvent : public Event diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh index b945922a7..bd68459d1 100644 --- a/src/cpu/inorder/resources/bpred_unit.hh +++ b/src/cpu/inorder/resources/bpred_unit.hh @@ -238,21 +238,21 @@ class BPredUnit ReturnAddrStack RAS[ThePipeline::MaxThreads]; /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; + Stats::Scalar lookups; /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; + Stats::Scalar condPredicted; /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; + Stats::Scalar condIncorrect; /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; + Stats::Scalar BTBLookups; /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; + Stats::Scalar BTBHits; /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; + Stats::Scalar BTBCorrect; /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; + Stats::Scalar usedRAS; /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; + Stats::Scalar RASIncorrect; }; #endif // __CPU_INORDER_BPRED_UNIT_HH__ diff --git a/src/cpu/inorder/resources/branch_predictor.hh b/src/cpu/inorder/resources/branch_predictor.hh index 57745343c..47053910d 100644 --- a/src/cpu/inorder/resources/branch_predictor.hh +++ b/src/cpu/inorder/resources/branch_predictor.hh @@ -78,8 +78,8 @@ class BranchPredictor : public Resource { // RESOURCE STATISTICS // ///////////////////////////////////////////////////////////////// - Stats::Scalar<> predictedTaken; - Stats::Scalar<> predictedNotTaken; + Stats::Scalar predictedTaken; + Stats::Scalar predictedNotTaken; }; diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh index e969497a2..46691bbf2 100644 --- a/src/cpu/inorder/resources/execution_unit.hh +++ b/src/cpu/inorder/resources/execution_unit.hh @@ -69,8 +69,8 @@ class ExecutionUnit : public Resource { // RESOURCE STATISTICS // ///////////////////////////////////////////////////////////////// - Stats::Scalar<> predictedTakenIncorrect; - Stats::Scalar<> predictedNotTakenIncorrect; + Stats::Scalar predictedTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; }; diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh index f4851e868..baadd42ff 100644 --- a/src/cpu/inorder/resources/inst_buffer.hh +++ b/src/cpu/inorder/resources/inst_buffer.hh @@ -86,7 +86,7 @@ class InstBuffer : public Resource { // ///////////////////////////////////////////////////////////////// /** Number of Instruction Requests the Resource Processes */ - Stats::Scalar<> instsBypassed; + Stats::Scalar instsBypassed; }; diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh index 003f6fbb1..76180714c 100644 --- a/src/cpu/inorder/resources/mult_div_unit.hh +++ b/src/cpu/inorder/resources/mult_div_unit.hh @@ -116,10 +116,10 @@ class MultDivUnit : public Resource { std::string lastInstName; /** Number of Instruction Requests the Resource Processes */ - Stats::Scalar<> multInstReqsProcessed; + Stats::Scalar multInstReqsProcessed; /** Number of Instruction Requests the Resource Processes */ - Stats::Scalar<> divInstReqsProcessed; + Stats::Scalar divInstReqsProcessed; MDUEvent *mduEvent; }; diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh index 82438b41f..907659f69 100644 --- a/src/cpu/memtest/memtest.hh +++ b/src/cpu/memtest/memtest.hh @@ -171,9 +171,9 @@ class MemTest : public MemObject bool atomic; - Stats::Scalar<> numReadsStat; - Stats::Scalar<> numWritesStat; - Stats::Scalar<> numCopiesStat; + Stats::Scalar numReadsStat; + Stats::Scalar numWritesStat; + Stats::Scalar numCopiesStat; // called by MemCompleteEvent::process() void completeRequest(PacketPtr pkt); diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 34fe74178..44f9bea79 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -237,21 +237,21 @@ class BPredUnit ReturnAddrStack RAS[Impl::MaxThreads]; /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; + Stats::Scalar lookups; /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; + Stats::Scalar condPredicted; /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; + Stats::Scalar condIncorrect; /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; + Stats::Scalar BTBLookups; /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; + Stats::Scalar BTBHits; /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; + Stats::Scalar BTBCorrect; /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; + Stats::Scalar usedRAS; /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; + Stats::Scalar RASIncorrect; }; #endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index ff1e517f2..f21c14569 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -452,40 +452,40 @@ class DefaultCommit void updateComInstStats(DynInstPtr &inst); /** Stat for the total number of committed instructions. */ - Stats::Scalar<> commitCommittedInsts; + Stats::Scalar commitCommittedInsts; /** Stat for the total number of squashed instructions discarded by commit. */ - Stats::Scalar<> commitSquashedInsts; + Stats::Scalar commitSquashedInsts; /** Stat for the total number of times commit is told to squash. * @todo: Actually increment this stat. */ - Stats::Scalar<> commitSquashEvents; + Stats::Scalar commitSquashEvents; /** Stat for the total number of times commit has had to stall due to a non- * speculative instruction reaching the head of the ROB. */ - Stats::Scalar<> commitNonSpecStalls; + Stats::Scalar commitNonSpecStalls; /** Stat for the total number of branch mispredicts that caused a squash. */ - Stats::Scalar<> branchMispredicts; + Stats::Scalar branchMispredicts; /** Distribution of the number of committed instructions each cycle. */ - Stats::Distribution<> numCommittedDist; + Stats::Distribution numCommittedDist; /** Total number of instructions committed. */ - Stats::Vector<> statComInst; + Stats::Vector statComInst; /** Total number of software prefetches committed. */ - Stats::Vector<> statComSwp; + Stats::Vector statComSwp; /** Stat for the total number of committed memory references. */ - Stats::Vector<> statComRefs; + Stats::Vector statComRefs; /** Stat for the total number of committed loads. */ - Stats::Vector<> statComLoads; + Stats::Vector statComLoads; /** Total number of committed memory barriers. */ - Stats::Vector<> statComMembars; + Stats::Vector statComMembars; /** Total number of committed branches. */ - Stats::Vector<> statComBranches; + Stats::Vector statComBranches; /** Number of cycles where the commit bandwidth limit is reached. */ - Stats::Scalar<> commitEligibleSamples; + Stats::Scalar commitEligibleSamples; /** Number of instructions not committed due to bandwidth limits. */ - Stats::Vector<> commitEligible; + Stats::Vector commitEligible; }; #endif // __CPU_O3_COMMIT_HH__ diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index f4ed28e8e..942970f5f 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -755,13 +755,13 @@ class FullO3CPU : public BaseO3CPU bool lockFlag; /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; + Stats::Scalar timesIdled; /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; + Stats::Scalar idleCycles; /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; + Stats::Vector committedInsts; /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; + Stats::Scalar totalCommittedInsts; /** Stat for the CPI per thread. */ Stats::Formula cpi; /** Stat for the total CPI. */ diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index dc8063f29..294b5b623 100644 --- a/src/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh @@ -288,27 +288,27 @@ class DefaultDecode /** Stat for total number of idle cycles. */ - Stats::Scalar<> decodeIdleCycles; + Stats::Scalar decodeIdleCycles; /** Stat for total number of blocked cycles. */ - Stats::Scalar<> decodeBlockedCycles; + Stats::Scalar decodeBlockedCycles; /** Stat for total number of normal running cycles. */ - Stats::Scalar<> decodeRunCycles; + Stats::Scalar decodeRunCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> decodeUnblockCycles; + Stats::Scalar decodeUnblockCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> decodeSquashCycles; + Stats::Scalar decodeSquashCycles; /** Stat for number of times a branch is resolved at decode. */ - Stats::Scalar<> decodeBranchResolved; + Stats::Scalar decodeBranchResolved; /** Stat for number of times a branch mispredict is detected. */ - Stats::Scalar<> decodeBranchMispred; + Stats::Scalar decodeBranchMispred; /** Stat for number of times decode detected a non-control instruction * incorrectly predicted as a branch. */ - Stats::Scalar<> decodeControlMispred; + Stats::Scalar decodeControlMispred; /** Stat for total number of decoded instructions. */ - Stats::Scalar<> decodeDecodedInsts; + Stats::Scalar decodeDecodedInsts; /** Stat for total number of squashed instructions. */ - Stats::Scalar<> decodeSquashedInsts; + Stats::Scalar decodeSquashedInsts; }; #endif // __CPU_O3_DECODE_HH__ diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 9886b6675..08ccb094b 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -448,33 +448,33 @@ class DefaultFetch // @todo: Consider making these vectors and tracking on a per thread basis. /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; + Stats::Scalar fetchedInsts; /** Total number of fetched branches. */ - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Total number of cycles spent blocked. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Total number of cycles spent in any other state. */ - Stats::Scalar<> fetchMiscStallCycles; + Stats::Scalar fetchMiscStallCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; /** Total number of outstanding icache accesses that were dropped * due to a squash. */ - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; + Stats::Distribution fetchNisnDist; /** Rate of how often fetch was idle. */ Stats::Formula idleRate; /** Number of branch fetches per cycle. */ diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index bc60f401b..3458f09d6 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -465,69 +465,69 @@ class DefaultIEW bool switchedOut; /** Stat for total number of idle cycles. */ - Stats::Scalar<> iewIdleCycles; + Stats::Scalar iewIdleCycles; /** Stat for total number of squashing cycles. */ - Stats::Scalar<> iewSquashCycles; + Stats::Scalar iewSquashCycles; /** Stat for total number of blocking cycles. */ - Stats::Scalar<> iewBlockCycles; + Stats::Scalar iewBlockCycles; /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> iewUnblockCycles; + Stats::Scalar iewUnblockCycles; /** Stat for total number of instructions dispatched. */ - Stats::Scalar<> iewDispatchedInsts; + Stats::Scalar iewDispatchedInsts; /** Stat for total number of squashed instructions dispatch skips. */ - Stats::Scalar<> iewDispSquashedInsts; + Stats::Scalar iewDispSquashedInsts; /** Stat for total number of dispatched load instructions. */ - Stats::Scalar<> iewDispLoadInsts; + Stats::Scalar iewDispLoadInsts; /** Stat for total number of dispatched store instructions. */ - Stats::Scalar<> iewDispStoreInsts; + Stats::Scalar iewDispStoreInsts; /** Stat for total number of dispatched non speculative instructions. */ - Stats::Scalar<> iewDispNonSpecInsts; + Stats::Scalar iewDispNonSpecInsts; /** Stat for number of times the IQ becomes full. */ - Stats::Scalar<> iewIQFullEvents; + Stats::Scalar iewIQFullEvents; /** Stat for number of times the LSQ becomes full. */ - Stats::Scalar<> iewLSQFullEvents; + Stats::Scalar iewLSQFullEvents; /** Stat for total number of memory ordering violation events. */ - Stats::Scalar<> memOrderViolationEvents; + Stats::Scalar memOrderViolationEvents; /** Stat for total number of incorrect predicted taken branches. */ - Stats::Scalar<> predictedTakenIncorrect; + Stats::Scalar predictedTakenIncorrect; /** Stat for total number of incorrect predicted not taken branches. */ - Stats::Scalar<> predictedNotTakenIncorrect; + Stats::Scalar predictedNotTakenIncorrect; /** Stat for total number of mispredicted branches detected at execute. */ Stats::Formula branchMispredicts; /** Stat for total number of executed instructions. */ - Stats::Scalar<> iewExecutedInsts; + Stats::Scalar iewExecutedInsts; /** Stat for total number of executed load instructions. */ - Stats::Vector<> iewExecLoadInsts; + Stats::Vector iewExecLoadInsts; /** Stat for total number of executed store instructions. */ -// Stats::Scalar<> iewExecStoreInsts; +// Stats::Scalar iewExecStoreInsts; /** Stat for total number of squashed instructions skipped at execute. */ - Stats::Scalar<> iewExecSquashedInsts; + Stats::Scalar iewExecSquashedInsts; /** Number of executed software prefetches. */ - Stats::Vector<> iewExecutedSwp; + Stats::Vector iewExecutedSwp; /** Number of executed nops. */ - Stats::Vector<> iewExecutedNop; + Stats::Vector iewExecutedNop; /** Number of executed meomory references. */ - Stats::Vector<> iewExecutedRefs; + Stats::Vector iewExecutedRefs; /** Number of executed branches. */ - Stats::Vector<> iewExecutedBranches; + Stats::Vector iewExecutedBranches; /** Number of executed store instructions. */ Stats::Formula iewExecStoreInsts; /** Number of instructions executed per cycle. */ Stats::Formula iewExecRate; /** Number of instructions sent to commit. */ - Stats::Vector<> iewInstsToCommit; + Stats::Vector iewInstsToCommit; /** Number of instructions that writeback. */ - Stats::Vector<> writebackCount; + Stats::Vector writebackCount; /** Number of instructions that wake consumers. */ - Stats::Vector<> producerInst; + Stats::Vector producerInst; /** Number of instructions that wake up from producers. */ - Stats::Vector<> consumerInst; + Stats::Vector consumerInst; /** Number of instructions that were delayed in writing back due * to resource contention. */ - Stats::Vector<> wbPenalized; + Stats::Vector wbPenalized; /** Number of instructions per cycle written back. */ Stats::Formula wbRate; /** Average number of woken instructions per writeback. */ diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index 43da1565d..0c3f44436 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -443,58 +443,58 @@ class InstructionQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; - Stats::Scalar<> iqInstsIssued; + Stats::Scalar iqInstsIssued; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; + Stats::Scalar iqIntInstsIssued; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; + Stats::Scalar iqFloatInstsIssued; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; + Stats::Scalar iqBranchInstsIssued; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; + Stats::Scalar iqMemInstsIssued; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; // Also include number of instructions rescheduled and replayed. /** Distribution of number of instructions in the queue. * @todo: Need to create struct to track the entry time for each * instruction. */ -// Stats::VectorDistribution<> queueResDist; +// Stats::VectorDistribution queueResDist; /** Distribution of the number of instructions issued. */ - Stats::Distribution<> numIssuedDist; + Stats::Distribution numIssuedDist; /** Distribution of the cycles it takes to issue an instruction. * @todo: Need to create struct to track the ready time for each * instruction. */ -// Stats::VectorDistribution<> issueDelayDist; +// Stats::VectorDistribution issueDelayDist; /** Number of times an instruction could not be issued because a * FU was busy. */ - Stats::Vector<> statFuBusy; -// Stats::Vector<> dist_unissued; + Stats::Vector statFuBusy; +// Stats::Vector dist_unissued; /** Stat for total number issued for each instruction type. */ - Stats::Vector2d<> statIssuedInstType; + Stats::Vector2d statIssuedInstType; /** Number of instructions issued per cycle. */ Stats::Formula issueRate; /** Number of times the FU was busy. */ - Stats::Vector<> fuBusy; + Stats::Vector fuBusy; /** Number of times the FU was busy per instruction issued. */ Stats::Formula fuBusyRate; }; diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 8af8f18e6..5323e3a47 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -409,35 +409,35 @@ class LSQUnit { // of that in stage that is one level up, and only call executeLoad/Store // the appropriate number of times. /** Total number of loads forwaded from LSQ stores. */ - Stats::Scalar<> lsqForwLoads; + Stats::Scalar lsqForwLoads; /** Total number of loads ignored due to invalid addresses. */ - Stats::Scalar<> invAddrLoads; + Stats::Scalar invAddrLoads; /** Total number of squashed loads. */ - Stats::Scalar<> lsqSquashedLoads; + Stats::Scalar lsqSquashedLoads; /** Total number of responses from the memory system that are * ignored due to the instruction already being squashed. */ - Stats::Scalar<> lsqIgnoredResponses; + Stats::Scalar lsqIgnoredResponses; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; /** Total number of squashed stores. */ - Stats::Scalar<> lsqSquashedStores; + Stats::Scalar lsqSquashedStores; /** Total number of software prefetches ignored due to invalid addresses. */ - Stats::Scalar<> invAddrSwpfs; + Stats::Scalar invAddrSwpfs; /** Ready loads blocked due to partial store-forwarding. */ - Stats::Scalar<> lsqBlockedLoads; + Stats::Scalar lsqBlockedLoads; /** Number of loads that were rescheduled. */ - Stats::Scalar<> lsqRescheduledLoads; + Stats::Scalar lsqRescheduledLoads; /** Number of times the LSQ is blocked due to the cache. */ - Stats::Scalar<> lsqCacheBlocked; + Stats::Scalar lsqCacheBlocked; public: /** Executes the load at the given index. */ diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index 4f66b4599..fa1c33320 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -253,13 +253,13 @@ class MemDepUnit { int id; /** Stat for number of inserted loads. */ - Stats::Scalar<> insertedLoads; + Stats::Scalar insertedLoads; /** Stat for number of inserted stores. */ - Stats::Scalar<> insertedStores; + Stats::Scalar insertedStores; /** Stat for number of conflicting loads that had to wait for a store. */ - Stats::Scalar<> conflictingLoads; + Stats::Scalar conflictingLoads; /** Stat for number of conflicting stores that had to wait for a store. */ - Stats::Scalar<> conflictingStores; + Stats::Scalar conflictingStores; }; #endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index c9e0d418d..0fdf28b19 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -441,44 +441,44 @@ class DefaultRename inline void incrFullStat(const FullSource &source); /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> renameSquashCycles; + Stats::Scalar renameSquashCycles; /** Stat for total number of cycles spent idle. */ - Stats::Scalar<> renameIdleCycles; + Stats::Scalar renameIdleCycles; /** Stat for total number of cycles spent blocking. */ - Stats::Scalar<> renameBlockCycles; + Stats::Scalar renameBlockCycles; /** Stat for total number of cycles spent stalling for a serializing inst. */ - Stats::Scalar<> renameSerializeStallCycles; + Stats::Scalar renameSerializeStallCycles; /** Stat for total number of cycles spent running normally. */ - Stats::Scalar<> renameRunCycles; + Stats::Scalar renameRunCycles; /** Stat for total number of cycles spent unblocking. */ - Stats::Scalar<> renameUnblockCycles; + Stats::Scalar renameUnblockCycles; /** Stat for total number of renamed instructions. */ - Stats::Scalar<> renameRenamedInsts; + Stats::Scalar renameRenamedInsts; /** Stat for total number of squashed instructions that rename discards. */ - Stats::Scalar<> renameSquashedInsts; + Stats::Scalar renameSquashedInsts; /** Stat for total number of times that the ROB starts a stall in rename. */ - Stats::Scalar<> renameROBFullEvents; + Stats::Scalar renameROBFullEvents; /** Stat for total number of times that the IQ starts a stall in rename. */ - Stats::Scalar<> renameIQFullEvents; + Stats::Scalar renameIQFullEvents; /** Stat for total number of times that the LSQ starts a stall in rename. */ - Stats::Scalar<> renameLSQFullEvents; + Stats::Scalar renameLSQFullEvents; /** Stat for total number of times that rename runs out of free registers * to use to rename. */ - Stats::Scalar<> renameFullRegistersEvents; + Stats::Scalar renameFullRegistersEvents; /** Stat for total number of renamed destination registers. */ - Stats::Scalar<> renameRenamedOperands; + Stats::Scalar renameRenamedOperands; /** Stat for total number of source register rename lookups. */ - Stats::Scalar<> renameRenameLookups; + Stats::Scalar renameRenameLookups; /** Stat for total number of committed renaming mappings. */ - Stats::Scalar<> renameCommittedMaps; + Stats::Scalar renameCommittedMaps; /** Stat for total number of mappings that were undone due to a squash. */ - Stats::Scalar<> renameUndoneMaps; + Stats::Scalar renameUndoneMaps; /** Number of serialize instructions handled. */ - Stats::Scalar<> renamedSerializing; + Stats::Scalar renamedSerializing; /** Number of instructions marked as temporarily serializing. */ - Stats::Scalar<> renamedTempSerializing; + Stats::Scalar renamedTempSerializing; /** Number of instructions inserted into skid buffers. */ - Stats::Scalar<> renameSkidInsts; + Stats::Scalar renameSkidInsts; }; #endif // __CPU_O3_RENAME_HH__ diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh index 84429f3c1..ca858ce2e 100644 --- a/src/cpu/ozone/back_end.hh +++ b/src/cpu/ozone/back_end.hh @@ -157,13 +157,13 @@ class BackEnd int numInsts; int width; - Stats::VectorDistribution<> occ_dist; + Stats::VectorDistribution occ_dist; - Stats::Vector<> inst_count; - Stats::Vector<> peak_inst_count; - Stats::Scalar<> empty_count; - Stats::Scalar<> current_count; - Stats::Scalar<> fullCount; + Stats::Vector inst_count; + Stats::Vector peak_inst_count; + Stats::Scalar empty_count; + Stats::Scalar current_count; + Stats::Scalar fullCount; Stats::Formula occ_rate; Stats::Formula avg_residency; @@ -371,45 +371,45 @@ class BackEnd bool fetchRedirect[Impl::MaxThreads]; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> rob_cap_events; - Stats::Vector<> rob_cap_inst_count; - Stats::Vector<> iq_cap_events; - Stats::Vector<> iq_cap_inst_count; + Stats::Vector rob_cap_events; + Stats::Vector rob_cap_inst_count; + Stats::Vector iq_cap_events; + Stats::Vector iq_cap_inst_count; // total number of instructions executed - Stats::Vector<> exe_inst; - Stats::Vector<> exe_swp; - Stats::Vector<> exe_nop; - Stats::Vector<> exe_refs; - Stats::Vector<> exe_loads; - Stats::Vector<> exe_branches; + Stats::Vector exe_inst; + Stats::Vector exe_swp; + Stats::Vector exe_nop; + Stats::Vector exe_refs; + Stats::Vector exe_loads; + Stats::Vector exe_branches; - Stats::Vector<> issued_ops; + Stats::Vector issued_ops; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; + Stats::Vector lsq_forw_loads; // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; + Stats::Vector inv_addr_loads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; + Stats::Vector inv_addr_swpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; + Stats::Vector lsq_blocked_loads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> n_issued_dist; - Stats::VectorDistribution<> issue_delay_dist; + Stats::Vector n_issued_dist; + Stats::VectorDistribution issue_delay_dist; - Stats::VectorDistribution<> queue_res_dist; + Stats::VectorDistribution queue_res_dist; /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -422,34 +422,34 @@ class BackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writeback_count; - Stats::Vector<> producer_inst; - Stats::Vector<> consumer_inst; - Stats::Vector<> wb_penalized; + Stats::Vector writeback_count; + Stats::Vector producer_inst; + Stats::Vector consumer_inst; + Stats::Vector wb_penalized; Stats::Formula wb_rate; Stats::Formula wb_fanout; Stats::Formula wb_penalized_rate; // total number of instructions committed - Stats::Vector<> stat_com_inst; - Stats::Vector<> stat_com_swp; - Stats::Vector<> stat_com_refs; - Stats::Vector<> stat_com_loads; - Stats::Vector<> stat_com_membars; - Stats::Vector<> stat_com_branches; + Stats::Vector stat_com_inst; + Stats::Vector stat_com_swp; + Stats::Vector stat_com_refs; + Stats::Vector stat_com_loads; + Stats::Vector stat_com_membars; + Stats::Vector stat_com_branches; - Stats::Distribution<> n_committed_dist; + Stats::Distribution n_committed_dist; - Stats::Scalar<> commit_eligible_samples; - Stats::Vector<> commit_eligible; + Stats::Scalar commit_eligible_samples; + Stats::Vector commit_eligible; - Stats::Scalar<> ROB_fcount; + Stats::Scalar ROB_fcount; Stats::Formula ROB_full_rate; - Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Vector ROB_count; // cumulative ROB occupancy Stats::Formula ROB_occ_rate; - Stats::VectorDistribution<> ROB_occ_dist; + Stats::VectorDistribution ROB_occ_dist; public: void dumpInsts(); }; diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index 054fc1aa1..0bfb4bfa9 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -390,7 +390,7 @@ class OzoneCPU : public BaseCPU Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; public: @@ -473,7 +473,7 @@ class OzoneCPU : public BaseCPU bool lockFlag; - Stats::Scalar<> quiesceCycles; + Stats::Scalar quiesceCycles; Checker *checker; }; diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index fac243449..38fc89e3f 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -275,48 +275,48 @@ class FrontEnd private: // number of idle cycles /* - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; */ // @todo: Consider making these vectors and tracking on a per thread basis. /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; + Stats::Scalar fetchedInsts; + Stats::Scalar fetchedBranches; /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; + Stats::Scalar predictedBranches; /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; + Stats::Scalar fetchCycles; - Stats::Scalar<> fetchIdleCycles; + Stats::Scalar fetchIdleCycles; /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; + Stats::Scalar fetchSquashCycles; /** Stat for total number of cycles spent blocked due to other stages in * the pipeline. */ - Stats::Scalar<> fetchBlockedCycles; + Stats::Scalar fetchBlockedCycles; /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; + Stats::Scalar fetchedCacheLines; - Stats::Scalar<> fetchIcacheSquashes; + Stats::Scalar fetchIcacheSquashes; /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; -// Stats::Vector<> qfull_iq_occupancy; -// Stats::VectorDistribution<> qfull_iq_occ_dist_; + Stats::Distribution fetchNisnDist; +// Stats::Vector qfull_iq_occupancy; +// Stats::VectorDistribution qfull_iq_occ_dist_; Stats::Formula idleRate; Stats::Formula branchRate; Stats::Formula fetchRate; - Stats::Scalar<> IFQCount; // cumulative IFQ occupancy + Stats::Scalar IFQCount; // cumulative IFQ occupancy Stats::Formula IFQOccupancy; Stats::Formula IFQLatency; - Stats::Scalar<> IFQFcount; // cumulative IFQ full count + Stats::Scalar IFQFcount; // cumulative IFQ full count Stats::Formula IFQFullRate; - Stats::Scalar<> dispatchCountStat; - Stats::Scalar<> dispatchedSerializing; - Stats::Scalar<> dispatchedTempSerializing; - Stats::Scalar<> dispatchSerializeStallCycles; + Stats::Scalar dispatchCountStat; + Stats::Scalar dispatchedSerializing; + Stats::Scalar dispatchedTempSerializing; + Stats::Scalar dispatchSerializeStallCycles; Stats::Formula dispatchRate; Stats::Formula regIntFull; Stats::Formula regFpFull; diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh index 0840591e0..e930144be 100644 --- a/src/cpu/ozone/inorder_back_end.hh +++ b/src/cpu/ozone/inorder_back_end.hh @@ -192,7 +192,7 @@ class InorderBackEnd TimeBuffer *comm; // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; }; diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh index a11d5204b..e840d5c21 100644 --- a/src/cpu/ozone/inst_queue.hh +++ b/src/cpu/ozone/inst_queue.hh @@ -473,35 +473,35 @@ class InstQueue void dumpInsts(); /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; + Stats::Scalar iqInstsAdded; /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; -// Stats::Scalar<> iqIntInstsAdded; + Stats::Scalar iqNonSpecInstsAdded; +// Stats::Scalar iqIntInstsAdded; /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; -// Stats::Scalar<> iqFloatInstsAdded; + Stats::Scalar iqIntInstsIssued; +// Stats::Scalar iqFloatInstsAdded; /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; -// Stats::Scalar<> iqBranchInstsAdded; + Stats::Scalar iqFloatInstsIssued; +// Stats::Scalar iqBranchInstsAdded; /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; -// Stats::Scalar<> iqMemInstsAdded; + Stats::Scalar iqBranchInstsIssued; +// Stats::Scalar iqMemInstsAdded; /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; -// Stats::Scalar<> iqMiscInstsAdded; + Stats::Scalar iqMemInstsIssued; +// Stats::Scalar iqMiscInstsAdded; /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; + Stats::Scalar iqMiscInstsIssued; /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; + Stats::Scalar iqSquashedInstsIssued; /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; + Stats::Scalar iqSquashedInstsExamined; /** Stat for number of squashed instruction operands examined when * squashing. */ - Stats::Scalar<> iqSquashedOperandsExamined; + Stats::Scalar iqSquashedOperandsExamined; /** Stat for number of non-speculative instructions removed due to a squash. */ - Stats::Scalar<> iqSquashedNonSpecRemoved; + Stats::Scalar iqSquashedNonSpecRemoved; }; diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh index 981682c26..47be245e5 100644 --- a/src/cpu/ozone/lsq_unit.hh +++ b/src/cpu/ozone/lsq_unit.hh @@ -331,7 +331,7 @@ class OzoneLSQ { //list mshrSeqNums; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; /** Wire to read information from the issue stage time queue. */ diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh index 8ab50d5c9..4a1657c9b 100644 --- a/src/cpu/ozone/lw_back_end.hh +++ b/src/cpu/ozone/lw_back_end.hh @@ -326,47 +326,47 @@ class LWBackEnd bool exactFullStall; // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; +/* Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; */ - Stats::Vector<> robCapEvents; - Stats::Vector<> robCapInstCount; - Stats::Vector<> iqCapEvents; - Stats::Vector<> iqCapInstCount; + Stats::Vector robCapEvents; + Stats::Vector robCapInstCount; + Stats::Vector iqCapEvents; + Stats::Vector iqCapInstCount; // total number of instructions executed - Stats::Vector<> exeInst; - Stats::Vector<> exeSwp; - Stats::Vector<> exeNop; - Stats::Vector<> exeRefs; - Stats::Vector<> exeLoads; - Stats::Vector<> exeBranches; + Stats::Vector exeInst; + Stats::Vector exeSwp; + Stats::Vector exeNop; + Stats::Vector exeRefs; + Stats::Vector exeLoads; + Stats::Vector exeBranches; - Stats::Vector<> issuedOps; + Stats::Vector issuedOps; // total number of loads forwaded from LSQ stores - Stats::Vector<> lsqForwLoads; + Stats::Vector lsqForwLoads; // total number of loads ignored due to invalid addresses - Stats::Vector<> invAddrLoads; + Stats::Vector invAddrLoads; // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> invAddrSwpfs; + Stats::Vector invAddrSwpfs; // ready loads blocked due to memory disambiguation - Stats::Vector<> lsqBlockedLoads; + Stats::Vector lsqBlockedLoads; - Stats::Scalar<> lsqInversion; + Stats::Scalar lsqInversion; - Stats::Vector<> nIssuedDist; + Stats::Vector nIssuedDist; /* - Stats::VectorDistribution<> issueDelayDist; + Stats::VectorDistribution issueDelayDist; - Stats::VectorDistribution<> queueResDist; + Stats::VectorDistribution queueResDist; */ /* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; + Stats::Vector stat_fu_busy; + Stats::Vector2d stat_fuBusy; + Stats::Vector dist_unissued; + Stats::Vector2d stat_issued_inst_type; Stats::Formula misspec_cnt; Stats::Formula misspec_ipc; @@ -379,37 +379,37 @@ class LWBackEnd Stats::Formula commit_ipb; Stats::Formula lsq_inv_rate; */ - Stats::Vector<> writebackCount; - Stats::Vector<> producerInst; - Stats::Vector<> consumerInst; - Stats::Vector<> wbPenalized; + Stats::Vector writebackCount; + Stats::Vector producerInst; + Stats::Vector consumerInst; + Stats::Vector wbPenalized; Stats::Formula wbRate; Stats::Formula wbFanout; Stats::Formula wbPenalizedRate; // total number of instructions committed - Stats::Vector<> statComInst; - Stats::Vector<> statComSwp; - Stats::Vector<> statComRefs; - Stats::Vector<> statComLoads; - Stats::Vector<> statComMembars; - Stats::Vector<> statComBranches; + Stats::Vector statComInst; + Stats::Vector statComSwp; + Stats::Vector statComRefs; + Stats::Vector statComLoads; + Stats::Vector statComMembars; + Stats::Vector statComBranches; - Stats::Distribution<> nCommittedDist; + Stats::Distribution nCommittedDist; - Stats::Scalar<> commitEligibleSamples; - Stats::Vector<> commitEligible; + Stats::Scalar commitEligibleSamples; + Stats::Vector commitEligible; - Stats::Vector<> squashedInsts; - Stats::Vector<> ROBSquashedInsts; + Stats::Vector squashedInsts; + Stats::Vector ROBSquashedInsts; - Stats::Scalar<> ROBFcount; + Stats::Scalar ROBFcount; Stats::Formula ROBFullRate; - Stats::Vector<> ROBCount; // cumulative ROB occupancy + Stats::Vector ROBCount; // cumulative ROB occupancy Stats::Formula ROBOccRate; -// Stats::VectorDistribution<> ROBOccDist; +// Stats::VectorDistribution ROBOccDist; public: void dumpInsts(); diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index 2525da76e..4f8101bc0 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -411,9 +411,9 @@ class OzoneLWLSQ { //list mshrSeqNums; /** Tota number of memory ordering violations. */ - Stats::Scalar<> lsqMemOrderViolation; + Stats::Scalar lsqMemOrderViolation; - //Stats::Scalar<> dcacheStallCycles; + //Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // Make these per thread? diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index d2ccc0ff1..e80606388 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -177,7 +177,7 @@ class BaseSimpleCPU : public BaseCPU // number of simulated instructions Counter numInst; Counter startNumInst; - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; void countInst() { @@ -196,30 +196,30 @@ class BaseSimpleCPU : public BaseCPU static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1); // number of simulated memory references - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; // number of simulated loads Counter numLoad; Counter startNumLoad; // number of idle cycles - Stats::Average<> notIdleFraction; + Stats::Average notIdleFraction; Stats::Formula idleFraction; // number of cycles stalled for I-cache responses - Stats::Scalar<> icacheStallCycles; + Stats::Scalar icacheStallCycles; Counter lastIcacheStall; // number of cycles stalled for I-cache retries - Stats::Scalar<> icacheRetryCycles; + Stats::Scalar icacheRetryCycles; Counter lastIcacheRetry; // number of cycles stalled for D-cache responses - Stats::Scalar<> dcacheStallCycles; + Stats::Scalar dcacheStallCycles; Counter lastDcacheStall; // number of cycles stalled for D-cache retries - Stats::Scalar<> dcacheRetryCycles; + Stats::Scalar dcacheRetryCycles; Counter lastDcacheRetry; virtual void serialize(std::ostream &os); diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 4465ce635..99f0c2a87 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -155,9 +155,9 @@ struct ThreadState { /** Number of instructions committed. */ Counter numInst; /** Stat for number instructions committed. */ - Stats::Scalar<> numInsts; + Stats::Scalar numInsts; /** Stat for number of memory references. */ - Stats::Scalar<> numMemRefs; + Stats::Scalar numMemRefs; /** Number of simulated loads, used for tracking events based on * the number of loads committed. -- cgit v1.2.3 From ac7bda0212a22d86d9e24665998f294b96869680 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Sat, 7 Mar 2009 14:30:54 -0800 Subject: stats: fix duplicate statistics names. This generally requires providing a more meaningful name() function for a class. --- src/cpu/o3/bpred_unit.hh | 4 ++++ src/cpu/o3/bpred_unit_impl.hh | 23 ++++++++++++----------- src/cpu/o3/mem_dep_unit.hh | 8 ++++++-- src/cpu/o3/mem_dep_unit_impl.hh | 19 +++++++------------ 4 files changed, 29 insertions(+), 25 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 44f9bea79..b32d2bd23 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -62,6 +62,8 @@ class BPredUnit PredType predictor; + const std::string _name; + public: /** @@ -69,6 +71,8 @@ class BPredUnit */ BPredUnit(DerivO3CPUParams *params); + const std::string &name() const { return _name; } + /** * Registers statistics. */ diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh index ded72a1b5..2fa59280d 100644 --- a/src/cpu/o3/bpred_unit_impl.hh +++ b/src/cpu/o3/bpred_unit_impl.hh @@ -38,9 +38,10 @@ template BPredUnit::BPredUnit(DerivO3CPUParams *params) - : BTB(params->BTBEntries, - params->BTBTagSize, - params->instShiftAmt) + : _name(params->name + ".BPredUnit"), + BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) { // Setup the selected predictor. if (params->predType == "local") { @@ -73,43 +74,43 @@ void BPredUnit::regStats() { lookups - .name(name() + ".BPredUnit.lookups") + .name(name() + ".lookups") .desc("Number of BP lookups") ; condPredicted - .name(name() + ".BPredUnit.condPredicted") + .name(name() + ".condPredicted") .desc("Number of conditional branches predicted") ; condIncorrect - .name(name() + ".BPredUnit.condIncorrect") + .name(name() + ".condIncorrect") .desc("Number of conditional branches incorrect") ; BTBLookups - .name(name() + ".BPredUnit.BTBLookups") + .name(name() + ".BTBLookups") .desc("Number of BTB lookups") ; BTBHits - .name(name() + ".BPredUnit.BTBHits") + .name(name() + ".BTBHits") .desc("Number of BTB hits") ; BTBCorrect - .name(name() + ".BPredUnit.BTBCorrect") + .name(name() + ".BTBCorrect") .desc("Number of correct BTB predictions (this stat may not " "work properly.") ; usedRAS - .name(name() + ".BPredUnit.usedRAS") + .name(name() + ".usedRAS") .desc("Number of times the RAS was used to get a target.") ; RASIncorrect - .name(name() + ".BPredUnit.RASInCorrect") + .name(name() + ".RASInCorrect") .desc("Number of incorrect RAS predictions.") ; } diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index fa1c33320..4f9e7c9f7 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -65,7 +65,11 @@ class InstructionQueue; * dependence prediction schemes. */ template -class MemDepUnit { +class MemDepUnit +{ + protected: + std::string _name; + public: typedef typename Impl::DynInstPtr DynInstPtr; @@ -79,7 +83,7 @@ class MemDepUnit { ~MemDepUnit(); /** Returns the name of the memory dependence unit. */ - std::string name() const; + std::string name() const { return _name; } /** Initializes the unit with parameters and a thread id. */ void init(DerivO3CPUParams *params, int tid); diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh index 124c087f8..8754539f9 100644 --- a/src/cpu/o3/mem_dep_unit_impl.hh +++ b/src/cpu/o3/mem_dep_unit_impl.hh @@ -44,7 +44,8 @@ MemDepUnit::MemDepUnit() template MemDepUnit::MemDepUnit(DerivO3CPUParams *params) - : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), + : _name(params->name + ".memdepunit"), + depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) { DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); @@ -75,19 +76,13 @@ MemDepUnit::~MemDepUnit() #endif } -template -std::string -MemDepUnit::name() const -{ - return "memdepunit"; -} - template void MemDepUnit::init(DerivO3CPUParams *params, int tid) { DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); + _name = csprintf("%s.memDep%d", params->name, tid); id = tid; depPred.init(params->SSITSize, params->LFSTSize); @@ -98,19 +93,19 @@ void MemDepUnit::regStats() { insertedLoads - .name(name() + ".memDep.insertedLoads") + .name(name() + ".insertedLoads") .desc("Number of loads inserted to the mem dependence unit."); insertedStores - .name(name() + ".memDep.insertedStores") + .name(name() + ".insertedStores") .desc("Number of stores inserted to the mem dependence unit."); conflictingLoads - .name(name() + ".memDep.conflictingLoads") + .name(name() + ".conflictingLoads") .desc("Number of conflicting loads."); conflictingStores - .name(name() + ".memDep.conflictingStores") + .name(name() + ".conflictingStores") .desc("Number of conflicting stores."); } -- cgit v1.2.3 From 61ff48a1f834b7335c2ae615a1f855995cfab335 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Wed, 11 Mar 2009 23:05:24 -0700 Subject: cpu: fix minor endian issue with trace output (no functional change) --- src/cpu/simple/atomic.cc | 2 +- src/cpu/simple/timing.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/cpu') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index acda552d9..17f93c882 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -513,7 +513,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) // calling changeStatus() and changing it to "bad addr write" // or something. if (traceData) { - traceData->setData(data); + traceData->setData(gtoh(data)); } return fault; } diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index f398365d3..a8f86f8d2 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -564,7 +564,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) assert(split_addr <= addr || split_addr - addr < block_size); T *dataP = new T; - *dataP = TheISA::gtoh(data); + *dataP = TheISA::htog(data); _status = DTBWaitResponse; if (split_addr > addr) { RequestPtr req1, req2; -- cgit v1.2.3