| /* |
| * Copyright (c) 2007 MIPS Technologies, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Korey Sewell |
| * |
| */ |
| |
| #ifndef __CPU_INORDER_CACHE_UNIT_HH__ |
| #define __CPU_INORDER_CACHE_UNIT_HH__ |
| |
| #include <list> |
| #include <string> |
| #include <vector> |
| |
| #include "arch/predecoder.hh" |
| #include "arch/tlb.hh" |
| #include "config/the_isa.hh" |
| #include "cpu/inorder/inorder_dyn_inst.hh" |
| #include "cpu/inorder/pipeline_traits.hh" |
| #include "cpu/inorder/resource.hh" |
| #include "mem/packet.hh" |
| #include "mem/packet_access.hh" |
| #include "mem/port.hh" |
| #include "params/InOrderCPU.hh" |
| #include "sim/sim_object.hh" |
| |
| class CacheRequest; |
| typedef CacheRequest* CacheReqPtr; |
| |
| class CacheReqPacket; |
| typedef CacheReqPacket* CacheReqPktPtr; |
| |
| class CacheUnit : public Resource |
| { |
| public: |
| typedef ThePipeline::DynInstPtr DynInstPtr; |
| |
| public: |
| CacheUnit(std::string res_name, int res_id, int res_width, |
| int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); |
| |
| enum Command { |
| InitiateReadData, |
| CompleteReadData, |
| InitiateWriteData, |
| CompleteWriteData, |
| InitSecondSplitRead, |
| InitSecondSplitWrite, |
| CompleteSecondSplitRead, |
| CompleteSecondSplitWrite |
| }; |
| |
| public: |
| /** CachePort class for the Cache Unit. Handles doing the |
| * communication with the cache/memory. |
| */ |
| class CachePort : public Port |
| { |
| protected: |
| /** Pointer to cache port unit */ |
| CacheUnit *cachePortUnit; |
| |
| public: |
| /** Default constructor. */ |
| CachePort(CacheUnit *_cachePortUnit) |
| : Port(_cachePortUnit->name() + "-cache-port", |
| (MemObject*)_cachePortUnit->cpu), |
| cachePortUnit(_cachePortUnit) |
| { } |
| |
| bool snoopRangeSent; |
| |
| protected: |
| /** Atomic version of receive. Panics. */ |
| Tick recvAtomic(PacketPtr pkt); |
| |
| /** Functional version of receive. Panics. */ |
| void recvFunctional(PacketPtr pkt); |
| |
| /** Receives status change. Other than range changing, panics. */ |
| void recvStatusChange(Status status); |
| |
| /** Returns the address ranges of this device. */ |
| void getDeviceAddressRanges(AddrRangeList &resp, |
| AddrRangeList &snoop) |
| { resp.clear(); snoop.clear(); } |
| |
| /** Timing version of receive. Handles setting fetch to the |
| * proper status to start fetching. */ |
| bool recvTiming(PacketPtr pkt); |
| |
| /** Handles doing a retry of a failed fetch. */ |
| void recvRetry(); |
| }; |
| |
| void init(); |
| |
| ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, |
| int res_idx, int slot_num, |
| unsigned cmd); |
| |
| ResReqPtr findRequest(DynInstPtr inst); |
| ResReqPtr findRequest(DynInstPtr inst, int idx); |
| |
| void requestAgain(DynInstPtr inst, bool &try_request); |
| |
| virtual int getSlot(DynInstPtr inst); |
| |
| /** Executes one of the commands from the "Command" enum */ |
| virtual void execute(int slot_num); |
| |
| virtual void squash(DynInstPtr inst, int stage_num, |
| InstSeqNum squash_seq_num, ThreadID tid); |
| |
| void squashDueToMemStall(DynInstPtr inst, int stage_num, |
| InstSeqNum squash_seq_num, ThreadID tid); |
| |
| virtual void squashCacheRequest(CacheReqPtr req_ptr); |
| |
| /** After memory request is completedd in the cache, then do final |
| processing to complete the request in the CPU. |
| */ |
| virtual void processCacheCompletion(PacketPtr pkt); |
| |
| /** Create request that will interface w/TLB and Memory objects */ |
| virtual void setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req, |
| int acc_size, int flags); |
| |
| 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); |
| |
| Fault write(DynInstPtr inst, uint8_t *data, unsigned size, |
| Addr addr, unsigned flags, uint64_t *res); |
| |
| void doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size, |
| int flags, TheISA::TLB::Mode tlb_mode); |
| |
| /** Read/Write on behalf of an instruction. |
| * curResSlot needs to be a valid value in instruction. |
| */ |
| void doCacheAccess(DynInstPtr inst, uint64_t *write_result=NULL, |
| CacheReqPtr split_req=NULL); |
| |
| uint64_t getMemData(Packet *packet); |
| |
| void setAddrDependency(DynInstPtr inst); |
| virtual void removeAddrDependency(DynInstPtr inst); |
| |
| protected: |
| /** Cache interface. */ |
| CachePort *cachePort; |
| |
| bool cachePortBlocked; |
| |
| std::vector<Addr> addrList[ThePipeline::MaxThreads]; |
| |
| std::map<Addr, InstSeqNum> addrMap[ThePipeline::MaxThreads]; |
| |
| public: |
| int cacheBlkSize; |
| |
| int cacheBlkMask; |
| |
| /** Align a PC to the start of the Cache block. */ |
| Addr cacheBlockAlign(Addr addr) |
| { |
| return (addr & ~(cacheBlkMask)); |
| } |
| |
| bool tlbBlocked[ThePipeline::MaxThreads]; |
| |
| TheISA::TLB* tlb(); |
| |
| TheISA::TLB *_tlb; |
| }; |
| |
| class CacheUnitEvent : public ResourceEvent { |
| public: |
| const std::string name() const |
| { |
| return "CacheUnitEvent"; |
| } |
| |
| |
| /** Constructs a resource event. */ |
| CacheUnitEvent(); |
| virtual ~CacheUnitEvent() {} |
| |
| /** Processes a resource event. */ |
| void process(); |
| }; |
| |
| //@todo: Move into CacheUnit Class for private access to "valid" field |
| class CacheRequest : public ResourceRequest |
| { |
| public: |
| CacheRequest(CacheUnit *cres) |
| : ResourceRequest(cres), memReq(NULL), reqData(NULL), |
| dataPkt(NULL), memAccComplete(false), |
| memAccPending(false), tlbStall(false), splitAccess(false), |
| splitAccessNum(-1), split2ndAccess(false), |
| fetchBufferFill(false) |
| { } |
| |
| virtual ~CacheRequest() |
| { |
| if (reqData && !splitAccess) |
| delete [] reqData; |
| } |
| |
| void setRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, |
| unsigned _cmd, MemCmd::Command pkt_cmd, int idx) |
| { |
| pktCmd = pkt_cmd; |
| instIdx = idx; |
| |
| ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num, _cmd); |
| } |
| |
| void clearRequest() |
| { |
| if (reqData && !splitAccess) |
| delete [] reqData; |
| |
| memReq = NULL; |
| reqData = NULL; |
| dataPkt = NULL; |
| memAccComplete = false; |
| memAccPending = false; |
| tlbStall = false; |
| splitAccess = false; |
| splitAccessNum = -1; |
| split2ndAccess = false; |
| instIdx = 0; |
| fetchBufferFill = false; |
| |
| ResourceRequest::clearRequest(); |
| } |
| |
| virtual PacketDataPtr getData() |
| { return reqData; } |
| |
| void |
| setMemAccCompleted(bool completed = true) |
| { |
| memAccComplete = completed; |
| } |
| |
| bool is2ndSplit() |
| { |
| return split2ndAccess; |
| } |
| |
| bool isMemAccComplete() { return memAccComplete; } |
| |
| void setMemAccPending(bool pending = true) { memAccPending = pending; } |
| bool isMemAccPending() { return memAccPending; } |
| |
| //Make this data private/protected! |
| MemCmd::Command pktCmd; |
| RequestPtr memReq; |
| PacketDataPtr reqData; |
| CacheReqPacket *dataPkt; |
| |
| bool memAccComplete; |
| bool memAccPending; |
| bool tlbStall; |
| |
| bool splitAccess; |
| int splitAccessNum; |
| bool split2ndAccess; |
| int instIdx; |
| |
| /** Should we expect block from cache access or fetch buffer? */ |
| bool fetchBufferFill; |
| }; |
| |
| class CacheReqPacket : public Packet |
| { |
| public: |
| CacheReqPacket(CacheRequest *_req, |
| Command _cmd, short _dest, int _idx = 0) |
| : Packet(_req->memReq, _cmd, _dest), cacheReq(_req), instIdx(_idx) |
| { |
| |
| } |
| |
| CacheRequest *cacheReq; |
| int instIdx; |
| |
| }; |
| |
| #endif //__CPU_CACHE_UNIT_HH__ |