CPU: Round-two unifying instr/data CPU ports across models
authorAndreas Hansson <andreas.hansson@arm.com>
Fri, 24 Feb 2012 16:42:00 +0000 (11:42 -0500)
committerAndreas Hansson <andreas.hansson@arm.com>
Fri, 24 Feb 2012 16:42:00 +0000 (11:42 -0500)
This patch continues the unification of how the different CPU models
create and share their instruction and data ports. Most importantly,
it forces every CPU to have an instruction and a data port, and gives
these ports explicit getters in the BaseCPU (getDataPort and
getInstPort). The patch helps in simplifying the code, make
assumptions more explicit, andfurther ease future patches related to
the CPU ports.

The biggest changes are in the in-order model (that was not modified
in the previous unification patch), which now moves the ports from the
CacheUnit to the CPU. It also distinguishes the instruction fetch and
load-store unit from the rest of the resources, and avoids the use of
indices and casting in favour of keeping track of these two units
explicitly (since they are always there anyways). The atomic, timing
and O3 model simply return references to their already existing ports.

25 files changed:
src/cpu/base.cc
src/cpu/base.hh
src/cpu/base_dyn_inst.hh
src/cpu/inorder/InOrderCPU.py
src/cpu/inorder/cpu.cc
src/cpu/inorder/cpu.hh
src/cpu/inorder/resource.hh
src/cpu/inorder/resource_pool.9stage.cc
src/cpu/inorder/resource_pool.cc
src/cpu/inorder/resource_pool.hh
src/cpu/inorder/resources/cache_unit.cc
src/cpu/inorder/resources/cache_unit.hh
src/cpu/o3/cpu.cc
src/cpu/o3/cpu.hh
src/cpu/o3/fetch_impl.hh
src/cpu/o3/iew_impl.hh
src/cpu/o3/lsq_impl.hh
src/cpu/simple/atomic.cc
src/cpu/simple/atomic.hh
src/cpu/simple/base.hh
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/cpu/thread_state.cc
src/kern/tru64/tru64_events.cc
src/mem/fs_translating_port_proxy.cc

index 276995da2cc1c8fa2a35cebcd5a1cf0aabbefc3b..86edf62cf9e7e9552d30773d131191d155492a9e 100644 (file)
@@ -296,6 +296,21 @@ BaseCPU::regStats()
         threadContexts[0]->regStats(name());
 }
 
