/* * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Korey Sewell * */ #ifndef __CPU_INORDER_RESOURCE_HH__ #define __CPU_INORDER_RESOURCE_HH__ #include #include #include #include "cpu/inst_seq.hh" #include "cpu/inorder/inorder_dyn_inst.hh" #include "cpu/inorder/pipeline_traits.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" class Event; class InOrderCPU; class ResourceEvent; class ResourceRequest; typedef ResourceRequest ResReq; typedef ResourceRequest* ResReqPtr; class Resource { public: typedef ThePipeline::DynInstPtr DynInstPtr; friend class ResourceEvent; friend class ResourceRequest; public: Resource(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu); virtual ~Resource() {} /** Return name of this resource */ virtual std::string name(); /** Define this function if resource, has a port to connect to an outside * simulation object. */ virtual Port* getPort(const std::string &if_name, int idx) { return NULL; } /** Return ID for this resource */ int getId() { return id; } /** Any extra initiliazation stuff can be set up using this function that * should get called before the simulation starts (tick 0) */ virtual void init(); virtual void initSlots(); /** Register Stats for this resource */ virtual void regStats(); /** Resources that care about thread activation override this. */ virtual void activateThread(unsigned tid) { } /** Deactivate Thread. Default action is to squash all instructions * from deactivated thread. */ virtual void deactivateThread(unsigned tid); /** Resources that care when an instruction has been graduated * can override this */ virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { } /** Request usage of this resource. Returns a ResourceRequest object * with all the necessary resource information */ virtual ResourceRequest* request(DynInstPtr inst); /** Get the next available slot in this resource. Instruction is passed * so that resources can check the instruction before allocating a slot * if necessary. */ virtual int getSlot(DynInstPtr inst); /** Find the slot that this instruction is using in a resource */ virtual int findSlot(DynInstPtr inst); /** Free a resource slot */ virtual void freeSlot(int slot_idx); /** Request usage of a resource for this instruction. If this instruction already * has made this request to this resource, and that request is uncompleted * this function will just return that request */ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, unsigned cmd); /** Schedule Execution of This Resource For A Given Slot*/ virtual void scheduleExecution(int slot_idx); /** Execute the function of this resource. The Default is action * is to do nothing. More specific models will derive from this * class and define their own execute function. */ virtual void execute(int slot_idx); /** Fetch on behalf of an instruction. Will check to see * if instruction is actually in resource before * trying to fetch. Needs to be defined for derived units. */ virtual Fault doFetchAccess(DynInstPtr inst) { panic("doFetchAccess undefined for %s", name()); return NoFault; } /** Read/Write on behalf of an instruction. Will check to see * if instruction is actually in resource before * trying to do access.Needs to be defined for derived units. */ virtual Fault doDataAccess(DynInstPtr inst, uint64_t *res=NULL) { panic("doDataAccess undefined for %s", name()); return NoFault; } virtual void prefetch(DynInstPtr inst) { panic("prefetch undefined for %s", name()); } virtual void writeHint(DynInstPtr inst) { panic("doDataAccess undefined for %s", name()); } /** Squash All Requests After This Seq Num */ virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid); /** The number of instructions available that this resource can * can still process */ int slotsAvail(); /** The number of instructions using this resource */ int slotsInUse(); /** Schedule resource event, regardless of its current state. */ void scheduleEvent(int slot_idx, int delay); /** Find instruction in list, Schedule resource event, regardless of its current state. */ bool scheduleEvent(DynInstPtr inst, int delay); /** Unschedule resource event, regardless of its current state. */ void unscheduleEvent(int slot_idx); /** Unschedule resource event, regardless of its current state. */ bool unscheduleEvent(DynInstPtr inst); /** Return the number of cycles in 'Tick' format */ Tick ticks(int numCycles); /** Find the request that corresponds to this instruction */ virtual ResReqPtr findRequest(DynInstPtr inst); /** */ virtual void rejectRequest(DynInstPtr inst); /** Request a Resource again. Some resources have to special process this * in subsequent accesses. */ virtual void requestAgain(DynInstPtr inst, bool &try_request); /** Return Latency of Resource */ /* Can be overridden for complex cases */ virtual int getLatency(int slot_num) { return latency; } protected: /** The name of this resource */ std::string resName; /** ID of the resource. The Resource Pool uses this # to identify this * resource. */ int id; /** The number of instructions the resource can simultaneously * process. */ int width; /** Constant latency for this resource. * Note: Dynamic latency resources set this to 0 and * manage the latency themselves */ const int latency; public: /** Mapping of slot-numbers to the resource-request pointers */ std::map reqMap; /** A list of all the available execution slots for this resource. * This correlates with the actual resource event idx. */ std::vector availSlots; /** The CPU(s) that this resource interacts with */ InOrderCPU *cpu; protected: /** The resource event used for scheduling resource slots on the * event queue */ ResourceEvent *resourceEvent; /** Default denied resource request pointer*/ ResReqPtr deniedReq; public: ///////////////////////////////////////////////////////////////// // // DEFAULT RESOURCE STATISTICS // ///////////////////////////////////////////////////////////////// /** Number of Instruction Requests the Resource Processes */ Stats::Scalar instReqsProcessed; }; class ResourceEvent : public Event { public: /** Pointer to the CPU. */ Resource *resource; /// Resource events that come before other associated CPU events /// (for InOrderCPU model). /// check src/sim/eventq.hh for more event priorities. enum InOrderPriority { Resource_Event_Pri = 45, }; /** The Resource Slot that this event is servicing */ int slotIdx; /** Constructs a resource event. */ ResourceEvent(); ResourceEvent(Resource *res, int slot_idx); virtual ~ResourceEvent() { } /** Initialize data for this resource event. */ virtual void init(Resource *res, int slot_idx); /** Processes a resource event. */ virtual void process(); /** Returns the description of the resource event. */ const char *description(); /** Set slot idx for event */ void setSlot(int slot) { slotIdx = slot; } /** Schedule resource event, regardless of its current state. */ void scheduleEvent(int delay) { if (squashed()) mainEventQueue.reschedule(this, curTick + resource->ticks(delay)); else if (!scheduled()) mainEventQueue.schedule(this, curTick + resource->ticks(delay)); } /** Unschedule resource event, regardless of its current state. */ void unscheduleEvent() { if (scheduled()) squash(); } }; class ResourceRequest { public: typedef ThePipeline::DynInstPtr DynInstPtr; static int resReqID; static int resReqCount; public: ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num, int res_idx, int slot_num, unsigned _cmd) : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num), resIdx(res_idx), slotNum(slot_num), completed(false), squashed(false), processing(false), waiting(false) { reqID = resReqID++; resReqCount++; DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount); if (resReqCount > 100) { fatal("Too many undeleted resource requests. Memory leak?\n"); } } virtual ~ResourceRequest() { resReqCount--; DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount); } int reqID; /** Acknowledge that this is a request is done and remove * from resource. */ void done(bool completed = true); ///////////////////////////////////////////// // // GET RESOURCE REQUEST IDENTIFICATION / INFO // ///////////////////////////////////////////// /** Get Resource Index */ int getResIdx() { return resIdx; } /** Get Slot Number */ int getSlot() { return slotNum; } /** Get Stage Number */ int getStageNum() { return stageNum; } /** Set/Get Thread Ids */ void setTid(unsigned _tid) { tid = _tid; } int getTid() { return tid; } /** Instruction this request is for */ DynInstPtr getInst() { return inst; } /** Data from this request. Overridden by Resource-Specific Request * Objects */ virtual PacketDataPtr getData() { return NULL; } /** Pointer to Resource that is being used */ Resource *res; /** Instruction being used */ DynInstPtr inst; /** Fault Associated With This Resource Request */ Fault fault; /** Command For This Resource */ unsigned cmd; //////////////////////////////////////// // // GET RESOURCE REQUEST STATUS FROM VARIABLES // //////////////////////////////////////// /** Get/Set Completed variables */ bool isCompleted() { return completed; } void setCompleted(bool cond = true) { completed = cond; } /** Get/Set Squashed variables */ bool isSquashed() { return squashed; } void setSquashed() { squashed = true; } /** Get/Set IsProcessing variables */ bool isProcessing() { return processing; } void setProcessing() { processing = true; } /** Get/Set IsWaiting variables */ bool isWaiting() { return waiting; } void setWaiting() { waiting = true; } protected: /** Resource Identification */ int tid; int stageNum; int resIdx; int slotNum; /** Resource Status */ bool completed; bool squashed; bool processing; bool waiting; }; #endif //__CPU_INORDER_RESOURCE_HH__