| /* | |
| * Copyright (c) 2010-2011 The Regents of The University of Michigan | |
| * 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_SKED_HH__ | |
| #define __CPU_INORDER_RESOURCE_SKED_HH__ | |
| #include <cstdlib> | |
| #include <list> | |
| #include <vector> | |
| /** ScheduleEntry class represents a single function that an instruction | |
| wants to do at any pipeline stage. For example, if an instruction | |
| needs to be decoded and do a branch prediction all in one stage | |
| then each of those tasks would need it's own ScheduleEntry. | |
| Each schedule entry corresponds to some resource that the instruction | |
| wants to interact with. | |
| The file pipeline_traits.cc shows how a typical instruction schedule is | |
| made up of these schedule entries. | |
| */ | |
| class ScheduleEntry { | |
| public: | |
| ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, | |
| int _idx = 0) : | |
| stageNum(stage_num), resNum(res_num), cmd(_cmd), | |
| idx(_idx), priority(_priority) | |
| { } | |
| /** Stage number to perform this service. */ | |
| int stageNum; | |
| /** Resource ID to access */ | |
| int resNum; | |
| /** See specific resource for meaning */ | |
| unsigned cmd; | |
| /** See specific resource for meaning */ | |
| unsigned idx; | |
| /** Some Resources May Need Priority */ | |
| int priority; | |
| }; | |
| /** The ResourceSked maintains the complete schedule | |
| for an instruction. That schedule includes what | |
| resources an instruction wants to acquire at each | |
| pipeline stage and is represented by a collection | |
| of ScheduleEntry objects (described above) that | |
| must be executed in-order. | |
| In every pipeline stage, the InOrder model will | |
| process all entries on the resource schedule for | |
| that stage and then send the instruction to the next | |
| stage if and only if the instruction successfully | |
| completed each ScheduleEntry. | |
| */ | |
| class ResourceSked { | |
| public: | |
| typedef std::list<ScheduleEntry*>::iterator SkedIt; | |
| typedef std::vector<std::list<ScheduleEntry*> > StageList; | |
| ResourceSked(); | |
| /** Initializee the current entry pointer to | |
| pipeline stage 0 and the 1st schedule entry | |
| */ | |
| void init(); | |
| /** Goes through the remaining stages on the schedule | |
| and sums all the remaining entries left to be | |
| processed | |
| */ | |
| int size(); | |
| /** Is the schedule empty? */ | |
| bool empty(); | |
| /** Beginning Entry of this schedule */ | |
| SkedIt begin(); | |
| /** Ending Entry of this schedule */ | |
| SkedIt end(); | |
| /** Ending Entry of a specified stage */ | |
| SkedIt end(int stage_num); | |
| /** Find a schedule entry based on stage and command */ | |
| SkedIt find(int stage_num, int cmd); | |
| /** What is the next task for this instruction schedule? */ | |
| ScheduleEntry* top(); | |
| /** Top() Task is completed, remove it from schedule */ | |
| void pop(); | |
| /** Add To Schedule based on stage num and priority of | |
| Schedule Entry | |
| */ | |
| void push(ScheduleEntry* sked_entry); | |
| /** Add Schedule Entry to be in front of another Entry */ | |
| void pushBefore(ScheduleEntry* sked_entry, int sked_cmd, int sked_cmd_idx); | |
| /** Print what's left on the instruction schedule */ | |
| void print(); | |
| StageList *getStages() | |
| { | |
| return &stages; | |
| } | |
| private: | |
| /** Current Schedule Entry Pointer */ | |
| SkedIt curSkedEntry; | |
| /** The Stage-by-Stage Resource Schedule: | |
| Resized to Number of Stages in the constructor | |
| */ | |
| StageList stages; | |
| /** Find a place to insert the instruction using the | |
| schedule entries priority | |
| */ | |
| SkedIt findIterByPriority(ScheduleEntry *sked_entry, int stage_num); | |
| /** Find a place to insert the instruction using a particular command | |
| to look for. | |
| */ | |
| SkedIt findIterByCommand(ScheduleEntry *sked_entry, int stage_num, | |
| int sked_cmd, int sked_cmd_idx = -1); | |
| }; | |
| /** Wrapper class around the SkedIt iterator in the Resource Sked so that | |
| we can use ++ operator to automatically go to the next available | |
| resource schedule entry but otherwise maintain same functionality | |
| as a normal iterator. | |
| */ | |
| class RSkedIt | |
| { | |
| public: | |
| RSkedIt() | |
| : curStage(0), numStages(0) | |
| { } | |
| /** init() must be called before the use of any other member | |
| in the RSkedIt class. | |
| */ | |
| void init(ResourceSked* rsked) | |
| { | |
| stages = rsked->getStages(); | |
| numStages = stages->size(); | |
| } | |
| /* Update the encapsulated "myIt" iterator, but only | |
| update curStage/curStage_end if the iterator is valid. | |
| The iterator could be invalid in the case where | |
| someone is saving the end of a list (i.e. std::list->end()) | |
| */ | |
| RSkedIt operator=(ResourceSked::SkedIt const &rhs) | |
| { | |
| myIt = rhs; | |
| if (myIt != (*stages)[numStages-1].end()) { | |
| curStage = (*myIt)->stageNum; | |
| curStage_end = (*stages)[curStage].end(); | |
| } | |
| return *this; | |
| } | |
| /** Increment to the next entry in current stage. | |
| If no more entries then find the next stage that has | |
| resource schedule to complete. | |
| If no more stages, then return the end() iterator from | |
| the last stage to indicate we are done. | |
| */ | |
| RSkedIt &operator++(int unused) | |
| { | |
| if (++myIt == curStage_end) { | |
| curStage++; | |
| while (curStage < numStages) { | |
| if ((*stages)[curStage].empty()) { | |
| curStage++; | |
| } else { | |
| myIt = (*stages)[curStage].begin(); | |
| curStage_end = (*stages)[curStage].end(); | |
| return *this; | |
| } | |
| } | |
| myIt = (*stages)[numStages - 1].end(); | |
| } | |
| return *this; | |
| } | |
| /** The "pointer" operator can be used on a RSkedIt and it | |
| will use the encapsulated iterator | |
| */ | |
| ScheduleEntry* operator->() | |
| { | |
| return *myIt; | |
| } | |
| /** Dereferencing a RSKedIt will access the encapsulated | |
| iterator | |
| */ | |
| ScheduleEntry* operator*() | |
| { | |
| return *myIt; | |
| } | |
| /** Equality for RSkedIt only compares the "myIt" iterators, | |
| as the other members are just ancillary | |
| */ | |
| bool operator==(RSkedIt const &rhs) | |
| { | |
| return this->myIt == rhs.myIt; | |
| } | |
| /** Inequality for RSkedIt only compares the "myIt" iterators, | |
| as the other members are just ancillary | |
| */ | |
| bool operator!=(RSkedIt const &rhs) | |
| { | |
| return this->myIt != rhs.myIt; | |
| } | |
| /* The == and != operator overloads should be sufficient | |
| here if need otherwise direct access to the schedule | |
| iterator, then this can be used */ | |
| ResourceSked::SkedIt getIt() | |
| { | |
| return myIt; | |
| } | |
| private: | |
| /** Schedule Iterator that this class is encapsulating */ | |
| ResourceSked::SkedIt myIt; | |
| /** Ptr to resource schedule that the 'myIt' iterator | |
| belongs to | |
| */ | |
| ResourceSked::StageList *stages; | |
| /** The last iterator in the current stage. */ | |
| ResourceSked::SkedIt curStage_end; | |
| /** Current Stage that "myIt" refers to. */ | |
| int curStage; | |
| /** Number of stages in the "*stages" object. */ | |
| int numStages; | |
| }; | |
| #endif //__CPU_INORDER_RESOURCE_SKED_HH__ |