+Port *
+BaseCPU::getPort(const string &if_name, int idx)
+{
+    // Get the right port based on name. This applies to all the
+    // subclasses of the base CPU and relies on their implementation
+    // of getDataPort and getInstPort. In all cases there methods
+    // return a CpuPort pointer.
+    if (if_name == "dcache_port")
+        return &getDataPort();
+    else if (if_name == "icache_port")
+        return &getInstPort();
+    else
+        panic("CPU %s has no port named %s\n", name(), if_name);
+}
+
 Tick
 BaseCPU::nextCycle()
 {
@@ -363,8 +378,8 @@ BaseCPU::switchOut()
 void
 BaseCPU::takeOverFrom(BaseCPU *oldCPU)
 {
-    Port *ic = getPort("icache_port");
-    Port *dc = getPort("dcache_port");
+    CpuPort &ic = getInstPort();
+    CpuPort &dc = getDataPort();
     assert(threadContexts.size() == oldCPU->threadContexts.size());
 
     _cpuId = oldCPU->cpuId();
@@ -453,16 +468,16 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
     // 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.
-    if (!ic->isConnected()) {
-        Port *peer = oldCPU->getPort("icache_port")->getPeer();
-        ic->setPeer(peer);
-        peer->setPeer(ic);
+    if (!ic.isConnected()) {
+        Port *peer = oldCPU->getInstPort().getPeer();
+        ic.setPeer(peer);
+        peer->setPeer(&ic);
     }
 
-    if (!dc->isConnected()) {
-        Port *peer = oldCPU->getPort("dcache_port")->getPeer();
-        dc->setPeer(peer);
-        peer->setPeer(dc);
+    if (!dc.isConnected()) {
+        Port *peer = oldCPU->getDataPort().getPeer();
+        dc.setPeer(peer);
+        peer->setPeer(&dc);
     }
 }
 
index 74c1a87621bf6b6b776df5d5210b77da0aaaace3..8728a6e0734e556326867f317ee31aa7ef55fead 100644 (file)
@@ -63,7 +63,6 @@ class BranchPred;
 class CheckerCPU;
 class ThreadContext;
 class System;
-class Port;
 
 namespace TheISA
 {
@@ -147,6 +146,23 @@ class BaseCPU : public MemObject
     };
 
   public:
+
+    /**
+     * Purely virtual method that returns a reference to the data
+     * port. All subclasses must implement this method.
+     *
+     * @return a reference to the data port
+     */
+    virtual CpuPort &getDataPort() = 0;
+
+    /**
+     * Purely virtual method that returns a reference to the instruction
+     * port. All subclasses must implement this method.
+     *
+     * @return a reference to the instruction port
+     */
+    virtual CpuPort &getInstPort() = 0;
+
     /** Reads this CPU's ID. */
     int cpuId() { return _cpuId; }
 
@@ -155,6 +171,23 @@ class BaseCPU : public MemObject
     /** Reads this CPU's unique instruction requestor ID */
     MasterID instMasterId() { return _instMasterId; }
 
+    /**
+     * Get a port on this MemObject. This method is virtual to allow
+     * the subclasses of the BaseCPU to override it. All CPUs have a
+     * data and instruction port, but the Atomic CPU (in its current
+     * form) adds a port directly connected to the memory and has to
+     * override getPort.
+     *
+     * This method uses getDataPort and getInstPort to resolve the two
+     * ports.
+     *
+     * @param if_name the port name
+     * @param idx ignored index
+     *
+     * @return a pointer to the port with the given name
+     */
+    virtual Port *getPort(const std::string &if_name, int idx = -1);
+
 //    Tick currentTick;
     inline Tick frequency() const { return SimClock::Frequency / clock; }
     inline Tick ticks(int numCycles) const { return clock * numCycles; }
index 882d5ba41e0d4861cee666faee8ee1c690977c34..134725f70feead4032e14ce7f215a9478dd4810a 100644 (file)
@@ -975,7 +975,7 @@ BaseDynInst<Impl>::splitRequest(RequestPtr req, RequestPtr &sreqLow,
                                 RequestPtr &sreqHigh)
 {
     // Check to see if the request crosses the next level block boundary.
-    unsigned block_size = cpu->getDcachePort()->peerBlockSize();
+    unsigned block_size = cpu->getDataPort().peerBlockSize();
     Addr addr = req->getVaddr();
     Addr split_addr = roundDown(addr + req->getSize() - 1, block_size);
     assert(split_addr <= addr || split_addr - addr < block_size);
index 40af48b1922ff303ad08bf2a43160500db0274ea..2dcd51d459b6ff5c045ae7bbbb5ef2af4885a24b 100644 (file)
@@ -42,9 +42,6 @@ class InOrderCPU(BaseCPU):
     cachePorts = Param.Unsigned(2, "Cache Ports")
     stageWidth = Param.Unsigned(4, "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")
-
     fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)")
     memBlockSize = Param.Unsigned(64, "Memory Block Size")
 
index 51d3cbe2f1b84592398204bf0e377808c7ee9184..84f5e38509c577e22578434deb5fea96bdddfbf4 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -34,6 +46,7 @@
 #include "arch/utility.hh"
 #include "base/bigint.hh"
 #include "config/the_isa.hh"
+#include "cpu/inorder/resources/cache_unit.hh"
 #include "cpu/inorder/resources/resource_list.hh"
 #include "cpu/inorder/cpu.hh"
 #include "cpu/inorder/first_stage.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Activity.hh"
 #include "debug/InOrderCPU.hh"
+#include "debug/InOrderCachePort.hh"
 #include "debug/Interrupt.hh"
+#include "debug/Quiesce.hh"
 #include "debug/RefCount.hh"
 #include "debug/SkedCache.hh"
-#include "debug/Quiesce.hh"
 #include "params/InOrderCPU.hh"
 #include "sim/full_system.hh"
 #include "sim/process.hh"
@@ -68,6 +82,34 @@ using namespace std;
 using namespace TheISA;
 using namespace ThePipeline;
 
+InOrderCPU::CachePort::CachePort(CacheUnit *_cacheUnit) :
+    CpuPort(_cacheUnit->name() + "-cache-port", _cacheUnit->cpu),
+    cacheUnit(_cacheUnit)
+{ }
+
+bool
+InOrderCPU::CachePort::recvTiming(Packet *pkt)
+{
+    if (pkt->isError())
+        DPRINTF(InOrderCachePort, "Got error packet back for address: %x\n",
+                pkt->getAddr());
+    else if (pkt->isResponse())
+        cacheUnit->processCacheCompletion(pkt);
+    else {
+        //@note: depending on consistency model, update here
+        DPRINTF(InOrderCachePort, "Received snoop pkt %x,Ignoring\n",
+                pkt->getAddr());
+    }
+
+    return true;
+}
+
+void
+InOrderCPU::CachePort::recvRetry()
+{
+    cacheUnit->recvRetry();
+}
+
 InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
   : Event(CPU_Tick_Pri), cpu(c)
 { }
@@ -191,7 +233,10 @@ InOrderCPU::InOrderCPU(Params *params)
       _status(Idle),
       tickEvent(this),
       stageWidth(params->stageWidth),
+      resPool(new ResourcePool(this, params)),
       timeBuffer(2 , 2),
+      dataPort(resPool->getDataUnit()),
+      instPort(resPool->getInstUnit()),
       removeInstsThisCycle(false),
       activityRec(params->name, NumStages, 10, params->activity),
       system(params->system),
@@ -207,8 +252,6 @@ InOrderCPU::InOrderCPU(Params *params)
 {    
     cpu_params = params;
 
-    resPool = new ResourcePool(this, params);
-
     // Resize for Multithreading CPUs
     thread.resize(numThreads);
 
@@ -240,17 +283,6 @@ InOrderCPU::InOrderCPU(Params *params)
         }
     }
 
-    // Bind the fetch & data ports from the resource pool.
-    fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
-    if (fetchPortIdx == 0) {
-        fatal("Unable to find port to fetch instructions from.\n");
-    }
-
-    dataPortIdx = resPool->getPortIdx(params->dataMemPort);
-    if (dataPortIdx == 0) {
-        fatal("Unable to find port for data.\n");
-    }
-
     for (ThreadID tid = 0; tid < numThreads; ++tid) {
         pc[tid].set(0);
         lastCommittedPC[tid].set(0);
@@ -775,12 +807,6 @@ InOrderCPU::init()
     resPool->init();
 }
 
-Port*
-InOrderCPU::getPort(const std::string &if_name, int idx)
-{
-    return resPool->getPort(if_name, idx);
-}
-
 Fault
 InOrderCPU::hwrei(ThreadID tid)
 {
@@ -1735,8 +1761,7 @@ InOrderCPU::syscall(int64_t callnum, ThreadID tid)
 TheISA::TLB*
 InOrderCPU::getITBPtr()
 {
-    CacheUnit *itb_res =
-        dynamic_cast<CacheUnit*>(resPool->getResource(fetchPortIdx));
+    CacheUnit *itb_res = resPool->getInstUnit();
     return itb_res->tlb();
 }
 
@@ -1744,38 +1769,26 @@ InOrderCPU::getITBPtr()
 TheISA::TLB*
 InOrderCPU::getDTBPtr()
 {
-    CacheUnit *dtb_res =
-        dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
-    return dtb_res->tlb();
+    return resPool->getDataUnit()->tlb();
 }
 
 Decoder *
 InOrderCPU::getDecoderPtr()
 {
-    FetchUnit *fetch_res =
-        dynamic_cast<FetchUnit*>(resPool->getResource(fetchPortIdx));
-    return &fetch_res->decoder;
+    return &resPool->getInstUnit()->decoder;
 }
 
 Fault
 InOrderCPU::read(DynInstPtr inst, Addr addr,
                  uint8_t *data, unsigned size, unsigned flags)
 {
-    //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
-    //       you want to run w/out caches?
-    CacheUnit *cache_res = 
-        dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
-
-    return cache_res->read(inst, addr, data, size, flags);
+    return resPool->getDataUnit()->read(inst, addr, data, size, flags);
 }
 
 Fault
 InOrderCPU::write(DynInstPtr inst, uint8_t *data, unsigned size,
                   Addr addr, unsigned flags, uint64_t *write_res)
 {
-    //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
-    //       you want to run w/out caches?
-    CacheUnit *cache_res =
-        dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
-    return cache_res->write(inst, data, size, addr, flags, write_res);
+    return resPool->getDataUnit()->write(inst, data, size, addr, flags,
+                                         write_res);
 }
index 5e336fd5af93685bd23dd7eaf3876403525bce88..d8fe5c0573d44f0a8db00362bae2c14db47411cd 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -61,6 +73,7 @@
 #include "sim/eventq.hh"
 #include "sim/process.hh"
 
+class CacheUnit;
 class ThreadContext;
 class MemInterface;
 class MemObject;
@@ -96,6 +109,12 @@ class InOrderCPU : public BaseCPU
     /* Destructor */
     ~InOrderCPU();
     
+    /** Return a reference to the data port. */
+    virtual CpuPort &getDataPort() { return dataPort; }
+
+    /** Return a reference to the instruction port. */
+    virtual CpuPort &getInstPort() { return instPort; }
+
     /** CPU ID */
     int cpu_id;
 
@@ -132,6 +151,31 @@ class InOrderCPU : public BaseCPU
     /** Overall CPU status. */
     Status _status;
   private:
+
+    /**
+     * CachePort class for the in-order CPU, interacting with a
+     * specific CacheUnit in the pipeline.
+     */
+    class CachePort : public CpuPort
+    {
+
+      private:
+        /** Pointer to cache unit */
+        CacheUnit *cacheUnit;
+
+      public:
+        /** Default constructor. */
+        CachePort(CacheUnit *_cacheUnit);
+
+      protected:
+
+        /** Timing version of receive */
+        bool recvTiming(PacketPtr pkt);
+
+        /** Handles doing a retry of a failed timing request. */
+        void recvRetry();
+    };
+
     /** Define TickEvent for the CPU */
     class TickEvent : public Event
     {
@@ -244,6 +288,10 @@ class InOrderCPU : public BaseCPU
                           CPUEventPri event_pri = InOrderCPU_Pri);
 
   public:
+
+    /** Width (processing bandwidth) of each stage */
+    int stageWidth;
+
     /** Interface between the CPU and CPU resources. */
     ResourcePool *resPool;
 
@@ -257,22 +305,9 @@ class InOrderCPU : public BaseCPU
     /** Used by resources to signify a denied access to a resource. */
     ResourceRequest *dummyReq[ThePipeline::MaxThreads];
 
-    /** 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];
 
-    /** Width (processing bandwidth) of each stage */
-    int stageWidth;
-
     /** Program Counters */
     TheISA::PCState pc[ThePipeline::MaxThreads];
 
@@ -396,6 +431,14 @@ class InOrderCPU : public BaseCPU
         }
     };
 
+  private:
+
+    /** Data port. Note that it has to appear after the resPool. */
+    CachePort dataPort;
+
+    /** Instruction port. Note that it has to appear after the resPool. */
+    CachePort instPort;
+
   public:
 
     /** Registers statistics. */
@@ -409,9 +452,6 @@ class InOrderCPU : public BaseCPU
     /** Initialize the CPU */
     void init();
 
-    /** Get a Memory Port */
-    Port* getPort(const std::string &if_name, int idx = 0);
-
     /** HW return from error interrupt. */
     Fault hwrei(ThreadID tid);
 
@@ -811,12 +851,6 @@ class InOrderCPU : public BaseCPU
     /** Pointers to all of the threads in the CPU. */
     std::vector<Thread *> 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;
 
index 972925d94094f24c6ae990b36bee39f9d273b290..8822a3620dde5af837cd9656361bf81d9f2d5945 100644 (file)
@@ -70,12 +70,6 @@ class 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; }
 
