From b3f930c884ef23e4d784553fdccc91a772334fd7 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 17 Jan 2012 12:55:08 -0600 Subject: [PATCH] CPU: Moving towards a more general port across CPU models This patch performs minimal changes to move the instruction and data ports from specialised subclasses to the base CPU (to the largest degree possible). Ultimately it servers to make the CPU(s) have a well-defined interface to the memory sub-system. --- src/cpu/BaseCPU.py | 7 +- src/cpu/base.cc | 62 ++++++++++++++ src/cpu/base.hh | 63 +++++++++++++++ src/cpu/inorder/InOrderCPU.py | 3 - src/cpu/o3/O3CPU.py | 3 - src/cpu/o3/cpu.cc | 65 ++++++++++++++- src/cpu/o3/cpu.hh | 87 +++++++++++++++++++- src/cpu/o3/fetch.hh | 56 +------------ src/cpu/o3/fetch_impl.hh | 87 +++----------------- src/cpu/o3/iew.hh | 3 - src/cpu/o3/lsq.hh | 76 ++++++------------ src/cpu/o3/lsq_impl.hh | 129 +++++++++++++----------------- src/cpu/simple/AtomicSimpleCPU.py | 4 - src/cpu/simple/TimingSimpleCPU.py | 3 - src/cpu/simple/atomic.cc | 45 ----------- src/cpu/simple/atomic.hh | 37 ++++----- src/cpu/simple/timing.cc | 38 +-------- src/cpu/simple/timing.hh | 43 +++++----- 18 files changed, 409 insertions(+), 402 deletions(-) diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 665d42af0..6800b4c91 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -152,9 +152,12 @@ class BaseCPU(MemObject): tracer = Param.InstTracer(default_tracer, "Instruction tracer") - _cached_ports = [] + icache_port = Port("Instruction Port") + dcache_port = Port("Data Port") + _cached_ports = ['icache_port', 'dcache_port'] + if buildEnv['TARGET_ISA'] in ['x86', 'arm'] and buildEnv['FULL_SYSTEM']: - _cached_ports = ["itb.walker.port", "dtb.walker.port"] + _cached_ports += ["itb.walker.port", "dtb.walker.port"] _uncached_ports = [] if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']: diff --git a/src/cpu/base.cc b/src/cpu/base.cc index c37f45856..2fe41cd4d 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2011 Regents of the University of California * All rights reserved. @@ -485,3 +497,53 @@ BaseCPU::traceFunctionsInternal(Addr pc) functionEntryTick = curTick(); } } + +bool +BaseCPU::CpuPort::recvTiming(PacketPtr pkt) +{ + panic("BaseCPU doesn't expect recvTiming callback!"); + return true; +} + +void +BaseCPU::CpuPort::recvRetry() +{ + panic("BaseCPU doesn't expect recvRetry callback!"); +} + +Tick +BaseCPU::CpuPort::recvAtomic(PacketPtr pkt) +{ + panic("BaseCPU doesn't expect recvAtomic callback!"); + return curTick(); +} + +void +BaseCPU::CpuPort::recvFunctional(PacketPtr pkt) +{ + // No internal storage to update (in the general case). In the + // long term this should never be called, but that assumed a split + // into master/slave and request/response. +} + +void +BaseCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) { + if (!snoopRangeSent) { + snoopRangeSent = true; + sendStatusChange(Port::RangeChange); + } + return; + } + + panic("BaseCPU doesn't expect recvStatusChange callback!"); +} + +void +BaseCPU::CpuPort::getDeviceAddressRanges(AddrRangeList& resp, + bool& snoop) +{ + resp.clear(); + snoop = false; +} diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 638556deb..5622031f8 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2011 Regents of the University of California * All rights reserved. @@ -95,6 +107,57 @@ class BaseCPU : public MemObject // therefore no setCpuId() method is provided int _cpuId; + /** + * Define a base class for the CPU ports (instruction and data) + * that is refined in the subclasses. This class handles the + * common cases, i.e. the functional accesses and the status + * changes and address range queries. The default behaviour for + * both atomic and timing access is to panic and the corresponding + * subclasses have to override these methods. + */ + class CpuPort : public Port + { + public: + + /** + * Create a CPU port with a name and a structural owner. + * + * @param _name port name including the owner + * @param _name structural owner of this port + */ + CpuPort(const std::string& _name, MemObject* _owner) : + Port(_name, _owner), snoopRangeSent(false) + { } + + protected: + + virtual bool recvTiming(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvRetry(); + + void recvFunctional(PacketPtr pkt); + + void recvStatusChange(Status status); + + /** + * Add CPU ports are master ports and do not respond to any + * address ranges. Note that the LSQ snoops for specific ISAs + * and thus has to override this method. + * + * @param resp list of ranges this port responds to + * @param snoop indicating if the port snoops or not + */ + virtual void getDeviceAddressRanges(AddrRangeList& resp, + bool& snoop); + + private: + + bool snoopRangeSent; + + }; + public: /** Reads this CPU's ID. */ int cpuId() { return _cpuId; } diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py index 4766a1ac1..40af48b19 100644 --- a/src/cpu/inorder/InOrderCPU.py +++ b/src/cpu/inorder/InOrderCPU.py @@ -44,9 +44,6 @@ class InOrderCPU(BaseCPU): 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") - _cached_ports = ['icache_port', 'dcache_port'] fetchBuffSize = Param.Unsigned(4, "Fetch Buffer Size (Number of Cache Blocks Stored)") memBlockSize = Param.Unsigned(64, "Memory Block Size") diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index 2a5b6782f..9dfcc8b9e 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -53,9 +53,6 @@ class DerivO3CPU(BaseCPU): checker.dtb = Parent.dtb cachePorts = Param.Unsigned(200, "Cache Ports") - icache_port = Port("Instruction Port") - dcache_port = Port("Data Port") - _cached_ports = BaseCPU._cached_ports + ['icache_port', 'dcache_port'] decodeToFetchDelay = Param.Unsigned(1, "Decode to fetch delay") renameToFetchDelay = Param.Unsigned(1 ,"Rename to fetch delay") diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index ee0c3a88a..7e0b4cee7 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2004-2006 The Regents of The University of Michigan * Copyright (c) 2011 Regents of the University of California * All rights reserved. @@ -79,6 +91,42 @@ BaseO3CPU::regStats() BaseCPU::regStats(); } +template +bool +FullO3CPU::IcachePort::recvTiming(PacketPtr pkt) +{ + DPRINTF(O3CPU, "Fetch unit received timing\n"); + if (pkt->isResponse()) { + // We shouldn't ever get a block in ownership state + assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); + + fetch->processCacheCompletion(pkt); + } + //else Snooped a coherence request, just return + return true; +} + +template +void +FullO3CPU::IcachePort::recvRetry() +{ + fetch->recvRetry(); +} + +template +bool +FullO3CPU::DcachePort::recvTiming(PacketPtr pkt) +{ + return lsq->recvTiming(pkt); +} + +template +void +FullO3CPU::DcachePort::recvRetry() +{ + lsq->recvRetry(); +} + template FullO3CPU::TickEvent::TickEvent(FullO3CPU *c) : Event(CPU_Tick_Pri), cpu(c) @@ -194,6 +242,9 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) TheISA::NumMiscRegs * numThreads, TheISA::ZeroReg), + icachePort(&fetch, this), + dcachePort(&iew.ldstQueue, this), + timeBuffer(params->backComSize, params->forwardComSize), fetchQueue(params->backComSize, params->forwardComSize), decodeQueue(params->backComSize, params->forwardComSize), @@ -218,6 +269,7 @@ FullO3CPU::FullO3CPU(DerivO3CPUParams *params) if (params->checker) { BaseCPU *temp_checker = params->checker; checker = dynamic_cast *>(temp_checker); + checker->setIcachePort(&icachePort); #if FULL_SYSTEM checker->setSystem(params->system); #endif @@ -528,9 +580,9 @@ Port * FullO3CPU::getPort(const std::string &if_name, int idx) { if (if_name == "dcache_port") - return iew.getDcachePort(); + return &dcachePort; else if (if_name == "icache_port") - return fetch.getIcachePort(); + return &icachePort; else panic("No Such Port\n"); } @@ -606,6 +658,13 @@ FullO3CPU::init() for (ThreadID tid = 0; tid < numThreads; ++tid) thread[tid]->inSyscall = true; + // this CPU could still be unconnected if we are restoring from a + // checkpoint and this CPU is to be switched in, thus we can only + // do this here if the instruction port is actually connected, if + // not we have to do it as part of takeOverFrom + if (icachePort.isConnected()) + fetch.setIcache(); + #if FULL_SYSTEM for (ThreadID tid = 0; tid < numThreads; tid++) { ThreadContext *src_tc = threadContexts[tid]; @@ -1170,7 +1229,7 @@ FullO3CPU::takeOverFrom(BaseCPU *oldCPU) activityRec.reset(); - BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort()); + BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); fetch.takeOverFrom(); decode.takeOverFrom(); diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 652e6d99a..1dd49a4f3 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2004-2005 The Regents of The University of Michigan * Copyright (c) 2011 Regents of the University of California * All rights reserved. @@ -118,6 +130,70 @@ class FullO3CPU : public BaseO3CPU Status _threadStatus[Impl::MaxThreads]; private: + + /** + * IcachePort class for instruction fetch. + */ + class IcachePort : public CpuPort + { + protected: + /** Pointer to fetch. */ + DefaultFetch *fetch; + + public: + /** Default constructor. */ + IcachePort(DefaultFetch *_fetch, FullO3CPU* _cpu) + : CpuPort(_fetch->name() + "-iport", _cpu), fetch(_fetch) + { } + + protected: + + /** 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(); + }; + + /** + * DcachePort class for the load/store queue. + */ + class DcachePort : public CpuPort + { + protected: + + /** Pointer to LSQ. */ + LSQ *lsq; + + public: + /** Default constructor. */ + DcachePort(LSQ *_lsq, FullO3CPU* _cpu) + : CpuPort(_lsq->name() + "-dport", _cpu), lsq(_lsq) + { } + + protected: + + /** Timing version of receive. Handles writing back and + * completing the load or store that has returned from + * memory. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of the previous send. */ + virtual void recvRetry(); + + /** + * As this CPU requires snooping to maintain the load store queue + * change the behaviour from the base CPU port. + * + * @param resp list of ranges this port responds to + * @param snoop indicating if the port snoops or not + */ + virtual void getDeviceAddressRanges(AddrRangeList& resp, + bool& snoop) + { resp.clear(); snoop = true; } + }; + class TickEvent : public Event { private: @@ -566,6 +642,12 @@ class FullO3CPU : public BaseO3CPU TheISA::ISA isa[Impl::MaxThreads]; + /** Instruction port. Note that it has to appear after the fetch stage. */ + IcachePort icachePort; + + /** Data port. Note that it has to appear after the iew stages */ + DcachePort dcachePort; + public: /** Enum to give each stage a specific index, so when calling * activateStage() or deactivateStage(), they can specify which stage @@ -704,8 +786,11 @@ class FullO3CPU : public BaseO3CPU data, store_idx); } + /** Used by the fetch unit to get a hold of the instruction port. */ + Port* getIcachePort() { return &icachePort; } + /** Get the dcache port (used to find block size for translations). */ - Port *getDcachePort() { return this->iew.ldstQueue.getDcachePort(); } + Port* getDcachePort() { return &dcachePort; } Addr lockAddr; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index d09d7f680..f5d275593 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -85,48 +85,6 @@ class DefaultFetch typedef TheISA::MachInst MachInst; typedef TheISA::ExtMachInst ExtMachInst; - /** IcachePort class for DefaultFetch. Handles doing the - * communication with the cache/memory. - */ - class IcachePort : public Port - { - protected: - /** Pointer to fetch. */ - DefaultFetch *fetch; - - public: - /** Default constructor. */ - IcachePort(DefaultFetch *_fetch) - : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch) - { } - - bool snoopRangeSent; - - virtual void setPeer(Port *port); - - 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, - bool &snoop) - { resp.clear(); snoop = true; } - - /** 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(); - }; - class FetchTranslation : public BaseTLB::Translation { protected: @@ -248,9 +206,6 @@ class DefaultFetch /** Registers statistics. */ void regStats(); - /** Returns the icache port. */ - Port *getIcachePort() { return icachePort; } - /** Sets the main backwards communication time buffer pointer. */ void setTimeBuffer(TimeBuffer *time_buffer); @@ -266,6 +221,9 @@ class DefaultFetch /** Tells the fetch stage that the Icache is set. */ void setIcache(); + /** Handles retrying the fetch access. */ + void recvRetry(); + /** Processes cache completion event. */ void processCacheCompletion(PacketPtr pkt); @@ -389,9 +347,6 @@ class DefaultFetch StaticInstPtr curMacroop, TheISA::PCState thisPC, TheISA::PCState nextPC, bool trace); - /** Handles retrying the fetch access. */ - void recvRetry(); - /** Returns the appropriate thread to fetch, given the fetch policy. */ ThreadID getFetchingThread(FetchPriority &fetch_priority); @@ -440,9 +395,6 @@ class DefaultFetch /** Wire used to write any information heading to decode. */ typename TimeBuffer::wire toDecode; - /** Icache interface. */ - IcachePort *icachePort; - /** BPredUnit. */ BPredUnit branchPred; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index ccab47d2f..d145fb099 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -70,68 +70,6 @@ using namespace std; -template -void -DefaultFetch::IcachePort::setPeer(Port *port) -{ - Port::setPeer(port); - - fetch->setIcache(); -} - -template -Tick -DefaultFetch::IcachePort::recvAtomic(PacketPtr pkt) -{ - panic("DefaultFetch doesn't expect recvAtomic callback!"); - return curTick(); -} - -template -void -DefaultFetch::IcachePort::recvFunctional(PacketPtr pkt) -{ - DPRINTF(Fetch, "DefaultFetch doesn't update its state from a " - "functional call.\n"); -} - -template -void -DefaultFetch::IcachePort::recvStatusChange(Status status) -{ - if (status == RangeChange) { - if (!snoopRangeSent) { - snoopRangeSent = true; - sendStatusChange(Port::RangeChange); - } - return; - } - - panic("DefaultFetch doesn't expect recvStatusChange callback!"); -} - -template -bool -DefaultFetch::IcachePort::recvTiming(PacketPtr pkt) -{ - DPRINTF(Fetch, "Received timing\n"); - if (pkt->isResponse()) { - // We shouldn't ever get a block in ownership state - assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); - - fetch->processCacheCompletion(pkt); - } - //else Snooped a coherence request, just return - return true; -} - -template -void -DefaultFetch::IcachePort::recvRetry() -{ - fetch->recvRetry(); -} - template DefaultFetch::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), @@ -191,17 +129,6 @@ DefaultFetch::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) // Get the size of an instruction. instSize = sizeof(TheISA::MachInst); - - // Name is finally available, so create the port. - icachePort = new IcachePort(this); - - icachePort->snoopRangeSent = false; - -#if USE_CHECKER - if (cpu->checker) { - cpu->checker->setIcachePort(icachePort); - } -#endif } template @@ -404,8 +331,10 @@ template void DefaultFetch::setIcache() { + assert(cpu->getIcachePort()->isConnected()); + // Size of cache block. - cacheBlkSize = icachePort->peerBlockSize(); + cacheBlkSize = cpu->getIcachePort()->peerBlockSize(); // Create mask to get rid of offset bits. cacheBlkMask = (cacheBlkSize - 1); @@ -496,6 +425,10 @@ template void DefaultFetch::takeOverFrom() { + // the instruction port is now connected so we can get the block + // size + setIcache(); + // Reset all state for (ThreadID i = 0; i < Impl::MaxThreads; ++i) { stalls[i].decode = 0; @@ -686,7 +619,7 @@ DefaultFetch::finishTranslation(Fault fault, RequestPtr mem_req) fetchedCacheLines++; // Access the cache. - if (!icachePort->sendTiming(data_pkt)) { + if (!cpu->getIcachePort()->sendTiming(data_pkt)) { assert(retryPkt == NULL); assert(retryTid == InvalidThreadID); DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid); @@ -1405,7 +1338,7 @@ DefaultFetch::recvRetry() assert(retryTid != InvalidThreadID); assert(fetchStatus[retryTid] == IcacheWaitRetry); - if (icachePort->sendTiming(retryPkt)) { + if (cpu->getIcachePort()->sendTiming(retryPkt)) { fetchStatus[retryTid] = IcacheWaitResponse; retryPkt = NULL; retryTid = InvalidThreadID; diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 113d0756e..c58361cd6 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -139,9 +139,6 @@ class DefaultIEW /** Initializes stage; sends back the number of free IQ and LSQ entries. */ void initStage(); - /** Returns the dcache port. */ - Port *getDcachePort() { return ldstQueue.getDcachePort(); } - /** Sets main time buffer used for backwards communication. */ void setTimeBuffer(TimeBuffer *tb_ptr); diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index d01a6b0a4..731c67ae6 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -66,13 +78,6 @@ class LSQ { /** Registers statistics of each LSQ unit. */ void regStats(); - /** Returns dcache port. - * @todo: Dcache port needs to be moved up to this level for SMT - * to work. For now it just returns the port from one of the - * threads. - */ - Port *getDcachePort() { return &dcachePort; } - /** Sets the pointer to the list of active threads. */ void setActiveThreads(std::list *at_ptr); /** Switches out the LSQ. */ @@ -282,56 +287,25 @@ class LSQ { Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh, uint8_t *data, int store_idx); + /** + * Retry the previous send that failed. + */ + void recvRetry(); + + /** + * Handles writing back and completing the load or store that has + * returned from memory. + * + * @param pkt Response packet from the memory sub-system + */ + bool recvTiming(PacketPtr pkt); + /** The CPU pointer. */ O3CPU *cpu; /** The IEW stage pointer. */ IEW *iewStage; - /** DcachePort class for this LSQ. Handles doing the - * communication with the cache/memory. - */ - class DcachePort : public Port - { - protected: - /** Pointer to LSQ. */ - LSQ *lsq; - - public: - /** Default constructor. */ - DcachePort(LSQ *_lsq) - : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq) - { } - - 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, - bool &snoop) - { resp.clear(); snoop = true; } - - /** Timing version of receive. Handles writing back and - * completing the load or store that has returned from - * memory. */ - virtual bool recvTiming(PacketPtr pkt); - - /** Handles doing a retry of the previous send. */ - virtual void recvRetry(); - }; - - /** D-cache port. */ - DcachePort dcachePort; - protected: /** The LSQ policy for SMT mode. */ LSQPolicy lsqPolicy; diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 61dced14f..f1642be9c 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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) 2005-2006 The Regents of The University of Michigan * All rights reserved. * @@ -40,85 +52,14 @@ using namespace std; -template -Tick -LSQ::DcachePort::recvAtomic(PacketPtr pkt) -{ - panic("O3CPU model does not work with atomic mode!"); - return curTick(); -} - -template -void -LSQ::DcachePort::recvFunctional(PacketPtr pkt) -{ - DPRINTF(LSQ, "LSQ doesn't update things on a recvFunctional.\n"); -} - -template -void -LSQ::DcachePort::recvStatusChange(Status status) -{ - if (status == RangeChange) { - if (!snoopRangeSent) { - snoopRangeSent = true; - sendStatusChange(Port::RangeChange); - } - return; - } - panic("O3CPU doesn't expect recvStatusChange callback!"); -} - -template -bool -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->threadId()].completeDataAccess(pkt); - } else { - DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(), - pkt->cmdString()); - - // must be a snoop - if (pkt->isInvalidate()) { - DPRINTF(LSQ, "received invalidation for addr:%#x\n", pkt->getAddr()); - for (ThreadID tid = 0; tid < lsq->numThreads; tid++) { - lsq->thread[tid].checkSnoop(pkt); - } - } - // to provide stronger consistency model - } - return true; -} - -template -void -LSQ::DcachePort::recvRetry() -{ - if (lsq->retryTid == -1) - { - //Squashed, so drop it - return; - } - int curr_retry_tid = lsq->retryTid; - // Speculatively clear the retry Tid. This will get set again if - // the LSQUnit was unable to complete its access. - lsq->retryTid = -1; - lsq->thread[curr_retry_tid].recvRetry(); -} - template LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) - : cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this), + : cpu(cpu_ptr), iewStage(iew_ptr), LQEntries(params->LQEntries), SQEntries(params->SQEntries), numThreads(params->numThreads), retryTid(-1) { - dcachePort.snoopRangeSent = false; - //**********************************************/ //************ Handle SMT Parameters ***********/ //**********************************************/ @@ -170,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(&dcachePort); + thread[tid].setDcachePort(cpu_ptr->getDcachePort()); } } @@ -360,6 +301,48 @@ LSQ::violation() return false; } +template +void +LSQ::recvRetry() +{ + if (retryTid == InvalidThreadID) + { + //Squashed, so drop it + return; + } + int curr_retry_tid = retryTid; + // Speculatively clear the retry Tid. This will get set again if + // the LSQUnit was unable to complete its access. + retryTid = -1; + thread[curr_retry_tid].recvRetry(); +} + +template +bool +LSQ::recvTiming(PacketPtr pkt) +{ + if (pkt->isError()) + DPRINTF(LSQ, "Got error packet back for address: %#X\n", + pkt->getAddr()); + if (pkt->isResponse()) { + thread[pkt->req->threadId()].completeDataAccess(pkt); + } else { + DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(), + pkt->cmdString()); + + // must be a snoop + if (pkt->isInvalidate()) { + DPRINTF(LSQ, "received invalidation for addr:%#x\n", + pkt->getAddr()); + for (ThreadID tid = 0; tid < numThreads; tid++) { + thread[tid].checkSnoop(pkt); + } + } + // to provide stronger consistency model + } + return true; +} + template int LSQ::getCount() diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py index a4d807f86..93cd02ba7 100644 --- a/src/cpu/simple/AtomicSimpleCPU.py +++ b/src/cpu/simple/AtomicSimpleCPU.py @@ -34,8 +34,4 @@ 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") - icache_port = Port("Instruction Port") - dcache_port = Port("Data Port") physmem_port = Port("Physical Memory Port") - _cached_ports = BaseSimpleCPU._cached_ports + \ - ['icache_port', 'dcache_port'] diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py index 8d6888f72..61491b087 100644 --- a/src/cpu/simple/TimingSimpleCPU.py +++ b/src/cpu/simple/TimingSimpleCPU.py @@ -31,6 +31,3 @@ from BaseSimpleCPU import BaseSimpleCPU class TimingSimpleCPU(BaseSimpleCPU): type = 'TimingSimpleCPU' - icache_port = Port("Instruction Port") - dcache_port = Port("Data Port") - _cached_ports = BaseSimpleCPU._cached_ports + ['icache_port', 'dcache_port'] diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index b40109ec1..84f42da08 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -107,47 +107,6 @@ AtomicSimpleCPU::init() data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too } -bool -AtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt) -{ - panic("AtomicSimpleCPU doesn't expect recvTiming callback!"); - return true; -} - -Tick -AtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) -{ - //Snooping a coherence request, just return - return 0; -} - -void -AtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) -{ - //No internal storage to update, just return - return; -} - -void -AtomicSimpleCPU::CpuPort::recvStatusChange(Status status) -{ - if (status == RangeChange) { - if (!snoopRangeSent) { - snoopRangeSent = true; - sendStatusChange(Port::RangeChange); - } - return; - } - - panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); -} - -void -AtomicSimpleCPU::CpuPort::recvRetry() -{ - panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); -} - AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false), simulate_data_stalls(p->simulate_data_stalls), @@ -156,10 +115,6 @@ AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) physmemPort(name() + "-iport", this), hasPhysMemPort(false) { _status = Idle; - - icachePort.snoopRangeSent = false; - dcachePort.snoopRangeSent = false; - } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index c3d78a381..77a9d6b0d 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -64,38 +64,31 @@ class AtomicSimpleCPU : public BaseSimpleCPU // main simulation loop (one cycle) void tick(); - class CpuPort : public Port + /** + * An AtomicCPUPort overrides the default behaviour of the + * recvAtomic and ignores the packet instead of panicking. + */ + class AtomicCPUPort : public CpuPort { + public: - CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu) - : Port(_name, _cpu), cpu(_cpu) + AtomicCPUPort(const std::string &_name, BaseCPU* _cpu) + : CpuPort(_name, _cpu) { } - bool snoopRangeSent; - protected: - AtomicSimpleCPU *cpu; - - virtual bool recvTiming(PacketPtr pkt); - - virtual Tick recvAtomic(PacketPtr pkt); - - virtual void recvFunctional(PacketPtr pkt); - - virtual void recvStatusChange(Status status); - - virtual void recvRetry(); - - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) - { resp.clear(); snoop = true; } + virtual Tick recvAtomic(PacketPtr pkt) + { + // Snooping a coherence request, just return + return 0; + } }; - CpuPort icachePort; - CpuPort dcachePort; + AtomicCPUPort icachePort; + AtomicCPUPort dcachePort; CpuPort physmemPort; bool hasPhysMemPort; diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 4375d2549..70583cae9 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -87,51 +87,19 @@ TimingSimpleCPU::init() #endif } -Tick -TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) -{ - panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); - return curTick(); -} - void -TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) -{ - //No internal storage to update, jusst return - return; -} - -void -TimingSimpleCPU::CpuPort::recvStatusChange(Status status) -{ - if (status == RangeChange) { - if (!snoopRangeSent) { - snoopRangeSent = true; - sendStatusChange(Port::RangeChange); - } - return; - } - - panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); -} - - -void -TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) +TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t) { pkt = _pkt; cpu->schedule(this, t); } TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) - : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), - dcachePort(this, p->clock), fetchEvent(this) + : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this), + dcachePort(this), fetchEvent(this) { _status = Idle; - icachePort.snoopRangeSent = false; - dcachePort.snoopRangeSent = false; - ifetch_pkt = dcache_pkt = NULL; drainEvent = NULL; previousTick = 0; diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 6e95ddd9d..dce3c58ff 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -137,31 +137,23 @@ class TimingSimpleCPU : public BaseSimpleCPU // This function always implicitly uses dcache_pkt. bool handleWritePacket(); - class CpuPort : public Port + /** + * A TimingCPUPort overrides the default behaviour of the + * recvTiming and recvRetry and implements events for the + * scheduling of handling of incoming packets in the following + * cycle. + */ + class TimingCPUPort : public CpuPort { - protected: - TimingSimpleCPU *cpu; - Tick lat; - public: - CpuPort(const std::string &_name, TimingSimpleCPU *_cpu, Tick _lat) - : Port(_name, _cpu), cpu(_cpu), lat(_lat), retryEvent(this) + TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu) + : CpuPort(_name, _cpu), cpu(_cpu), retryEvent(this) { } - bool snoopRangeSent; - protected: - virtual Tick recvAtomic(PacketPtr pkt); - - virtual void recvFunctional(PacketPtr pkt); - - virtual void recvStatusChange(Status status); - - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) - { resp.clear(); snoop = false; } + TimingSimpleCPU* cpu; struct TickEvent : public Event { @@ -169,7 +161,7 @@ class TimingSimpleCPU : public BaseSimpleCPU TimingSimpleCPU *cpu; CpuPort *port; - TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {} + TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {} const char *description() const { return "Timing CPU tick"; } void schedule(PacketPtr _pkt, Tick t); }; @@ -177,12 +169,13 @@ class TimingSimpleCPU : public BaseSimpleCPU EventWrapper retryEvent; }; - class IcachePort : public CpuPort + class IcachePort : public TimingCPUPort { public: - IcachePort(TimingSimpleCPU *_cpu, Tick _lat) - : CpuPort(_cpu->name() + "-iport", _cpu, _lat), tickEvent(_cpu) + IcachePort(TimingSimpleCPU *_cpu) + : TimingCPUPort(_cpu->name() + "-iport", _cpu), + tickEvent(_cpu) { } protected: @@ -204,12 +197,12 @@ class TimingSimpleCPU : public BaseSimpleCPU }; - class DcachePort : public CpuPort + class DcachePort : public TimingCPUPort { public: - DcachePort(TimingSimpleCPU *_cpu, Tick _lat) - : CpuPort(_cpu->name() + "-dport", _cpu, _lat), tickEvent(_cpu) + DcachePort(TimingSimpleCPU *_cpu) + : TimingCPUPort(_cpu->name() + "-dport", _cpu), tickEvent(_cpu) { } protected: