From: Andreas Hansson Date: Fri, 24 Feb 2012 16:42:00 +0000 (-0500) Subject: CPU: Round-two unifying instr/data CPU ports across models X-Git-Tag: stable_2012_06_28~223 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9f07d2ce7ecf435b9a1946f15fb3491bb4636637;p=gem5.git CPU: Round-two unifying instr/data CPU ports across models 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. --- diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 276995da2..86edf62cf 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -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); } } diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 74c1a8762..8728a6e07 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -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; } diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 882d5ba41..134725f70 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -975,7 +975,7 @@ BaseDynInst::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); diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py index 40af48b19..2dcd51d45 100644 --- a/src/cpu/inorder/InOrderCPU.py +++ b/src/cpu/inorder/InOrderCPU.py @@ -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") diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 51d3cbe2f..84f5e3850 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -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" @@ -50,10 +63,11 @@ #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(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(resPool->getResource(dataPortIdx)); - return dtb_res->tlb(); + return resPool->getDataUnit()->tlb(); } Decoder * InOrderCPU::getDecoderPtr() { - FetchUnit *fetch_res = - dynamic_cast(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(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(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); } diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 5e336fd5a..d8fe5c057 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -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; - /** 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; diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 972925d94..8822a3620 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -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; } diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc index e0a00ee0f..d231aafba 100644 --- a/src/cpu/inorder/resource_pool.9stage.cc +++ b/src/cpu/inorder/resource_pool.9stage.cc @@ -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) { diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index 50d667ea7..4c01165b8 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -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) { diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index 4f05494c4..9e0952236 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -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 #include #include @@ -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 resources; - /** Resources that interface with memory objects */ - std::vector memObjects; + /** The instruction fetch unit. */ + FetchUnit *instUnit; + + /** The data load/store unit. */ + CacheUnit *dataUnit; + + std::vector resources; /** Resources that need to be updated on an inst. graduation */ std::vector gradObjects; diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 33bd9e619..10046f7f2 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -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; diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh index 416cb76d1..d9f98e42c 100644 --- a/src/cpu/inorder/resources/cache_unit.hh +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -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; diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 82f17adc9..7f24ee988 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -577,18 +577,6 @@ FullO3CPU::regStats() .prereq(miscRegfileWrites); } -template -Port * -FullO3CPU::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 void FullO3CPU::tick() diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 1c713097a..f48c0f0f2 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -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; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 3dca6e8ba..1271ea481 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -335,10 +335,10 @@ template void DefaultFetch::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::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::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; diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 97b41ad9f..209ad317b 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -302,7 +302,7 @@ DefaultIEW::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 diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index f1642be9c..02758f212 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -111,7 +111,7 @@ LSQ::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()); } } diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 4b243e862..cc2c3576f 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -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 diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index f677ed49b..8a1c9000f 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -101,8 +101,20 @@ class AtomicSimpleCPU : public BaseSimpleCPU Range 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); diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 4c02e2eb0..4b73a4519 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -67,7 +67,6 @@ // forward declarations class Checkpoint; -class MemObject; class Process; class Processor; class ThreadContext; diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index d71a96580..3d1fe081d 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -60,17 +60,6 @@ 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() { diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index ed91524cf..e0c5c89f7 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -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 §ion); diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc index 86e552afb..33c0d719c 100644 --- a/src/cpu/thread_state.cc +++ b/src/cpu/thread_state.cc @@ -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); } diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc index 5638a2350..357665184 100644 --- a/src/kern/tru64/tru64_events.cc +++ b/src/kern/tru64/tru64_events.cc @@ -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; diff --git a/src/mem/fs_translating_port_proxy.cc b/src/mem/fs_translating_port_proxy.cc index c0898a003..cbf85d1e4 100644 --- a/src/mem/fs_translating_port_proxy.cc +++ b/src/mem/fs_translating_port_proxy.cc @@ -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) { }