index e0a00ee0f767c4c996490c1354e9f1ff06e1a01b..d231aafba7c702b0d838472375b81f98b264e991 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -39,7 +51,7 @@ using namespace std;
 using namespace ThePipeline;
 
 ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
-    : cpu(_cpu)
+    : cpu(_cpu), instUnit(NULL), dataUnit(NULL)
 {
     //@todo: use this function to instantiate the resources in resource pool. This will help in the
     //auto-generation of this pipeline model.
@@ -53,9 +65,13 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
 
     resources.push_back(new TLBUnit("itlb", ITLB, StageWidth, 0, _cpu, params));
 
-    memObjects.push_back(ICache);
-    resources.push_back(new CacheUnit("icache_port", ICache,
-            StageWidth * MaxThreads, 0, _cpu, params));
+
+    // Keep track of the instruction fetch unit so we can easily
+    // provide a pointer to it in the CPU.
+    instUnit = new FetchUnit("icache_port", ICache,
+                             StageWidth * MaxThreads, 0, _cpu,
+                             params);
+    resources.push_back(instUnit);
 
     resources.push_back(new DecodeUnit("decode_unit", Decode, StageWidth, 0,
             _cpu, params));
@@ -84,9 +100,12 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
 
     resources.push_back(new TLBUnit("dtlb", DTLB, StageWidth, 0, _cpu, params));
 
-    memObjects.push_back(DCache);
-    resources.push_back(new CacheUnit("dcache_port", DCache,
-            StageWidth * MaxThreads, 0, _cpu, params));
+    // Keep track of the data load/store unit so we can easily provide
+    // a pointer to it in the CPU.
+    dataUnit = new CacheUnit("dcache_port", DCache,
+                             StageWidth * MaxThreads, 0, _cpu,
+                             params);
+    resources.push_back(dataUnit);
 
     resources.push_back(new GraduationUnit("graduation_unit", Grad,
             StageWidth * MaxThreads, 0, _cpu, params));
@@ -119,34 +138,6 @@ ResourcePool::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)
 {
index 50d667ea7595222c051dead0cfea5df3dd7587f6..4c01165b89d7eda4fc0e5dc91bbc47a2dfd205ab 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -40,7 +52,7 @@ using namespace std;
 using namespace ThePipeline;
 
 ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
-    : cpu(_cpu)
+    : cpu(_cpu), instUnit(NULL), dataUnit(NULL)
 {
     //@todo: use this function to instantiate the resources in resource pool. 
     //This will help in the auto-generation of this pipeline model.
@@ -54,10 +66,12 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
     resources.push_back(new FetchSeqUnit("fetch_seq_unit", FetchSeq,
                                          stage_width * 2, 0, _cpu, params));
 
-    memObjects.push_back(ICache);
-    resources.push_back(new FetchUnit("icache_port", ICache,
-                                      stage_width * 2 + MaxThreads, 0, _cpu,
-                                      params));
+    // Keep track of the instruction fetch unit so we can easily
+    // provide a pointer to it in the CPU.
+    instUnit = new FetchUnit("icache_port", ICache,
+                             stage_width * 2 + MaxThreads, 0, _cpu,
+                             params);
+    resources.push_back(instUnit);
 
     resources.push_back(new DecodeUnit("decode_unit", Decode,
                                        stage_width, 0, _cpu, params));
@@ -84,10 +98,12 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
                                         _cpu,
                                         params));
 
