|  | /* | 
|  | * 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) 2006 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: Kevin Lim | 
|  | */ | 
|  |  | 
|  | #ifndef __CPU_O3_DEP_GRAPH_HH__ | 
|  | #define __CPU_O3_DEP_GRAPH_HH__ | 
|  |  | 
|  | #include "cpu/o3/comm.hh" | 
|  |  | 
|  | /** Node in a linked list. */ | 
|  | template <class DynInstPtr> | 
|  | class DependencyEntry | 
|  | { | 
|  | public: | 
|  | DependencyEntry() | 
|  | : inst(NULL), next(NULL) | 
|  | { } | 
|  |  | 
|  | DynInstPtr inst; | 
|  | //Might want to include data about what arch. register the | 
|  | //dependence is waiting on. | 
|  | DependencyEntry<DynInstPtr> *next; | 
|  | }; | 
|  |  | 
|  | /** Array of linked list that maintains the dependencies between | 
|  | * producing instructions and consuming instructions.  Each linked | 
|  | * list represents a single physical register, having the future | 
|  | * producer of the register's value, and all consumers waiting on that | 
|  | * value on the list.  The head node of each linked list represents | 
|  | * the producing instruction of that register.  Instructions are put | 
|  | * on the list upon reaching the IQ, and are removed from the list | 
|  | * either when the producer completes, or the instruction is squashed. | 
|  | */ | 
|  | template <class DynInstPtr> | 
|  | class DependencyGraph | 
|  | { | 
|  | public: | 
|  | typedef DependencyEntry<DynInstPtr> DepEntry; | 
|  |  | 
|  | /** Default construction.  Must call resize() prior to use. */ | 
|  | DependencyGraph() | 
|  | : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0) | 
|  | { } | 
|  |  | 
|  | ~DependencyGraph(); | 
|  |  | 
|  | /** Resize the dependency graph to have num_entries registers. */ | 
|  | void resize(int num_entries); | 
|  |  | 
|  | /** Clears all of the linked lists. */ | 
|  | void reset(); | 
|  |  | 
|  | /** Inserts an instruction to be dependent on the given index. */ | 
|  | void insert(PhysRegIndex idx, DynInstPtr &new_inst); | 
|  |  | 
|  | /** Sets the producing instruction of a given register. */ | 
|  | void setInst(PhysRegIndex idx, DynInstPtr &new_inst) | 
|  | { dependGraph[idx].inst = new_inst; } | 
|  |  | 
|  | /** Clears the producing instruction. */ | 
|  | void clearInst(PhysRegIndex idx) | 
|  | { dependGraph[idx].inst = NULL; } | 
|  |  | 
|  | /** Removes an instruction from a single linked list. */ | 
|  | void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove); | 
|  |  | 
|  | /** Removes and returns the newest dependent of a specific register. */ | 
|  | DynInstPtr pop(PhysRegIndex idx); | 
|  |  | 
|  | /** Checks if the entire dependency graph is empty. */ | 
|  | bool empty() const; | 
|  |  | 
|  | /** Checks if there are any dependents on a specific register. */ | 
|  | bool empty(PhysRegIndex idx) const { return !dependGraph[idx].next; } | 
|  |  | 
|  | /** Debugging function to dump out the dependency graph. | 
|  | */ | 
|  | void dump(); | 
|  |  | 
|  | private: | 
|  | /** Array of linked lists.  Each linked list is a list of all the | 
|  | *  instructions that depend upon a given register.  The actual | 
|  | *  register's index is used to index into the graph; ie all | 
|  | *  instructions in flight that are dependent upon r34 will be | 
|  | *  in the linked list of dependGraph[34]. | 
|  | */ | 
|  | DepEntry *dependGraph; | 
|  |  | 
|  | /** Number of linked lists; identical to the number of registers. */ | 
|  | int numEntries; | 
|  |  | 
|  | // Debug variable, remove when done testing. | 
|  | unsigned memAllocCounter; | 
|  |  | 
|  | public: | 
|  | // Debug variable, remove when done testing. | 
|  | uint64_t nodesTraversed; | 
|  | // Debug variable, remove when done testing. | 
|  | uint64_t nodesRemoved; | 
|  | }; | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | DependencyGraph<DynInstPtr>::~DependencyGraph() | 
|  | { | 
|  | delete [] dependGraph; | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | void | 
|  | DependencyGraph<DynInstPtr>::resize(int num_entries) | 
|  | { | 
|  | numEntries = num_entries; | 
|  | dependGraph = new DepEntry[numEntries]; | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | void | 
|  | DependencyGraph<DynInstPtr>::reset() | 
|  | { | 
|  | // Clear the dependency graph | 
|  | DepEntry *curr; | 
|  | DepEntry *prev; | 
|  |  | 
|  | for (int i = 0; i < numEntries; ++i) { | 
|  | curr = dependGraph[i].next; | 
|  |  | 
|  | while (curr) { | 
|  | memAllocCounter--; | 
|  |  | 
|  | prev = curr; | 
|  | curr = prev->next; | 
|  | prev->inst = NULL; | 
|  |  | 
|  | delete prev; | 
|  | } | 
|  |  | 
|  | if (dependGraph[i].inst) { | 
|  | dependGraph[i].inst = NULL; | 
|  | } | 
|  |  | 
|  | dependGraph[i].next = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | void | 
|  | DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst) | 
|  | { | 
|  | //Add this new, dependent instruction at the head of the dependency | 
|  | //chain. | 
|  |  | 
|  | // First create the entry that will be added to the head of the | 
|  | // dependency chain. | 
|  | DepEntry *new_entry = new DepEntry; | 
|  | new_entry->next = dependGraph[idx].next; | 
|  | new_entry->inst = new_inst; | 
|  |  | 
|  | // Then actually add it to the chain. | 
|  | dependGraph[idx].next = new_entry; | 
|  |  | 
|  | ++memAllocCounter; | 
|  | } | 
|  |  | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | void | 
|  | DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx, | 
|  | DynInstPtr &inst_to_remove) | 
|  | { | 
|  | DepEntry *prev = &dependGraph[idx]; | 
|  | DepEntry *curr = dependGraph[idx].next; | 
|  |  | 
|  | // Make sure curr isn't NULL.  Because this instruction is being | 
|  | // removed from a dependency list, it must have been placed there at | 
|  | // an earlier time.  The dependency chain should not be empty, | 
|  | // unless the instruction dependent upon it is already ready. | 
|  | if (curr == NULL) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | nodesRemoved++; | 
|  |  | 
|  | // Find the instruction to remove within the dependency linked list. | 
|  | while (curr->inst != inst_to_remove) { | 
|  | prev = curr; | 
|  | curr = curr->next; | 
|  | nodesTraversed++; | 
|  |  | 
|  | assert(curr != NULL); | 
|  | } | 
|  |  | 
|  | // Now remove this instruction from the list. | 
|  | prev->next = curr->next; | 
|  |  | 
|  | --memAllocCounter; | 
|  |  | 
|  | // Could push this off to the destructor of DependencyEntry | 
|  | curr->inst = NULL; | 
|  |  | 
|  | delete curr; | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | DynInstPtr | 
|  | DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx) | 
|  | { | 
|  | DepEntry *node; | 
|  | node = dependGraph[idx].next; | 
|  | DynInstPtr inst = NULL; | 
|  | if (node) { | 
|  | inst = node->inst; | 
|  | dependGraph[idx].next = node->next; | 
|  | node->inst = NULL; | 
|  | memAllocCounter--; | 
|  | delete node; | 
|  | } | 
|  | return inst; | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | bool | 
|  | DependencyGraph<DynInstPtr>::empty() const | 
|  | { | 
|  | for (int i = 0; i < numEntries; ++i) { | 
|  | if (!empty(i)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <class DynInstPtr> | 
|  | void | 
|  | DependencyGraph<DynInstPtr>::dump() | 
|  | { | 
|  | DepEntry *curr; | 
|  |  | 
|  | for (int i = 0; i < numEntries; ++i) | 
|  | { | 
|  | curr = &dependGraph[i]; | 
|  |  | 
|  | if (curr->inst) { | 
|  | cprintf("dependGraph[%i]: producer: %s [sn:%lli] consumer: ", | 
|  | i, curr->inst->pcState(), curr->inst->seqNum); | 
|  | } else { | 
|  | cprintf("dependGraph[%i]: No producer. consumer: ", i); | 
|  | } | 
|  |  | 
|  | while (curr->next != NULL) { | 
|  | curr = curr->next; | 
|  |  | 
|  | cprintf("%s [sn:%lli] ", | 
|  | curr->inst->pcState(), curr->inst->seqNum); | 
|  | } | 
|  |  | 
|  | cprintf("\n"); | 
|  | } | 
|  | cprintf("memAllocCounter: %i\n", memAllocCounter); | 
|  | } | 
|  |  | 
|  | #endif // __CPU_O3_DEP_GRAPH_HH__ |