-    memObjects.push_back(DCache);
-    resources.push_back(new CacheUnit("dcache_port", DCache, 
-                                      stage_width * 2 + MaxThreads, 0, _cpu,
-                                      params));
+    // Keep track of the data load/store unit so we can easily provide
+    // a pointer to it in the CPU.
+    dataUnit = new CacheUnit("dcache_port", DCache,
+                             stage_width * 2 + MaxThreads, 0, _cpu,
+                             params);
+    resources.push_back(dataUnit);
 
     gradObjects.push_back(BPred);
     resources.push_back(new GraduationUnit("graduation_unit", Grad,
@@ -151,58 +167,6 @@ ResourcePool::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;
-}
-
-unsigned
-ResourcePool::getResIdx(const std::string &res_name)
-{
-    DPRINTF(Resource, "Finding Resource Idx for %s.\n", res_name);
-
-    int num_resources = resources.size();
-
-    for (int idx = 0; idx < num_resources; idx++) {
-        if (resources[idx]->name() == res_name)
-            return idx;
-    }
-
-    panic("Can't find resource idx for: %s\n", res_name);
-    return 0;
-}
-
 unsigned
 ResourcePool::getResIdx(const ThePipeline::ResourceId &res_id)
 {
index 4f05494c45eb826f09cd3e9f2d903aded195aa59..9e0952236fec8408a46cdaafca772c66acc39738 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 MIPS Technologies, Inc.
  * All rights reserved.
  *
@@ -32,7 +44,6 @@
 #ifndef __CPU_INORDER_RESOURCE_POOL_HH__
 #define __CPU_INORDER_RESOURCE_POOL_HH__
 
-#include <list>
 #include <string>
 #include <vector>
 
@@ -46,9 +57,9 @@
 #include "sim/eventq.hh"
 #include "sim/sim_object.hh"
 
+class CacheUnit;
 class Event;
-class InOrderCPU;
-class Resource;
+class FetchUnit;
 class ResourceEvent;
 
 class ResourcePool {
@@ -142,14 +153,7 @@ class ResourcePool {
     /** 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 &port_name);
-
     /** Returns a specific resource. */
-    unsigned getResIdx(const std::string &res_name);
     unsigned getResIdx(const ThePipeline::ResourceId &res_id);
 
     /** Returns a pointer to a resource */
@@ -215,11 +219,29 @@ class ResourcePool {
 
     DynInstPtr dummyInst[ThePipeline::MaxThreads];
 
+    /**
+     * Get a pointer to the (always present) instruction fetch unit.
+     *
+     * @return the instruction unit
+     */
+    FetchUnit *getInstUnit() const { return instUnit; }
+
+    /**
+     * Get a pointer to the (always present) data load/store unit.
+     *
+     * @return the data cache unit
+     */
+    CacheUnit *getDataUnit() const { return dataUnit; }
+
   private:
-    std::vector<Resource *> resources;
 
-    /** Resources that interface with memory objects */
-    std::vector<int> memObjects;
+    /** The instruction fetch unit. */
+    FetchUnit *instUnit;
+
+    /** The data load/store unit. */
+    CacheUnit *dataUnit;
+
+    std::vector<Resource *> resources;
 
     /** Resources that need to be updated on an inst. graduation */
     std::vector<int> gradObjects;
index 33bd9e619eb5023f474d1db1387d823a00555c8f..10046f7f2f120f107c852b5e71225c4a2ffa1956 100644 (file)
@@ -67,62 +67,23 @@ printMemData(uint8_t *data, unsigned size)
 }
 #endif
 
-Tick
-CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
-{
-    panic("%s doesn't expect recvAtomic callback!", cachePortUnit->name());
-    return curTick();
-}
-
-void
-CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
-{
-    DPRINTF(InOrderCachePort, "Doesn't update state on a recvFunctional."
-            "Ignoring packet for %x.\n", pkt->getAddr());
-}
-
-void
-CacheUnit::CachePort::recvRangeChange()
-{
-}
-
-bool
-CacheUnit::CachePort::recvTiming(Packet *pkt)
-{
-    if (pkt->isError())
-        DPRINTF(InOrderCachePort, "Got error packet back for address: %x\n",
-                pkt->getAddr());
-    else if (pkt->isResponse())
-        cachePortUnit->processCacheCompletion(pkt);
-    else {
-        //@note: depending on consistency model, update here
-        DPRINTF(InOrderCachePort, "Received snoop pkt %x,Ignoring\n", pkt->getAddr());
-    }
-
-    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),
-      cachePortBlocked(false)
+      cachePort(NULL), cachePortBlocked(false)
 {
-    cachePort = new CachePort(this);
-
     // Hard-Code Selection For Now
-    if (res_name == "icache_port")
+    if (res_id == ICache)
         _tlb = params->itb;
-    else if (res_name == "dcache_port")
+    else if (res_id == DCache)
         _tlb = params->dtb;
     else
         fatal("Unrecognized TLB name passed by user");
 
+    // Note that the CPU port is not yet instantiated (as it is done
+    // after the resource pool), we delay setting the cachePort
+    // pointer until init().
+
     for (int i=0; i < MaxThreads; i++) {
         tlbBlocked[i] = false;
         tlbBlockSeqNum[i] = 0;
@@ -136,23 +97,22 @@ CacheUnit::tlb()
 
 }
 
-Port *
-CacheUnit::getPort(const string &if_name, int idx)
-{
-    if (if_name == resName)
-        return cachePort;
-    else
-        return NULL;
-}
-
 void
 CacheUnit::init()
 {
+    // Get the appropriate port from the CPU based on the resource name.
+    if (id == ICache) {
+        cachePort = &cpu->getInstPort();
+    } else if (id == DCache) {
+        cachePort = &cpu->getDataPort();
+    }
+    assert(cachePort != NULL);
+
     for (int i = 0; i < width; i++) {
         reqs[i] = new CacheRequest(this);
     }
 
-    cacheBlkSize = this->cachePort->peerBlockSize();
+    cacheBlkSize = cachePort->peerBlockSize();
     cacheBlkMask = cacheBlkSize  - 1;
 
     initSlots();
@@ -446,7 +406,7 @@ CacheUnit::read(DynInstPtr inst, Addr addr,
     assert(cache_req && "Can't Find Instruction for Read!");
 
     // The block size of our peer
-    unsigned blockSize = this->cachePort->peerBlockSize();
+    unsigned blockSize = cacheBlkSize;
 
     //The size of the data we're trying to read.
     int fullSize = size;
@@ -541,7 +501,7 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size,
     assert(cache_req && "Can't Find Instruction for Write!");
 
     // The block size of our peer
-    unsigned blockSize = this->cachePort->peerBlockSize();
+    unsigned blockSize = cacheBlkSize;
 
     //The size of the data we're trying to write.
     int fullSize = size;
index 416cb76d1f39388ec5674f97336c7b99adb222a1..d9f98e42cc3af21d8db7f59c0de9bb798a8e7353 100644 (file)
@@ -73,39 +73,6 @@ class CacheUnit : public Resource
     };
 
   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)
-        { }
-
-      protected:
-        /** Atomic version of receive.  Panics. */
-        Tick recvAtomic(PacketPtr pkt);
-
-        /** Functional version of receive.*/
-        void recvFunctional(PacketPtr pkt);
-
-        /** Receives range changes. */
-        void recvRangeChange();
-
-        /** Timing version of receive */
-        bool recvTiming(PacketPtr pkt);
-
-        /** Handles doing a retry of a failed fetch. */
-        void recvRetry();
-    };
 
     void init();
 
@@ -149,9 +116,6 @@ class CacheUnit : public Resource
     void trap(Fault fault, ThreadID tid, DynInstPtr inst);
 
     void recvRetry();
-
-    /** Returns a specific port. */
-    Port *getPort(const std::string &if_name, int idx);
     
     Fault read(DynInstPtr inst, Addr addr,
                uint8_t *data, unsigned size, unsigned flags);
@@ -175,7 +139,7 @@ class CacheUnit : public Resource
     
   protected:
     /** Cache interface. */
-    CachePort *cachePort;
+    Port *cachePort;
 
     bool cachePortBlocked;
 
index 82f17adc9561d5359b4ed14ce1358275ff09a60a..7f24ee988ad647ce06c62311db2e864730fbbee4 100644 (file)
@@ -577,18 +577,6 @@ FullO3CPU<Impl>::regStats()
         .prereq(miscRegfileWrites);
 }
 
-template <class Impl>
-Port *
-FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
-{
-    if (if_name == "dcache_port")
-        return &dcachePort;
-    else if (if_name == "icache_port")
-        return &icachePort;
-    else
-        panic("No Such Port\n");
-}
-
 template <class Impl>
 void
 FullO3CPU<Impl>::tick()
index 1c713097a3ab89884b9f295fcbd1334fec5442b4..f48c0f0f20f383620f3042b838d8664e267bb700 100644 (file)
@@ -361,9 +361,6 @@ class FullO3CPU : public BaseO3CPU
         this->dtb->demapPage(vaddr, asn);
     }
 
-    /** Returns a specific port. */
-    Port *getPort(const std::string &if_name, int idx);
-
     /** Ticks CPU, calling tick() on each stage, and checking the overall
      *  activity to see if the CPU should deschedule itself.
      */
@@ -781,10 +778,10 @@ class FullO3CPU : public BaseO3CPU
     }
 
     /** Used by the fetch unit to get a hold of the instruction port. */
-    Port* getIcachePort() { return &icachePort; }
+    virtual CpuPort &getInstPort() { return icachePort; }
 
     /** Get the dcache port (used to find block size for translations). */
-    Port* getDcachePort() { return &dcachePort; }
+    virtual CpuPort &getDataPort() { return dcachePort; }
 
     Addr lockAddr;
 
index 3dca6e8baafb50352df217221d12269bae35d7a4..1271ea481bc0fed8b3b9aef49832a5c631ffe1f1 100644 (file)
@@ -335,10 +335,10 @@ template<class Impl>
 void
 DefaultFetch<Impl>::setIcache()
 {
-    assert(cpu->getIcachePort()->isConnected());
+    assert(cpu->getInstPort().isConnected());
 
     // Size of cache block.
-    cacheBlkSize = cpu->getIcachePort()->peerBlockSize();
+    cacheBlkSize = cpu->getInstPort().peerBlockSize();
 
     // Create mask to get rid of offset bits.
     cacheBlkMask = (cacheBlkSize - 1);
@@ -623,7 +623,7 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
         fetchedCacheLines++;
 
         // Access the cache.
-        if (!cpu->getIcachePort()->sendTiming(data_pkt)) {
+        if (!cpu->getInstPort().sendTiming(data_pkt)) {
             assert(retryPkt == NULL);
             assert(retryTid == InvalidThreadID);
             DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
@@ -1358,7 +1358,7 @@ DefaultFetch<Impl>::recvRetry()
         assert(retryTid != InvalidThreadID);
         assert(fetchStatus[retryTid] == IcacheWaitRetry);
 
-        if (cpu->getIcachePort()->sendTiming(retryPkt)) {
+        if (cpu->getInstPort().sendTiming(retryPkt)) {
             fetchStatus[retryTid] = IcacheWaitResponse;
             retryPkt = NULL;
             retryTid = InvalidThreadID;
index 97b41ad9f63c6b969040f5fc9b394663d096ce60..209ad317b3e162e1076e946e33b2af28197f142d 100644 (file)
@@ -302,7 +302,7 @@ DefaultIEW<Impl>::initStage()
 // Initialize the checker's dcache port here
 #if USE_CHECKER
     if (cpu->checker) {
-        cpu->checker->setDcachePort(cpu->getDcachePort());
+        cpu->checker->setDcachePort(&cpu->getDataPort());
      }
 #endif
 
index f1642be9c0fada6e4b0431cf0dac8c31a317c4c6..02758f212350d768b8db949bc37b5caabb4412b0 100644 (file)
@@ -111,7 +111,7 @@ LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
     for (ThreadID tid = 0; tid < numThreads; tid++) {
         thread[tid].init(cpu, iew_ptr, params, this,
                          maxLQEntries, maxSQEntries, tid);
-        thread[tid].setDcachePort(cpu_ptr->getDcachePort());
+        thread[tid].setDcachePort(&cpu_ptr->getDataPort());
     }
 }
 
index 4b243e8626994829be546a1b700598d8f63ce1cd..cc2c3576f31cca2afd95a8c645de6cbba9e77e3a 100644 (file)
@@ -68,16 +68,12 @@ AtomicSimpleCPU::TickEvent::description() const
 Port *
 AtomicSimpleCPU::getPort(const string &if_name, int idx)
 {
-    if (if_name == "dcache_port")
-        return &dcachePort;
-    else if (if_name == "icache_port")
-        return &icachePort;
-    else if (if_name == "physmem_port") {
+    if (if_name == "physmem_port") {
         hasPhysMemPort = true;
         return &physmemPort;
+    } else {
+        return BaseCPU::getPort(if_name, idx);
     }
-    else
-        panic("No Such Port\n");
 }
 
 void
index f677ed49b5d2bf2f2dd27255cf295614a21e4fb0..8a1c9000fe5b4c5a74b4cf0edfdf93aec7a2d916 100644 (file)
@@ -101,8 +101,20 @@ class AtomicSimpleCPU : public BaseSimpleCPU
 
     Range<Addr> physMemAddr;
 
+  protected:
+
+    /** Return a reference to the data port. */
+    virtual CpuPort &getDataPort() { return dcachePort; }
+
+    /** Return a reference to the instruction port. */
+    virtual CpuPort &getInstPort() { return icachePort; }
+
   public:
 
+    /**
+     * Override the getPort of the BaseCPU so that we can provide a pointer
+     * to the physmemPort, unique to the Atomic CPU.
+     */
     virtual Port *getPort(const std::string &if_name, int idx = -1);
 
     virtual void serialize(std::ostream &os);
index 4c02e2eb0acd404bb79f607af3e3ff8a24f054e7..4b73a45196a63a13348627e5a897fcd5e0dc1e7d 100644 (file)
@@ -67,7 +67,6 @@
 
 // forward declarations
 class Checkpoint;
-class MemObject;
 class Process;
 class Processor;
 class ThreadContext;
index d71a96580fd48c3aa872ca13560deb3f889d61ef..3d1fe081d99029e151e81ad833c3a83a024b16da 100644 (file)
 using namespace std;
 using namespace TheISA;
 
-Port *
-TimingSimpleCPU::getPort(const std::string &if_name, int idx)
-{
-    if (if_name == "dcache_port")
-        return &dcachePort;
-    else if (if_name == "icache_port")
-        return &icachePort;
-    else
-        panic("No Such Port\n");
-}
-
 void
 TimingSimpleCPU::init()
 {
index ed91524cfb58f9c0e3fdfa56f66836a1250ff895..e0c5c89f79f4c8360fa3da556a7d8895c3add2ec 100644 (file)
@@ -231,9 +231,15 @@ class TimingSimpleCPU : public BaseSimpleCPU
 
     Tick previousTick;
 
-  public:
+  protected:
+
+     /** Return a reference to the data port. */
+    virtual CpuPort &getDataPort() { return dcachePort; }
 
-    virtual Port *getPort(const std::string &if_name, int idx = -1);
+    /** Return a reference to the instruction port. */
+    virtual CpuPort &getInstPort() { return icachePort; }
+
+  public:
 
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
index 86e552afbea8a718bdea2a4d70b7013a09241958..33c0d719cc2a130a2f3ef55b64cda74e5f214660 100644 (file)
@@ -106,7 +106,7 @@ ThreadState::initMemProxies(ThreadContext *tc)
     // (i.e. due to restoring from a checkpoint and later switching
     // in.
     if (physProxy == NULL)
-        physProxy = new PortProxy(*baseCpu->getPort("dcache_port"));
+        physProxy = new PortProxy(baseCpu->getDataPort());
     if (virtProxy == NULL)
         virtProxy = new FSTranslatingPortProxy(tc);
 }
index 5638a2350d9ce283dabae523cb4f496c7bb39156..3576651840e2bdbe08128d7ee8c8a43f236c1b9e 100644 (file)
@@ -60,9 +60,9 @@ BadAddrEvent::process(ThreadContext *tc)
     AddrRangeIter iter;
     bool found = false;
 
-    Port* dataPort = tc->getCpuPtr()->getPort("dcache_port");
+    Port &dataPort = tc->getCpuPtr()->getDataPort();
 
-    AddrRangeList resp = dataPort->getPeer()->getAddrRanges();
+    AddrRangeList resp = dataPort.getPeer()->getAddrRanges();
     for (iter = resp.begin(); iter != resp.end(); iter++) {
         if (*iter == (K0Seg2Phys(a0) & PAddrImplMask))
             found = true;
index c0898a0035e376da3220ab2f1fbdf8eebc7a71ef..cbf85d1e43d2a51403079fac5b0c0d37ce2f40b2 100644 (file)
@@ -54,7 +54,7 @@
 using namespace TheISA;
 
 FSTranslatingPortProxy::FSTranslatingPortProxy(ThreadContext *tc)
-    : PortProxy(*(tc->getCpuPtr()->getPort("dcache_port"))), _tc(tc)
+    : PortProxy(tc->getCpuPtr()->getDataPort()), _tc(tc)
 {
 }