ruby: Import ruby and slicc from GEMS
We eventually plan to replace the m5 cache hierarchy with the GEMS hierarchy, but for now we will make both live alongside eachother.
This commit is contained in:
parent
c70241810d
commit
2f30950143
485 changed files with 101056 additions and 0 deletions
83
src/mem/gems_common/Allocator.hh
Normal file
83
src/mem/gems_common/Allocator.hh
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 1999 by Mark Hill and David Wood for the Wisconsin
|
||||
* Multifacet Project. ALL RIGHTS RESERVED.
|
||||
*
|
||||
* ##HEADER##
|
||||
*
|
||||
* This software is furnished under a license and may be used and
|
||||
* copied only in accordance with the terms of such license and the
|
||||
* inclusion of the above copyright notice. This software or any
|
||||
* other copies thereof or any derivative works may not be provided or
|
||||
* otherwise made available to any other persons. Title to and
|
||||
* ownership of the software is retained by Mark Hill and David Wood.
|
||||
* Any use of this software must include the above copyright notice.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS". THE LICENSOR MAKES NO
|
||||
* WARRANTIES ABOUT ITS CORRECTNESS OR PERFORMANCE.
|
||||
* */
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef ALLOCATOR_H
|
||||
#define ALLOCATOR_H
|
||||
|
||||
#include "Vector.hh"
|
||||
|
||||
template <class TYPE>
|
||||
class Allocator {
|
||||
public:
|
||||
// Constructors
|
||||
Allocator() { m_counter = 0; }
|
||||
|
||||
// Destructor
|
||||
~Allocator() { for(int i=0; i<m_pool_vec.size(); i++) { delete m_pool_vec[i]; }}
|
||||
|
||||
// Public Methods
|
||||
TYPE* allocate(const TYPE& obj);
|
||||
void deallocate(TYPE* obj_ptr);
|
||||
private:
|
||||
// Private copy constructor and assignment operator
|
||||
Allocator(const Allocator& obj);
|
||||
Allocator& operator=(const Allocator& obj);
|
||||
|
||||
// Private Methods
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
Vector<TYPE*> m_pool_vec;
|
||||
int m_counter;
|
||||
};
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
TYPE* Allocator<TYPE>::allocate(const TYPE& obj)
|
||||
{
|
||||
m_counter++;
|
||||
DEBUG_EXPR(ALLOCATOR_COMP, LowPrio, m_counter);
|
||||
TYPE* new_obj_ptr;
|
||||
|
||||
// See if we need to allocate any new objects
|
||||
if (m_pool_vec.size() == 0) {
|
||||
// Allocate a new item
|
||||
m_pool_vec.insertAtBottom(new TYPE);
|
||||
}
|
||||
|
||||
// Pop the pointer from the stack/pool
|
||||
int size = m_pool_vec.size();
|
||||
new_obj_ptr = m_pool_vec[size-1];
|
||||
m_pool_vec.setSize(size-1);
|
||||
|
||||
// Copy the object
|
||||
*new_obj_ptr = obj;
|
||||
return new_obj_ptr;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Allocator<TYPE>::deallocate(TYPE* obj)
|
||||
{
|
||||
m_pool_vec.insertAtBottom(obj);
|
||||
}
|
||||
|
||||
#endif //ALLOCATOR_H
|
186
src/mem/gems_common/Map.hh
Normal file
186
src/mem/gems_common/Map.hh
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAP_H
|
||||
#define MAP_H
|
||||
|
||||
#include "Vector.hh"
|
||||
|
||||
namespace __gnu_cxx {
|
||||
template <> struct hash <std::string>
|
||||
{
|
||||
size_t operator()(const string& s) const { return hash<char*>()(s.c_str()); }
|
||||
};
|
||||
}
|
||||
|
||||
typedef unsigned long long uint64;
|
||||
//hack for uint64 hashes...
|
||||
namespace __gnu_cxx {
|
||||
template <> struct hash <uint64>
|
||||
{
|
||||
size_t operator()(const uint64 & s) const { return (size_t) s; }
|
||||
};
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
Map() { /* empty */ }
|
||||
~Map() { /* empty */ }
|
||||
|
||||
void add(const KEY_TYPE& key, const VALUE_TYPE& value);
|
||||
bool exist(const KEY_TYPE& key) const;
|
||||
int size() const { return m_map.size(); }
|
||||
void erase(const KEY_TYPE& key) { assert(exist(key)); m_map.erase(key); }
|
||||
Vector<KEY_TYPE> keys() const;
|
||||
Vector<VALUE_TYPE> values() const;
|
||||
void deleteKeys();
|
||||
void deleteValues();
|
||||
VALUE_TYPE& lookup(const KEY_TYPE& key) const;
|
||||
void clear() { m_map.clear(); }
|
||||
void print(ostream& out) const;
|
||||
|
||||
// Synonyms
|
||||
void remove(const KEY_TYPE& key) { erase(key); }
|
||||
void deallocate(const KEY_TYPE& key) { erase(key); }
|
||||
void allocate(const KEY_TYPE& key) { add(key, VALUE_TYPE()); }
|
||||
void insert(const KEY_TYPE& key, const VALUE_TYPE& value) { add(key, value); }
|
||||
|
||||
// Use default copy constructor and assignment operator
|
||||
private:
|
||||
// Data members
|
||||
|
||||
// m_map is declared mutable because some methods from the STL "map"
|
||||
// class that should be const are not. Thus we define this as
|
||||
// mutable so we can still have conceptually const accessors.
|
||||
mutable __gnu_cxx::hash_map<KEY_TYPE, VALUE_TYPE> m_map;
|
||||
};
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
ostream& operator<<(ostream& out, const Map<KEY_TYPE, VALUE_TYPE>& map);
|
||||
|
||||
// *********************
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
void Map<KEY_TYPE, VALUE_TYPE>::add(const KEY_TYPE& key, const VALUE_TYPE& value)
|
||||
{
|
||||
// Update or add a new key/value pair
|
||||
m_map[key] = value;
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
bool Map<KEY_TYPE, VALUE_TYPE>::exist(const KEY_TYPE& key) const
|
||||
{
|
||||
return (m_map.count(key) != 0);
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
VALUE_TYPE& Map<KEY_TYPE, VALUE_TYPE>::lookup(const KEY_TYPE& key) const
|
||||
{
|
||||
assert(exist(key));
|
||||
return m_map[key];
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
Vector<KEY_TYPE> Map<KEY_TYPE, VALUE_TYPE>::keys() const
|
||||
{
|
||||
Vector<KEY_TYPE> keys;
|
||||
typename hash_map<KEY_TYPE, VALUE_TYPE>::const_iterator iter;
|
||||
for (iter = m_map.begin(); iter != m_map.end(); iter++) {
|
||||
keys.insertAtBottom((*iter).first);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
Vector<VALUE_TYPE> Map<KEY_TYPE, VALUE_TYPE>::values() const
|
||||
{
|
||||
Vector<VALUE_TYPE> values;
|
||||
typename hash_map<KEY_TYPE, VALUE_TYPE>::const_iterator iter;
|
||||
pair<KEY_TYPE, VALUE_TYPE> p;
|
||||
|
||||
for (iter = m_map.begin(); iter != m_map.end(); iter++) {
|
||||
p = *iter;
|
||||
values.insertAtBottom(p.second);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
void Map<KEY_TYPE, VALUE_TYPE>::deleteKeys()
|
||||
{
|
||||
typename hash_map<KEY_TYPE, VALUE_TYPE>::const_iterator iter;
|
||||
pair<KEY_TYPE, VALUE_TYPE> p;
|
||||
|
||||
for (iter = m_map.begin(); iter != m_map.end(); iter++) {
|
||||
p = *iter;
|
||||
delete p.first;
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
void Map<KEY_TYPE, VALUE_TYPE>::deleteValues()
|
||||
{
|
||||
typename hash_map<KEY_TYPE, VALUE_TYPE>::const_iterator iter;
|
||||
pair<KEY_TYPE, VALUE_TYPE> p;
|
||||
|
||||
for (iter = m_map.begin(); iter != m_map.end(); iter++) {
|
||||
p = *iter;
|
||||
delete p.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
void Map<KEY_TYPE, VALUE_TYPE>::print(ostream& out) const
|
||||
{
|
||||
typename hash_map<KEY_TYPE, VALUE_TYPE>::const_iterator iter;
|
||||
pair<KEY_TYPE, VALUE_TYPE> p;
|
||||
|
||||
out << "[";
|
||||
for (iter = m_map.begin(); iter != m_map.end(); iter++) {
|
||||
// unparse each basic block
|
||||
p = *iter;
|
||||
out << " " << p.first << "=" << p.second;
|
||||
}
|
||||
out << " ]";
|
||||
}
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE>
|
||||
ostream& operator<<(ostream& out, const Map<KEY_TYPE, VALUE_TYPE>& map)
|
||||
{
|
||||
map.print(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //MAP_H
|
249
src/mem/gems_common/PrioHeap.hh
Normal file
249
src/mem/gems_common/PrioHeap.hh
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PRIOHEAP_H
|
||||
#define PRIOHEAP_H
|
||||
|
||||
#include "Vector.hh"
|
||||
|
||||
typedef unsigned int HeapIndex;
|
||||
|
||||
template <class TYPE>
|
||||
class PrioHeap {
|
||||
public:
|
||||
// Constructors
|
||||
PrioHeap() { init(); }
|
||||
|
||||
// Destructor
|
||||
//~PrioHeap();
|
||||
|
||||
// Public Methods
|
||||
void init() { m_current_size = 0; }
|
||||
int size() const { return m_current_size; }
|
||||
void insert(const TYPE& key);
|
||||
const TYPE& peekMin() const;
|
||||
const TYPE& peekElement(int index) const;
|
||||
TYPE extractMin();
|
||||
void print(ostream& out) const;
|
||||
private:
|
||||
// Private Methods
|
||||
bool verifyHeap() const;
|
||||
bool verifyHeap(HeapIndex index) const;
|
||||
void heapify();
|
||||
|
||||
// Private copy constructor and assignment operator
|
||||
PrioHeap(const PrioHeap& obj);
|
||||
PrioHeap<TYPE>& operator=(const PrioHeap& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
Vector<TYPE> m_heap;
|
||||
HeapIndex m_current_size;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
template <class TYPE>
|
||||
ostream& operator<<(ostream& out, const PrioHeap<TYPE>& obj);
|
||||
|
||||
// ******************* Helper Functions *******************
|
||||
inline
|
||||
HeapIndex get_parent(HeapIndex i)
|
||||
{
|
||||
// return (i/2);
|
||||
return (i>>1);
|
||||
}
|
||||
|
||||
inline
|
||||
HeapIndex get_right(HeapIndex i)
|
||||
{
|
||||
// return (2*i) + 1;
|
||||
return (i<<1) | 1;
|
||||
}
|
||||
|
||||
inline
|
||||
HeapIndex get_left(HeapIndex i)
|
||||
{
|
||||
// return (2*i);
|
||||
return (i<<1);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void prio_heap_swap(TYPE& n1, TYPE& n2)
|
||||
{
|
||||
TYPE temp = n1;
|
||||
n1 = n2;
|
||||
n2 = temp;
|
||||
}
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
template <class TYPE>
|
||||
void PrioHeap<TYPE>::insert(const TYPE& key)
|
||||
{
|
||||
int i;
|
||||
// grow the vector size
|
||||
m_current_size++;
|
||||
m_heap.setSize(m_current_size+1);
|
||||
|
||||
if(m_current_size == 1){ // HACK: need to initialize index 0 to avoid purify UMCs
|
||||
m_heap[0] = key;
|
||||
}
|
||||
|
||||
i = m_current_size;
|
||||
while ((i > 1) && (node_less_then_eq(key, m_heap[get_parent(i)]))) {
|
||||
m_heap[i] = m_heap[get_parent(i)];
|
||||
i = get_parent(i);
|
||||
}
|
||||
m_heap[i] = key;
|
||||
// assert(verifyHeap());
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
const TYPE& PrioHeap<TYPE>::peekMin() const
|
||||
{
|
||||
assert(size() > 0);
|
||||
return m_heap[1]; // 1, not 0, is the first element
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
const TYPE& PrioHeap<TYPE>::peekElement(int index) const
|
||||
{
|
||||
assert(size() > 0);
|
||||
return m_heap[index];
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
TYPE PrioHeap<TYPE>::extractMin()
|
||||
{
|
||||
// TYPE temp;
|
||||
assert(size() > 0);
|
||||
TYPE temp = m_heap[1]; // 1, not 0, is the first element
|
||||
m_heap[1] = m_heap[m_current_size];
|
||||
m_current_size--;
|
||||
heapify();
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
bool PrioHeap<TYPE>::verifyHeap() const
|
||||
{
|
||||
return verifyHeap(1);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
bool PrioHeap<TYPE>::verifyHeap(HeapIndex index) const
|
||||
{
|
||||
// Recursively verify that each node is <= its parent
|
||||
if(index > m_current_size) {
|
||||
return true;
|
||||
} else if (index == 1) {
|
||||
return
|
||||
verifyHeap(get_right(index)) &&
|
||||
verifyHeap(get_left(index));
|
||||
} else if (node_less_then_eq(m_heap[get_parent(index)], m_heap[index])) {
|
||||
return
|
||||
verifyHeap(get_right(index)) &&
|
||||
verifyHeap(get_left(index));
|
||||
} else {
|
||||
// Heap property violation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void PrioHeap<TYPE>::heapify()
|
||||
{
|
||||
HeapIndex current_node = 1;
|
||||
HeapIndex left, right, smallest;
|
||||
// HeapIndex size = m_current_size;
|
||||
|
||||
while(true) {
|
||||
left = get_left(current_node);
|
||||
right = get_right(current_node);
|
||||
|
||||
// Find the smallest of the current node and children
|
||||
if (left <= m_current_size && node_less_then_eq(m_heap[left], m_heap[current_node])) {
|
||||
smallest = left;
|
||||
} else {
|
||||
smallest = current_node;
|
||||
}
|
||||
|
||||
if (right <= m_current_size && node_less_then_eq(m_heap[right], m_heap[smallest])) {
|
||||
smallest = right;
|
||||
}
|
||||
|
||||
// Check to see if we are done
|
||||
if (smallest == current_node) {
|
||||
// We are done
|
||||
break;
|
||||
} else {
|
||||
// Not done, heapify on the smallest child
|
||||
prio_heap_swap(m_heap[current_node], m_heap[smallest]);
|
||||
current_node = smallest;
|
||||
}
|
||||
}
|
||||
// assert(verifyHeap());
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void PrioHeap<TYPE>::print(ostream& out) const
|
||||
{
|
||||
Vector<TYPE> copyHeap(m_heap);
|
||||
|
||||
// sort copyHeap (inefficient, but will not be done often)
|
||||
|
||||
for(HeapIndex i=0;i<m_current_size; i++){
|
||||
for(HeapIndex j=0; j< m_current_size; j++){
|
||||
if(copyHeap[i].m_time < copyHeap[j].m_time){
|
||||
prio_heap_swap(copyHeap[i], copyHeap[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out << "[PrioHeap: ";
|
||||
|
||||
for(HeapIndex i=1; i<= m_current_size; i++){
|
||||
out << copyHeap[i];
|
||||
|
||||
if(i != m_current_size-1){
|
||||
out << ",";
|
||||
}
|
||||
out << " ";
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
// Output operator definition
|
||||
template <class TYPE>
|
||||
ostream& operator<<(ostream& out, const PrioHeap<TYPE>& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //PRIOHEAP_H
|
162
src/mem/gems_common/RefCnt.hh
Normal file
162
src/mem/gems_common/RefCnt.hh
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef REFCNT_H
|
||||
#define REFCNT_H
|
||||
|
||||
template <class TYPE>
|
||||
class RefCnt {
|
||||
public:
|
||||
// Constructors
|
||||
RefCnt();
|
||||
RefCnt(const TYPE& data);
|
||||
|
||||
// Destructor
|
||||
~RefCnt();
|
||||
|
||||
// Public Methods
|
||||
const TYPE* ref() const { return m_data_ptr; }
|
||||
TYPE* ref() { return m_data_ptr; }
|
||||
TYPE* mod_ref() const { return m_data_ptr; }
|
||||
void freeRef();
|
||||
void print(ostream& out) const;
|
||||
|
||||
// Public copy constructor and assignment operator
|
||||
RefCnt(const RefCnt& obj);
|
||||
RefCnt& operator=(const RefCnt& obj);
|
||||
|
||||
private:
|
||||
// Private Methods
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
TYPE* m_data_ptr;
|
||||
// int* m_count_ptr; // Not used yet
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
template <class TYPE>
|
||||
inline
|
||||
ostream& operator<<(ostream& out, const RefCnt<TYPE>& obj);
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
// Constructors
|
||||
template <class TYPE>
|
||||
inline
|
||||
RefCnt<TYPE>::RefCnt()
|
||||
{
|
||||
m_data_ptr = NULL;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
RefCnt<TYPE>::RefCnt(const TYPE& data)
|
||||
{
|
||||
m_data_ptr = data.clone();
|
||||
m_data_ptr->setRefCnt(1);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
RefCnt<TYPE>::~RefCnt()
|
||||
{
|
||||
freeRef();
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void RefCnt<TYPE>::freeRef()
|
||||
{
|
||||
if (m_data_ptr != NULL) {
|
||||
m_data_ptr->decRefCnt();
|
||||
if (m_data_ptr->getRefCnt() == 0) {
|
||||
m_data_ptr->destroy();
|
||||
}
|
||||
m_data_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void RefCnt<TYPE>::print(ostream& out) const
|
||||
{
|
||||
if (m_data_ptr == NULL) {
|
||||
out << "[RefCnt: Null]";
|
||||
} else {
|
||||
out << "[RefCnt: ";
|
||||
m_data_ptr->print(out);
|
||||
out << "]";
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
template <class TYPE>
|
||||
inline
|
||||
RefCnt<TYPE>::RefCnt(const RefCnt<TYPE>& obj)
|
||||
{
|
||||
// m_data_ptr = obj.m_data_ptr->clone();
|
||||
m_data_ptr = obj.m_data_ptr;
|
||||
|
||||
// Increment the reference count
|
||||
if (m_data_ptr != NULL) {
|
||||
m_data_ptr->incRefCnt();
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment operator
|
||||
template <class TYPE>
|
||||
inline
|
||||
RefCnt<TYPE>& RefCnt<TYPE>::operator=(const RefCnt<TYPE>& obj)
|
||||
{
|
||||
if (this == &obj) {
|
||||
// If this is the case, do nothing
|
||||
// assert(false);
|
||||
} else {
|
||||
freeRef();
|
||||
m_data_ptr = obj.m_data_ptr;
|
||||
if (m_data_ptr != NULL) {
|
||||
m_data_ptr->incRefCnt();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Output operator definition
|
||||
template <class TYPE>
|
||||
inline
|
||||
ostream& operator<<(ostream& out, const RefCnt<TYPE>& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //REFCNT_H
|
78
src/mem/gems_common/RefCnt_tester.cc
Normal file
78
src/mem/gems_common/RefCnt_tester.cc
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code used to test the RefCnt class
|
||||
*/
|
||||
|
||||
#include "RefCnt.hh"
|
||||
#include "RefCountable.hh"
|
||||
|
||||
class Foo : public RefCountable {
|
||||
public:
|
||||
int m_data;
|
||||
Foo* clone() const;
|
||||
private:
|
||||
};
|
||||
|
||||
Foo* Foo::clone() const
|
||||
{
|
||||
Foo* temp_ptr;
|
||||
temp_ptr = new Foo;
|
||||
*temp_ptr = *this;
|
||||
cout << "Cloned!" << endl;
|
||||
return temp_ptr;
|
||||
}
|
||||
|
||||
void bar(RefCnt<Foo> f)
|
||||
{
|
||||
cout << f.ref()->m_data << endl;
|
||||
}
|
||||
|
||||
Foo f2;
|
||||
|
||||
int main()
|
||||
{
|
||||
Foo f;
|
||||
f.m_data = 2;
|
||||
|
||||
{
|
||||
RefCnt<Foo> a(f);
|
||||
|
||||
f.m_data = 3;
|
||||
cout << a.ref()->m_data << endl;
|
||||
cout << f.m_data << endl;
|
||||
f2 = f;
|
||||
}
|
||||
|
||||
bar(f2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
59
src/mem/gems_common/RefCountable.hh
Normal file
59
src/mem/gems_common/RefCountable.hh
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Virtual base class for things that can be reference counted
|
||||
*/
|
||||
|
||||
#ifndef REFCOUNTABLE_H
|
||||
#define REFCOUNTABLE_H
|
||||
|
||||
#include "RefCnt.hh"
|
||||
|
||||
class RefCountable {
|
||||
public:
|
||||
// Public Methods
|
||||
|
||||
RefCountable() { m_refcnt = 0; }
|
||||
|
||||
// These are used by the RefCnt class to hold the reference count
|
||||
// for the object. These really should be private and accessed by a
|
||||
// friend class, but I can't figure out how to make a template class
|
||||
// a friend.
|
||||
void incRefCnt() { m_refcnt++; }
|
||||
void decRefCnt() { m_refcnt--; }
|
||||
int getRefCnt() const { return m_refcnt; }
|
||||
void setRefCnt(int cnt) { m_refcnt = cnt; }
|
||||
private:
|
||||
// Private Methods
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
int m_refcnt;
|
||||
};
|
||||
|
||||
#endif //REFCOUNTABLE_H
|
334
src/mem/gems_common/Vector.hh
Normal file
334
src/mem/gems_common/Vector.hh
Normal file
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Description: The Vector class is a generic container which acts
|
||||
* much like an array. The Vector class handles dynamic sizing and
|
||||
* resizing as well as performing bounds checking on each access. An
|
||||
* "insertAtBottom" operation is supported to allow adding elements to
|
||||
* the Vector much like you would add new elements to a linked list or
|
||||
* queue.
|
||||
*/
|
||||
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include "std-includes.hh"
|
||||
|
||||
template <class TYPE>
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
Vector();
|
||||
explicit Vector(int initial_size); // Construct with an initial max size
|
||||
~Vector();
|
||||
const TYPE& ref(int index) const; // Get an element of the vector
|
||||
TYPE& ref(int index); // Get an element of the vector
|
||||
void clear(); // remove all elements of the vector
|
||||
void sortVector(); // sort all elements using < operator
|
||||
int size() const { return m_size; }
|
||||
void setSize(int new_size); // Increase size, reallocates memory as needed
|
||||
void expand(int num) { setSize(m_size+num); } // Increase size by num
|
||||
void increaseSize(int new_size, const TYPE& reset); // and adds num of slots at the bottom set to reset value
|
||||
void insertAtTop(const TYPE& element); // Increase size by one and set last element
|
||||
// FIXME - WARNING: insertAtTop is currently O(n) and needs to be fixed
|
||||
void insertAtBottom(const TYPE& element); // Increase size by one and set last element
|
||||
TYPE sum() const; // Uses the += operator to sum all the elements of the vector
|
||||
void deletePointers(); // Walks the Vector calling delete on all
|
||||
// elements and sets them to NULL, can only
|
||||
// be used when the TYPE is a pointer type.
|
||||
void removeFromTop(int num); // removes elements from top
|
||||
void print(ostream& out) const;
|
||||
|
||||
|
||||
// Array Reference operator overloading
|
||||
const TYPE& operator[](int index) const { return ref(index); }
|
||||
TYPE& operator[](int index) { return ref(index); }
|
||||
|
||||
// Public copy constructor and assignment operator
|
||||
Vector(const Vector& vec);
|
||||
Vector<TYPE>& operator=(const Vector& vec);
|
||||
private:
|
||||
|
||||
void grow(int new_max_size); // Expands vector to new_max_size
|
||||
|
||||
// Data members
|
||||
TYPE* m_vec; // Array to hold the elements
|
||||
int m_size; // Number of elements in use
|
||||
int m_max_size; // Size of allocated array
|
||||
};
|
||||
|
||||
template <class TYPE>
|
||||
ostream& operator<<(ostream& out, const Vector<TYPE>& vec);
|
||||
|
||||
// *********************
|
||||
|
||||
template <class TYPE>
|
||||
Vector<TYPE>::Vector()
|
||||
{
|
||||
m_size = 0;
|
||||
m_max_size = 0;
|
||||
m_vec = NULL;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
Vector<TYPE>::Vector(int initial_size)
|
||||
{
|
||||
m_size = 0;
|
||||
m_max_size = initial_size;
|
||||
m_vec = NULL;
|
||||
grow(initial_size);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
Vector<TYPE>::~Vector()
|
||||
{
|
||||
delete [] m_vec;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
const TYPE& Vector<TYPE>::ref(int index) const
|
||||
{
|
||||
#ifndef NO_VECTOR_BOUNDS_CHECKS
|
||||
assert(m_size != 0);
|
||||
assert(index < m_size);
|
||||
assert(index >= 0);
|
||||
#endif
|
||||
return m_vec[index];
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
TYPE& Vector<TYPE>::ref(int index)
|
||||
{
|
||||
#ifndef NO_VECTOR_BOUNDS_CHECKS
|
||||
assert(m_size != 0);
|
||||
assert(index < m_size);
|
||||
assert(index >= 0);
|
||||
#endif
|
||||
return m_vec[index];
|
||||
}
|
||||
|
||||
|
||||
template <class TYPE>
|
||||
void Vector<TYPE>::setSize(int new_size)
|
||||
{
|
||||
// FIXME - this should also decrease or shrink the size of the array at some point.
|
||||
if (new_size > m_max_size) {
|
||||
grow(max((m_max_size+1)*2, new_size));
|
||||
}
|
||||
m_size = new_size;
|
||||
#ifndef NO_VECTOR_BOUNDS_CHECKS
|
||||
assert(m_size <= m_max_size);
|
||||
assert(m_size >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Vector<TYPE>::increaseSize(int new_size, const TYPE& reset)
|
||||
{
|
||||
assert(new_size >= m_size);
|
||||
if (new_size >= m_max_size) {
|
||||
grow(max((m_max_size+1)*2, new_size));
|
||||
}
|
||||
int old_size = m_size;
|
||||
m_size = new_size;
|
||||
for (int j = old_size; j < m_size; j++) {
|
||||
ref(j) = reset;
|
||||
}
|
||||
|
||||
#ifndef NO_VECTOR_BOUNDS_CHECKS
|
||||
assert(m_size <= m_max_size);
|
||||
assert(m_size >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Vector<TYPE>::clear()
|
||||
{
|
||||
m_size = 0;
|
||||
m_max_size = 0;
|
||||
delete [] m_vec;
|
||||
m_vec = NULL;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Vector<TYPE>::sortVector()
|
||||
{
|
||||
sort(&m_vec[0], &m_vec[m_size]);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Vector<TYPE>::insertAtTop(const TYPE& element)
|
||||
{
|
||||
setSize(m_size+1);
|
||||
for (int i = m_size-1; i >= 1; i--) {
|
||||
ref(i) = ref(i-1);
|
||||
}
|
||||
ref(0) = element;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline
|
||||
void Vector<TYPE>::removeFromTop(int num)
|
||||
{
|
||||
if (num > m_size) {
|
||||
num = m_size;
|
||||
}
|
||||
for (int i = 0; i < m_size - num; i++) {
|
||||
m_vec[i] = m_vec[i+num];
|
||||
}
|
||||
m_size = m_size - num;
|
||||
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void Vector<TYPE>::insertAtBottom(const TYPE& element)
|
||||
{
|
||||
setSize(m_size+1);
|
||||
ref(m_size-1) = element;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
TYPE Vector<TYPE>::sum() const
|
||||
{
|
||||
assert(m_size > 0);
|
||||
TYPE sum = ref(0);
|
||||
for(int i=1; i<m_size; i++) {
|
||||
sum += ref(i);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void Vector<TYPE>::deletePointers()
|
||||
{
|
||||
assert(m_size >= 0);
|
||||
for(int i=0; i<m_size; i++) {
|
||||
// FIXME this function should be non-member function, otherwise this
|
||||
// prevent template instantiation for non-pointer types
|
||||
//
|
||||
// Also, there is warning of Switch.cc which use void* here
|
||||
delete ref(i);
|
||||
ref(i) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void Vector<TYPE>::print(ostream& out) const
|
||||
{
|
||||
out << "[ ";
|
||||
for(int i=0; i<m_size; i++) {
|
||||
if (i != 0) {
|
||||
out << " ";
|
||||
}
|
||||
out << ref(i);
|
||||
}
|
||||
out << " ]";
|
||||
out << flush;
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
template <class TYPE>
|
||||
Vector<TYPE>::Vector(const Vector& vec)
|
||||
{
|
||||
// Setup the new memory
|
||||
m_size = vec.m_size;
|
||||
m_max_size = vec.m_max_size;
|
||||
if (m_max_size != 0) {
|
||||
m_vec = new TYPE[m_max_size];
|
||||
assert(m_vec != NULL);
|
||||
} else {
|
||||
m_vec = NULL;
|
||||
}
|
||||
|
||||
// Copy the elements of the array
|
||||
for(int i=0; i<m_size; i++) {
|
||||
m_vec[i] = vec.m_vec[i]; // Element copy
|
||||
}
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
Vector<TYPE>& Vector<TYPE>::operator=(const Vector& vec)
|
||||
{
|
||||
if (this == &vec) {
|
||||
// assert(0);
|
||||
} else {
|
||||
// Free the old memory
|
||||
delete [] m_vec;
|
||||
|
||||
// Setup the new memory
|
||||
m_size = vec.m_size;
|
||||
m_max_size = vec.m_max_size;
|
||||
|
||||
if (m_max_size != 0) {
|
||||
m_vec = new TYPE[m_max_size];
|
||||
assert(m_vec != NULL);
|
||||
} else {
|
||||
m_vec = NULL;
|
||||
}
|
||||
|
||||
// Copy the elements of the array
|
||||
for(int i=0; i<m_size; i++) {
|
||||
m_vec[i] = vec.m_vec[i]; // Element copy
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
void Vector<TYPE>::grow(int new_max_size)
|
||||
{
|
||||
TYPE* temp_vec;
|
||||
m_max_size = new_max_size;
|
||||
if (new_max_size != 0) {
|
||||
temp_vec = new TYPE[new_max_size];
|
||||
assert(temp_vec != NULL);
|
||||
} else {
|
||||
temp_vec = NULL;
|
||||
}
|
||||
|
||||
// Copy the elements of the array
|
||||
for(int i=0; i<m_size; i++) {
|
||||
temp_vec[i] = m_vec[i]; // Element copy
|
||||
}
|
||||
delete [] m_vec;
|
||||
m_vec = temp_vec;
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
ostream& operator<<(ostream& out, const Vector<TYPE>& vec)
|
||||
{
|
||||
vec.print(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //VECTOR_H
|
38
src/mem/gems_common/calc_host.sh
Executable file
38
src/mem/gems_common/calc_host.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/csh -f
|
||||
|
||||
set OS=`uname -s`
|
||||
set HOST_ARCH=`uname -m`
|
||||
|
||||
switch ($OS)
|
||||
case Linux:
|
||||
set OS_PART=linux
|
||||
breaksw
|
||||
case SunOS:
|
||||
set OS_PART=sol8-64
|
||||
breaksw
|
||||
case OSF1:
|
||||
set OS_PART=tru64-gcc
|
||||
breaksw
|
||||
default:
|
||||
set OS_PART=`echo $OS | sed 's/ /-/g'`
|
||||
endsw
|
||||
|
||||
switch ($HOST_ARCH)
|
||||
case i586:
|
||||
set ARCH=x86
|
||||
breaksw
|
||||
case i686:
|
||||
set ARCH=x86
|
||||
breaksw
|
||||
case x86_64:
|
||||
set ARCH=amd64
|
||||
breaksw
|
||||
case sun4u:
|
||||
set ARCH=v9
|
||||
breaksw
|
||||
default:
|
||||
set ARCH=`echo $HOST_ARCH | sed 's/ /-/g'`
|
||||
endsw
|
||||
|
||||
echo $ARCH-$OS_PART
|
||||
|
229
src/mem/gems_common/ioutil/attrlex.ll
Normal file
229
src/mem/gems_common/ioutil/attrlex.ll
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
Copyright (C) 1999-2005 by Mark D. Hill and David A. Wood for the
|
||||
Wisconsin Multifacet Project. Contact: gems@cs.wisc.edu
|
||||
http://www.cs.wisc.edu/gems/
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This file a component of the Multifacet GEMS (General
|
||||
Execution-driven Multiprocessor Simulator) software toolset
|
||||
originally developed at the University of Wisconsin-Madison.
|
||||
|
||||
Ruby was originally developed primarily by Milo Martin and Daniel
|
||||
Sorin with contributions from Ross Dickson, Carl Mauer, and Manoj
|
||||
Plakal.
|
||||
|
||||
SLICC was originally developed by Milo Martin with substantial
|
||||
contributions from Daniel Sorin.
|
||||
|
||||
Opal was originally developed by Carl Mauer based upon code by
|
||||
Craig Zilles.
|
||||
|
||||
Substantial further development of Multifacet GEMS at the
|
||||
University of Wisconsin was performed by Alaa Alameldeen, Brad
|
||||
Beckmann, Ross Dickson, Pacia Harper, Milo Martin, Michael Marty,
|
||||
Carl Mauer, Kevin Moore, Manoj Plakal, Daniel Sorin, Min Xu, and
|
||||
Luke Yen.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
If your use of this software contributes to a published paper, we
|
||||
request that you (1) cite our summary paper that appears on our
|
||||
website (http://www.cs.wisc.edu/gems/) and (2) e-mail a citation
|
||||
for your published paper to gems@cs.wisc.edu.
|
||||
|
||||
If you redistribute derivatives of this software, we request that
|
||||
you notify us and either (1) ask people to register with us at our
|
||||
website (http://www.cs.wisc.edu/gems/) or (2) collect registration
|
||||
information and periodically send it to us.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Multifacet GEMS is free software; you can redistribute it and/or
|
||||
modify it under the terms of version 2 of the GNU General Public
|
||||
License as published by the Free Software Foundation.
|
||||
|
||||
Multifacet GEMS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the Multifacet GEMS; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA
|
||||
|
||||
The GNU General Public License is contained in the file LICENSE.
|
||||
|
||||
### END HEADER ###
|
||||
*/
|
||||
|
||||
|
||||
%option noyywrap
|
||||
|
||||
ALPHADIGIT [^\:\,\(\)\n\t\(\) \0\#]
|
||||
HEXDIGIT [0-9a-fA-Fx]
|
||||
NEWLINE [\n]
|
||||
WHITESPACE [ \t]
|
||||
|
||||
%{
|
||||
|
||||
#ifdef IS_RUBY
|
||||
#include "Global.hh"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Maurice
|
||||
// extern "C" {
|
||||
// #include "simics/api.h"
|
||||
// };
|
||||
|
||||
#include "FakeSimicsDataTypes.hh"
|
||||
|
||||
// CM: simics 1.6.5 API redefines fwrite, much to my chagrin
|
||||
#undef fwrite
|
||||
#undef printf
|
||||
#include "attrparse.h"
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 10
|
||||
|
||||
/** global result of parsing file */
|
||||
extern attr_value_t g_attr_map;
|
||||
|
||||
extern int atparse(void);
|
||||
|
||||
static int linenum=1; /* the current line number */
|
||||
static int colnum=1; /* the current column number */
|
||||
static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
|
||||
static int include_stack_ptr = 0;
|
||||
static char g_relative_include_path[256];
|
||||
|
||||
|
||||
// forward declaration of aterror
|
||||
void aterror(const char *msg);
|
||||
%}
|
||||
|
||||
%x SLASHCOMMENT INCLUDE
|
||||
|
||||
%%
|
||||
|
||||
%{ /* PATTERNS FOR STRING TOKENS */
|
||||
%}
|
||||
|
||||
"//".*[\n] { linenum++; colnum=1; } /* C++ style comments */
|
||||
|
||||
\#include { colnum+=yyleng; BEGIN(INCLUDE); }
|
||||
<INCLUDE>{WHITESPACE}* { colnum+=yyleng; }
|
||||
<INCLUDE>[^ \t\n]+ {
|
||||
// should really be FILEIO_MAX_FILENAME or MAX_NAME
|
||||
char str[256];
|
||||
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
|
||||
{
|
||||
ERROR_OUT( "Includes nested too deeply" );
|
||||
exit( 1 );
|
||||
}
|
||||
include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
|
||||
|
||||
yyin = fopen( yytext, "r" );
|
||||
if ( ! yyin ) {
|
||||
sprintf( str, "%s%s", g_relative_include_path, yytext );
|
||||
yyin = fopen( str, "r" );
|
||||
}
|
||||
if ( ! yyin ) {
|
||||
sprintf( str, "%s%s%s", g_relative_include_path, "config/", yytext );
|
||||
yyin = fopen( str, "r" );
|
||||
}
|
||||
if ( ! yyin ) {
|
||||
ERROR_OUT("unable to open included file: %s or %s\n", yytext, str);
|
||||
aterror("file open error.\n");
|
||||
}
|
||||
yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ));
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
<<EOF>> {
|
||||
if ( --include_stack_ptr < 0 ) {
|
||||
yyterminate();
|
||||
} else {
|
||||
yy_delete_buffer( YY_CURRENT_BUFFER );
|
||||
fclose(yyin);
|
||||
yy_switch_to_buffer(include_stack[include_stack_ptr] );
|
||||
}
|
||||
}
|
||||
|
||||
\( { colnum+=yyleng; return (LPAREN); }
|
||||
\) { colnum+=yyleng; return (RPAREN); }
|
||||
\: { colnum+=yyleng; return (':'); }
|
||||
\, { colnum+=yyleng; return (','); }
|
||||
{HEXDIGIT}+ {
|
||||
colnum+=yyleng;
|
||||
attr_value_t *val = (attr_value_t *)
|
||||
malloc( sizeof(attr_value_t) );
|
||||
memset( val, 0, sizeof(attr_value_t) );
|
||||
atlval.attrval = val;
|
||||
val->kind = Sim_Val_Integer;
|
||||
val->u.integer = strtoull( yytext, NULL, 0 );
|
||||
return (INTEGER); }
|
||||
{ALPHADIGIT}+ {
|
||||
colnum+=yyleng;
|
||||
attr_value_t *val = (attr_value_t *)
|
||||
malloc( sizeof(attr_value_t) );
|
||||
memset( val, 0, sizeof(attr_value_t) );
|
||||
atlval.attrval = val;
|
||||
val->kind = Sim_Val_String;
|
||||
val->u.string = strdup(yytext);
|
||||
return (STRING); }
|
||||
|
||||
%{ /* OTHER PATTERNS */
|
||||
%}
|
||||
|
||||
{WHITESPACE}+ {colnum += yyleng;}
|
||||
{NEWLINE} {linenum++; colnum = 1;}
|
||||
|
||||
%%
|
||||
|
||||
extern "C" void parseInitialize( void )
|
||||
{
|
||||
// since no global variables are set in simics, we must do it manually
|
||||
// this is also necessary now that the parser can be used more than once.
|
||||
// (it is used to parse the defaults, and can be used after that)
|
||||
linenum = 1;
|
||||
colnum = 1;
|
||||
include_stack_ptr = 0;
|
||||
}
|
||||
|
||||
extern "C" int parseAttrFile( FILE *inputFile, const char *relative_include_path, attr_value_t *myTable )
|
||||
{
|
||||
parseInitialize();
|
||||
strncpy( g_relative_include_path, relative_include_path, 255 );
|
||||
|
||||
int result;
|
||||
yyin = inputFile;
|
||||
YY_BUFFER_STATE scan_state = yy_create_buffer( yyin, YY_BUF_SIZE );
|
||||
yy_switch_to_buffer( scan_state );
|
||||
result = atparse();
|
||||
*myTable = g_attr_map;
|
||||
yy_delete_buffer( scan_state );
|
||||
return (result);
|
||||
}
|
||||
|
||||
extern "C" int parseAttrString( const char *str, attr_value_t *myTable )
|
||||
{
|
||||
parseInitialize();
|
||||
|
||||
int result;
|
||||
YY_BUFFER_STATE scan_state = yy_scan_string( str );
|
||||
result = atparse();
|
||||
*myTable = g_attr_map;
|
||||
yy_delete_buffer( scan_state );
|
||||
return (result);
|
||||
}
|
||||
|
||||
extern void aterror(const char *msg)
|
||||
{
|
||||
ERROR_OUT("%d:%d: ERROR while parsing config file%s\n", linenum, colnum, msg );
|
||||
}
|
||||
|
232
src/mem/gems_common/ioutil/attrparse.yy
Normal file
232
src/mem/gems_common/ioutil/attrparse.yy
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Copyright (C) 1999-2005 by Mark D. Hill and David A. Wood for the
|
||||
Wisconsin Multifacet Project. Contact: gems@cs.wisc.edu
|
||||
http://www.cs.wisc.edu/gems/
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This file a component of the Multifacet GEMS (General
|
||||
Execution-driven Multiprocessor Simulator) software toolset
|
||||
originally developed at the University of Wisconsin-Madison.
|
||||
|
||||
Ruby was originally developed primarily by Milo Martin and Daniel
|
||||
Sorin with contributions from Ross Dickson, Carl Mauer, and Manoj
|
||||
Plakal.
|
||||
|
||||
SLICC was originally developed by Milo Martin with substantial
|
||||
contributions from Daniel Sorin.
|
||||
|
||||
Opal was originally developed by Carl Mauer based upon code by
|
||||
Craig Zilles.
|
||||
|
||||
Substantial further development of Multifacet GEMS at the
|
||||
University of Wisconsin was performed by Alaa Alameldeen, Brad
|
||||
Beckmann, Ross Dickson, Pacia Harper, Milo Martin, Michael Marty,
|
||||
Carl Mauer, Kevin Moore, Manoj Plakal, Daniel Sorin, Min Xu, and
|
||||
Luke Yen.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
If your use of this software contributes to a published paper, we
|
||||
request that you (1) cite our summary paper that appears on our
|
||||
website (http://www.cs.wisc.edu/gems/) and (2) e-mail a citation
|
||||
for your published paper to gems@cs.wisc.edu.
|
||||
|
||||
If you redistribute derivatives of this software, we request that
|
||||
you notify us and either (1) ask people to register with us at our
|
||||
website (http://www.cs.wisc.edu/gems/) or (2) collect registration
|
||||
information and periodically send it to us.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Multifacet GEMS is free software; you can redistribute it and/or
|
||||
modify it under the terms of version 2 of the GNU General Public
|
||||
License as published by the Free Software Foundation.
|
||||
|
||||
Multifacet GEMS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the Multifacet GEMS; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA
|
||||
|
||||
The GNU General Public License is contained in the file LICENSE.
|
||||
|
||||
### END HEADER ###
|
||||
*/
|
||||
|
||||
|
||||
|
||||
%{
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef IS_RUBY
|
||||
#include "Global.hh"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Maurice
|
||||
// extern "C" {
|
||||
// #include "simics/api.h"
|
||||
// };
|
||||
|
||||
#include "FakeSimicsDataTypes.hh"
|
||||
|
||||
#include "confio.hh"
|
||||
|
||||
// CM FIX: if I wasn't working on a paper: I'd re-write the grammer to
|
||||
// be left (or right) recursive, which ever is more efficient
|
||||
// This only affects extremely large cache sizes / BP sizes on read in.
|
||||
#define YYMAXDEPTH 100000
|
||||
|
||||
extern char* attext;
|
||||
|
||||
extern void aterror(const char *);
|
||||
extern int atlex();
|
||||
attr_value_t g_attr_map;
|
||||
|
||||
extern void fprintAttr( FILE *fp, attr_value_t attr );
|
||||
|
||||
%}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Union declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
// The types of the tokens and nonterminals
|
||||
%union {
|
||||
attr_value_t *attrval;
|
||||
};
|
||||
|
||||
%token <attrval> STRING INTEGER
|
||||
%token MY_END LPAREN RPAREN
|
||||
|
||||
%type <attrval> confmapping confpair attributes attrlist
|
||||
%%
|
||||
|
||||
conffile : confmapping
|
||||
{
|
||||
g_attr_map = *($1);
|
||||
free( $1 )
|
||||
}
|
||||
|
||||
confmapping : confmapping confpair
|
||||
{
|
||||
attr_value_t *newattr = mallocAttribute(1);
|
||||
newattr->kind = Sim_Val_List;
|
||||
if ( $1 == NULL ) {
|
||||
newattr->u.list.size = 1;
|
||||
newattr->u.list.vector = $2;
|
||||
} else {
|
||||
// add the latest mapping to the return mapping
|
||||
uint32 newsize = $1->u.list.size + 1;
|
||||
attr_value_t *vector = mallocAttribute( newsize );
|
||||
newattr->u.list.size = newsize;
|
||||
newattr->u.list.vector = vector;
|
||||
for (uint32 i = 0; i < newsize - 1; i++) {
|
||||
vector[i] = $1->u.list.vector[i];
|
||||
}
|
||||
vector[newsize - 1] = *($2);
|
||||
free( $1->u.list.vector );
|
||||
free( $1 );
|
||||
free( $2 );
|
||||
}
|
||||
$$ = newattr;
|
||||
}
|
||||
| // nothing
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
|
||||
confpair : STRING ':' attributes
|
||||
{
|
||||
attr_value_t *newattr = mallocAttribute(1);
|
||||
newattr->kind = Sim_Val_List;
|
||||
newattr->u.list.size = 2;
|
||||
newattr->u.list.vector = mallocAttribute(2);
|
||||
newattr->u.list.vector[0] = *($1);
|
||||
newattr->u.list.vector[1] = *($3);
|
||||
free( $1 );
|
||||
free( $3 );
|
||||
$$ = newattr;
|
||||
}
|
||||
|
||||
attributes : INTEGER
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| STRING
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| LPAREN attrlist RPAREN
|
||||
{
|
||||
attr_value_t *newattr = mallocAttribute(1);
|
||||
newattr->kind = Sim_Val_List;
|
||||
if ( $2->kind != CONF_ATTR_SINGLE &&
|
||||
$2->kind != CONF_ATTR_PAIR ) {
|
||||
newattr->u.list.size = 1;
|
||||
newattr->u.list.vector = $2;
|
||||
} else {
|
||||
newattr->u.list.size = $2->u.list.size;
|
||||
newattr->u.list.vector = mallocAttribute(newattr->u.list.size);
|
||||
attr_value_t *curattr = $2;
|
||||
uint32 i = 0;
|
||||
while ( i < newattr->u.list.size ) {
|
||||
if (curattr->kind == CONF_ATTR_SINGLE) {
|
||||
newattr->u.list.vector[i] = curattr->u.list.vector[0];
|
||||
i++;
|
||||
|
||||
curattr = NULL;
|
||||
} else if (curattr->kind == CONF_ATTR_PAIR) {
|
||||
newattr->u.list.vector[i] = curattr->u.list.vector[0];
|
||||
i++;
|
||||
if ( i < newattr->u.list.size )
|
||||
curattr = &(curattr->u.list.vector[1]);
|
||||
else
|
||||
curattr = NULL;
|
||||
|
||||
} else {
|
||||
ERROR_OUT("error: unknown kind in pair: %d\n", curattr->kind);
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
// FIX memory leak: around 600 KB
|
||||
// freeAttribute( $2 ); // with gcc-3.4 this free call tries to free memory from the stack
|
||||
}
|
||||
$$ = newattr;
|
||||
}
|
||||
|
||||
attrlist : attributes
|
||||
{
|
||||
attr_value_t *newattr = mallocAttribute(1);
|
||||
newattr->kind = CONF_ATTR_SINGLE;
|
||||
newattr->u.list.size = 1;
|
||||
newattr->u.list.vector = $1;
|
||||
$$ = newattr;
|
||||
}
|
||||
| attributes ',' attrlist
|
||||
{
|
||||
// allocate the pair ( x , y ) attribute
|
||||
attr_value_t *newattr = mallocAttribute(1);
|
||||
int newsize = $3->u.list.size + 1;
|
||||
attr_value_t *vector = mallocAttribute(2);
|
||||
newattr->kind = CONF_ATTR_PAIR;
|
||||
newattr->u.list.size = newsize;
|
||||
newattr->u.list.vector = vector;
|
||||
|
||||
// assign the LH attribute
|
||||
vector[0] = *($1);
|
||||
vector[1] = *($3);
|
||||
free( $1 );
|
||||
free( $3 );
|
||||
$$ = newattr;
|
||||
}
|
456
src/mem/gems_common/ioutil/confio.cc
Normal file
456
src/mem/gems_common/ioutil/confio.cc
Normal file
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* saves configuration information for later runs
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef IS_OPAL
|
||||
#include "hfa.hh"
|
||||
#endif
|
||||
|
||||
#ifdef IS_RUBY
|
||||
#include "Global.hh"
|
||||
#define SIM_HALT ASSERT(0)
|
||||
#endif
|
||||
|
||||
#ifdef IS_TOURMALINE
|
||||
#include "Tourmaline_Global.hh"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Maurice
|
||||
// extern "C" {
|
||||
// #include "global.hh"
|
||||
// #include "simics/api.hh"
|
||||
//
|
||||
// #ifdef SIMICS22X
|
||||
// #include "sparc_api.hh"
|
||||
// #endif
|
||||
// #ifdef SIMICS30
|
||||
// #ifdef SPARC
|
||||
// #include "sparc.hh"
|
||||
// #else
|
||||
// #include "x86.hh"
|
||||
// #endif
|
||||
// #endif
|
||||
// };
|
||||
|
||||
#include "FakeSimicsDataTypes.hh"
|
||||
|
||||
#include "confio.hh"
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Macro declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Variable declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Forward declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// C++ Template: explicit instantiation
|
||||
template class map<string, confnode_t *>;
|
||||
|
||||
// These functions are defined in parser/attrlex.l
|
||||
extern "C" int parseAttrFile( FILE *inputFile, const char *relative_include_path, attr_value_t *myTable );
|
||||
extern "C" int parseAttrString( const char *str, attr_value_t *myTable );
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Constructor(s) / destructor */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
confio_t::confio_t( )
|
||||
{
|
||||
m_verbose = false;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
confio_t::~confio_t( )
|
||||
{
|
||||
ConfTable::iterator iter;
|
||||
|
||||
for ( iter = m_table.begin(); iter != m_table.end(); iter++ ) {
|
||||
confnode_t *cfnode = (*iter).second;
|
||||
free( cfnode );
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Public methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Accessor(s) / mutator(s) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
int confio_t::register_attribute( const char *name,
|
||||
get_confio_t get_attr, void *get_attr_data,
|
||||
set_confio_t set_attr, void *set_attr_data )
|
||||
{
|
||||
confnode_t *newnode;
|
||||
if ( m_table.find(name) == m_table.end() ) {
|
||||
if (m_verbose)
|
||||
DEBUG_OUT(" registering checkpoint attribute: \"%s\"\n", name);
|
||||
|
||||
// add a new entry to the table
|
||||
newnode = (confnode_t *) malloc( sizeof( confnode_t ) );
|
||||
newnode->get_attr = get_attr;
|
||||
newnode->set_attr = set_attr;
|
||||
newnode->set_attr_data = set_attr_data;
|
||||
newnode->get_attr_data = get_attr_data;
|
||||
newnode->attr_is_set = false;
|
||||
string key(name);
|
||||
m_table[key] = newnode;
|
||||
} else {
|
||||
ERROR_OUT(" warning: confio: adding existing conf node: %s\n", name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
void fprintAttr( FILE *fp, attr_value_t attr )
|
||||
{
|
||||
switch (attr.kind) {
|
||||
case Sim_Val_Invalid:
|
||||
fprintf(fp, "invalid");
|
||||
break;
|
||||
|
||||
case Sim_Val_String:
|
||||
fprintf(fp, "%s", attr.u.string);
|
||||
break;
|
||||
|
||||
case Sim_Val_Integer:
|
||||
fprintf(fp, "0x%llx", attr.u.integer);
|
||||
break;
|
||||
|
||||
case Sim_Val_Floating:
|
||||
fprintf(fp, "0x%llx", attr.u.integer);
|
||||
break;
|
||||
|
||||
case Sim_Val_List:
|
||||
fprintf(fp, "(");
|
||||
for (uint32 i = 0; i < attr.u.list.size; i++) {
|
||||
fprintAttr(fp, attr.u.list.vector[i]);
|
||||
if (i != attr.u.list.size -1) {
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
}
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_OUT("fprintAttr: unknown/unimplemented attribute %d\n", attr.kind);
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
void freeAttribute( attr_value_t *attr )
|
||||
{
|
||||
switch (attr->kind) {
|
||||
case Sim_Val_Invalid:
|
||||
break;
|
||||
|
||||
case Sim_Val_String:
|
||||
free( (char *) attr->u.string );
|
||||
break;
|
||||
|
||||
case Sim_Val_Integer:
|
||||
break;
|
||||
|
||||
case Sim_Val_Floating:
|
||||
break;
|
||||
|
||||
case Sim_Val_List:
|
||||
for (uint32 i = 0; i < attr->u.list.size; i++) {
|
||||
freeAttribute( &(attr->u.list.vector[i]) );
|
||||
}
|
||||
free( attr->u.list.vector );
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_OUT("freeAttr: unknown/unimplemented attribute %d\n", attr->kind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates, and initializes a attribute value.
|
||||
* @param number The number of values to allocate.
|
||||
* @return A pointer to the newly allocated structure.
|
||||
*/
|
||||
//**************************************************************************
|
||||
attr_value_t *mallocAttribute( uint32 number )
|
||||
{
|
||||
attr_value_t *newattr = (attr_value_t *) malloc( number *
|
||||
sizeof(attr_value_t) );
|
||||
if ( newattr == NULL ) {
|
||||
ERROR_OUT( "confio: mallocAttribute: out of memory\n" );
|
||||
exit(1);
|
||||
}
|
||||
memset( newattr, 0, number*sizeof(attr_value_t) );
|
||||
return (newattr);
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
void fprintMap( FILE *fp, attr_value_t attr )
|
||||
{
|
||||
attr_value_t name;
|
||||
attr_value_t value;
|
||||
|
||||
if (attr.kind != Sim_Val_List)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < attr.u.list.size; i++) {
|
||||
|
||||
if (attr.u.list.vector[i].kind != Sim_Val_List ||
|
||||
attr.u.list.vector[i].u.list.size != 2)
|
||||
return;
|
||||
|
||||
name = attr.u.list.vector[i].u.list.vector[0];
|
||||
value = attr.u.list.vector[i].u.list.vector[1];
|
||||
fprintf( fp, " %s: ", name.u.string);
|
||||
fprintAttr( fp, value );
|
||||
fprintf( fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a configuration file: e.g. save state
|
||||
*/
|
||||
//**************************************************************************
|
||||
int confio_t::writeConfiguration( const char *outputFilename )
|
||||
{
|
||||
FILE *fp;
|
||||
ConfTable::iterator iter;
|
||||
confnode_t *cfnode;
|
||||
attr_value_t attr;
|
||||
|
||||
memset( &attr, 0, sizeof(attr_value_t) );
|
||||
if ( outputFilename == NULL ) {
|
||||
fp = stdout;
|
||||
} else {
|
||||
fp = fopen( outputFilename, "w" );
|
||||
if ( fp == NULL ) {
|
||||
ERROR_OUT("error: writeConfiguration: unable to open file %s\n",
|
||||
outputFilename );
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
for (iter = m_table.begin(); iter != m_table.end(); iter++) {
|
||||
fprintf( fp, " %s: ", (*iter).first.c_str() );
|
||||
cfnode = (*iter).second;
|
||||
attr = (*(cfnode->get_attr))( cfnode->get_attr_data, NULL );
|
||||
fprintAttr( fp, attr );
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
if ( outputFilename != NULL ) {
|
||||
// wrote to a file: now close it!
|
||||
fclose( fp );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read state from an existing configuration file
|
||||
*/
|
||||
//**************************************************************************
|
||||
int confio_t::readConfiguration( const char *inputFilename,
|
||||
const char *relativeIncludePath )
|
||||
{
|
||||
// parse the input stream
|
||||
FILE *fp;
|
||||
char relativeFilename[256];
|
||||
|
||||
fp = fopen( inputFilename, "r" );
|
||||
if ( fp == NULL ) {
|
||||
sprintf( relativeFilename, "%s%s", relativeIncludePath, inputFilename );
|
||||
fp = fopen( relativeFilename, "r" );
|
||||
}
|
||||
if ( fp == NULL ) {
|
||||
sprintf( relativeFilename, "%s%s%s", relativeIncludePath, "config/",
|
||||
inputFilename );
|
||||
fp = fopen( relativeFilename, "r" );
|
||||
}
|
||||
if ( fp == NULL ) {
|
||||
ERROR_OUT("error: readConfiguration: unable to open file %s or %s\n",
|
||||
inputFilename, relativeFilename);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
attr_value_t *myattr = mallocAttribute(1);
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() parsing conf file\n");
|
||||
#endif
|
||||
int rc = parseAttrFile( fp, relativeIncludePath, myattr );
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() parse completed\n");
|
||||
#endif
|
||||
if ( rc == 0 ) {
|
||||
applyConfiguration( myattr );
|
||||
freeAttribute( myattr );
|
||||
free(myattr);
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() completed\n");
|
||||
#endif
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* read state from a configuration string
|
||||
*/
|
||||
//**************************************************************************
|
||||
int confio_t::readConfigurationString( const char *inputBuffer )
|
||||
{
|
||||
if ( inputBuffer == NULL ) {
|
||||
ERROR_OUT( "error: readConfiguration: NULL inputBuffer\n" );
|
||||
return (-1);
|
||||
}
|
||||
|
||||
attr_value_t *myattr = mallocAttribute(1);
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() parsing conf string\n");
|
||||
#endif
|
||||
|
||||
int rc = parseAttrString( inputBuffer, myattr );
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() parse completed\n");
|
||||
#endif
|
||||
if ( rc == 0 ) {
|
||||
applyConfiguration( myattr );
|
||||
freeAttribute( myattr );
|
||||
free(myattr);
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
void confio_t::checkInitialization( void )
|
||||
{
|
||||
ConfTable::iterator iter;
|
||||
confnode_t *cfnode;
|
||||
|
||||
for (iter = m_table.begin(); iter != m_table.end(); iter++) {
|
||||
cfnode = (*iter).second;
|
||||
if ( !cfnode->attr_is_set ) {
|
||||
DEBUG_OUT(" warning: %s is not set in configuration file.\n", (*iter).first.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Private methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
int confio_t::applyConfiguration( attr_value_t *attr )
|
||||
{
|
||||
confnode_t *cfnode;
|
||||
attr_value_t name;
|
||||
attr_value_t value;
|
||||
set_error_t seterr;
|
||||
|
||||
#ifdef MODINIT_VERBOSE
|
||||
DEBUG_OUT("confio_t() data in memory\n");
|
||||
fprintMap( stdout, *attr );
|
||||
#endif
|
||||
|
||||
// apply the configuration the the m_table
|
||||
if (attr->kind != Sim_Val_List ||
|
||||
attr->u.list.size <= 0) {
|
||||
ERROR_OUT("readconfiguration: internal error #1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < attr->u.list.size; i++) {
|
||||
|
||||
if (attr->u.list.vector[i].kind != Sim_Val_List ||
|
||||
attr->u.list.vector[i].u.list.size != 2) {
|
||||
ERROR_OUT("readconfiguration: illegal configuration kind:%d size:%lld\n",
|
||||
attr->u.list.vector[i].kind,
|
||||
attr->u.list.vector[i].u.list.size);
|
||||
continue;
|
||||
}
|
||||
|
||||
name = attr->u.list.vector[i].u.list.vector[0];
|
||||
value = attr->u.list.vector[i].u.list.vector[1];
|
||||
string newstr((char *) name.u.string);
|
||||
if ( m_table.find(newstr) != m_table.end()) {
|
||||
|
||||
// set the value found in the configuration
|
||||
cfnode = m_table[newstr];
|
||||
seterr = (*cfnode->set_attr)( cfnode->set_attr_data, NULL,
|
||||
&(value) );
|
||||
if ( seterr == Sim_Set_Ok ) {
|
||||
cfnode->attr_is_set = true;
|
||||
if (m_verbose)
|
||||
DEBUG_OUT("configuration set for: %s\n", name.u.string);
|
||||
} else {
|
||||
ERROR_OUT("error: \"%s\" unable to set value: %d\n",
|
||||
name.u.string, (int) seterr);
|
||||
}
|
||||
} else {
|
||||
ERROR_OUT("error: \"%s\" not found. unable to set value.\n",
|
||||
name.u.string);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Static methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/** [Memo].
|
||||
* [Internal Documentation]
|
||||
*/
|
||||
//**************************************************************************
|
||||
|
192
src/mem/gems_common/ioutil/confio.hh
Normal file
192
src/mem/gems_common/ioutil/confio.hh
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIO_H_
|
||||
#define _CONFIO_H_
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#include "FakeSimicsDataTypes.hh"
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Macro declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/// constant for attribute parsing: a (x) single value
|
||||
const attr_kind_t CONF_ATTR_SINGLE = (attr_kind_t) (Sim_Val_Object + 1);
|
||||
/// constant for attribute parsing: a (x,y) pair of values
|
||||
const attr_kind_t CONF_ATTR_PAIR = (attr_kind_t) (Sim_Val_Object + 2);
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Class declaration(s) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Functions for modifying the micro-architectural configuation of
|
||||
* a class.
|
||||
*/
|
||||
|
||||
/// function for getting the configuration value
|
||||
typedef attr_value_t (*get_confio_t)( void *ptr, void *obj );
|
||||
/// function for setting the configuration value
|
||||
typedef set_error_t (*set_confio_t)( void *ptr, void *obj,
|
||||
attr_value_t *value );
|
||||
|
||||
/// a struture containing the functional callbacks for each conf node
|
||||
typedef struct confnode {
|
||||
get_confio_t get_attr;
|
||||
set_confio_t set_attr;
|
||||
void *set_attr_data;
|
||||
void *get_attr_data;
|
||||
bool attr_is_set;
|
||||
} confnode_t;
|
||||
|
||||
/// a mapping from a string to a configuration structure
|
||||
typedef map<string, confnode_t *> ConfTable;
|
||||
|
||||
/**
|
||||
* Configuration state saving: allows the user to save the micro-architectural
|
||||
* state in a text file for later runs. This file is also used to set
|
||||
* globals during simulation.
|
||||
*
|
||||
* @author cmauer
|
||||
* @version $Id$
|
||||
*/
|
||||
class confio_t {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* @name Constructor(s) / destructor
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Constructor: creates object
|
||||
*/
|
||||
confio_t();
|
||||
|
||||
/**
|
||||
* Destructor: frees object.
|
||||
*/
|
||||
~confio_t();
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @name Methods
|
||||
*/
|
||||
//@{
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @name Accessor(s) / mutator(s)
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* register a configuration variable with the configuration manager.
|
||||
* @param get_attr A function to get the attribute value
|
||||
* @param get_attr_data Void pointer, available to get_attr
|
||||
* @param set_attr A function to set the attribute value
|
||||
* @param set_attr_data Void pointer, available to set_attr
|
||||
* @return [Description of return value]
|
||||
*/
|
||||
int register_attribute( const char *name,
|
||||
get_confio_t get_attr, void *get_attr_data,
|
||||
set_confio_t set_attr, void *set_attr_data );
|
||||
|
||||
/**
|
||||
* Set verbosity of the configuration
|
||||
* @param verbose True causes more info to be printed out, False doesn't
|
||||
*/
|
||||
void setVerbosity( bool verbose ) {
|
||||
m_verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* write a configuration file: e.g. save state
|
||||
*/
|
||||
int writeConfiguration( const char *outputFilename );
|
||||
|
||||
/**
|
||||
* read state from an existing configuration file
|
||||
* @param inputFilename The file to read
|
||||
* @param relativeIncludePath The path to search on 'include' statements
|
||||
*/
|
||||
int readConfiguration( const char *inputFilename,
|
||||
const char *relativeIncludePath );
|
||||
|
||||
/**
|
||||
* read state from a string
|
||||
*/
|
||||
int readConfigurationString( const char *inputBuffer );
|
||||
|
||||
/**
|
||||
* check that each registered configuration is set (reports a warning if
|
||||
* they are not.)
|
||||
*/
|
||||
void checkInitialization( void );
|
||||
//@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Apply an attribute list to the configuration table
|
||||
*/
|
||||
int applyConfiguration( attr_value_t *attr );
|
||||
|
||||
/// configuration table: contains a map from a string -> conf node
|
||||
ConfTable m_table;
|
||||
|
||||
/// if false, nothing is printed under normal operation
|
||||
bool m_verbose;
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global variables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Allocates an array of attributes.
|
||||
*/
|
||||
attr_value_t *mallocAttribute( uint32 number );
|
||||
|
||||
/**
|
||||
* Walks an attribute tree, freeing all memory under attr. Does not free
|
||||
* attr itself.
|
||||
*/
|
||||
void freeAttribute( attr_value_t *attr );
|
||||
|
||||
#endif /* _CONFIO_H_ */
|
||||
|
||||
|
54
src/mem/gems_common/ioutil/embedtext.py
Normal file
54
src/mem/gems_common/ioutil/embedtext.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
|
||||
import sys
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class embedText:
|
||||
"""
|
||||
embedText converts a text file into a file that can be embedded in C
|
||||
using an #include statement, that defines a \"const char *\" pointing
|
||||
to the same text.
|
||||
|
||||
This is useful to embed scripts and configuration files in object files.
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.escape = [ "\'", "\"", "\\", "\?" ]
|
||||
|
||||
def write(self, outputfile, varname):
|
||||
# reads the text file in, line by line, converting it to a C string
|
||||
fin = open( self.filename, 'r' )
|
||||
fout= open( outputfile, 'w' )
|
||||
fout.write("static const char *%s =\n" % varname);
|
||||
l = " "
|
||||
while l != "":
|
||||
l = fin.readline()
|
||||
|
||||
# add escape sequences for the characters in escape
|
||||
fout.write("\"")
|
||||
for char in l:
|
||||
if char == "\n":
|
||||
break
|
||||
if char in self.escape:
|
||||
fout.write( "\\" )
|
||||
fout.write( char )
|
||||
else:
|
||||
fout.write( char )
|
||||
fout.write("\\n\"\n");
|
||||
fout.write(";\n");
|
||||
fin.close()
|
||||
fout.close()
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 4:
|
||||
print len(sys.argv)
|
||||
print "usage:", sys.argv[0], " input-file output-file varname"
|
||||
sys.exit(1)
|
||||
inputfile = sys.argv[1]
|
||||
outputfile = sys.argv[2]
|
||||
varname = sys.argv[3]
|
||||
print "generating embedded text file: %s from %s\n" % (outputfile, inputfile)
|
||||
inc = embedText( inputfile )
|
||||
inc.write( outputfile, varname )
|
626
src/mem/gems_common/ioutil/initvar.cc
Normal file
626
src/mem/gems_common/ioutil/initvar.cc
Normal file
|
@ -0,0 +1,626 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file has been modified by Kevin Moore and Dan Nussbaum of the
|
||||
Scalable Systems Research Group at Sun Microsystems Laboratories
|
||||
(http://research.sun.com/scalable/) to support the Adaptive
|
||||
Transactional Memory Test Platform (ATMTP).
|
||||
|
||||
Please send email to atmtp-interest@sun.com with feedback, questions, or
|
||||
to request future announcements about ATMTP.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
File modification date: 2008-02-23
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* FileName: initvar.C
|
||||
* Synopsis: implementation of global variable initialization in simics
|
||||
* Author: cmauer
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Maurice
|
||||
// extern "C" {
|
||||
// #include "global.hh"
|
||||
// #include "simics/api.hh"
|
||||
// #ifdef SIMICS22X
|
||||
// #include "configuration_api.hh"
|
||||
// #endif
|
||||
// #ifdef SIMICS30
|
||||
// #include "configuration.hh"
|
||||
// #endif
|
||||
// };
|
||||
|
||||
#include "FakeSimicsDataTypes.hh"
|
||||
|
||||
#ifdef IS_OPAL
|
||||
#include "hfatypes.hh"
|
||||
#include "debugio.hh"
|
||||
#endif
|
||||
|
||||
#ifdef IS_RUBY
|
||||
#include "Global.hh"
|
||||
#endif
|
||||
|
||||
#ifdef IS_TOURMALINE
|
||||
#include "Tourmaline_Global.hh"
|
||||
#endif
|
||||
|
||||
#include "confio.hh"
|
||||
#include "initvar.hh"
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Macro declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#define CONFIG_VAR_FILENAME "config.include"
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Variable declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// define global "constants" using centralized file
|
||||
#define PARAM( NAME ) \
|
||||
int32 NAME;
|
||||
#define PARAM_UINT( NAME ) \
|
||||
uint32 NAME;
|
||||
#define PARAM_ULONG( NAME ) \
|
||||
uint64 NAME;
|
||||
#define PARAM_BOOL( NAME ) \
|
||||
bool NAME;
|
||||
#define PARAM_DOUBLE( NAME ) \
|
||||
double NAME;
|
||||
#define PARAM_STRING( NAME ) \
|
||||
char *NAME;
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
PTYPE NAME[ARRAY_SIZE];
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
|
||||
/** global initvar object */
|
||||
initvar_t *initvar_t::m_inst = NULL;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Forward declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
static attr_value_t initvar_get_attr( void *ptr, void *obj );
|
||||
static set_error_t initvar_set_attr( void *ptr, void *obj,
|
||||
attr_value_t *value );
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Constructor(s) / destructor */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
initvar_t::initvar_t( const char *name, const char *relativeIncludePath,
|
||||
const char *initializingString,
|
||||
void (*allocate_fn)(void),
|
||||
void (*my_generate_fn)(void),
|
||||
get_attr_t my_get_attr, set_attr_t my_set_attr )
|
||||
{
|
||||
m_is_init = false;
|
||||
m_name = (char *) malloc( sizeof(char)*(strlen( name ) + 2) );
|
||||
m_rel_include_path = (char *) malloc( sizeof(char)*(strlen( relativeIncludePath ) + 2) );
|
||||
m_config_filename = NULL;
|
||||
strcpy( m_name, name );
|
||||
strcpy( m_rel_include_path, relativeIncludePath );
|
||||
m_allocate_f = allocate_fn;
|
||||
m_generate_values_f = my_generate_fn;
|
||||
m_my_get_attr = my_get_attr;
|
||||
m_my_set_attr = my_set_attr;
|
||||
|
||||
initvar_t::m_inst = this;
|
||||
init_config_reader( initializingString );
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
initvar_t::~initvar_t( )
|
||||
{
|
||||
#define PARAM( NAME )
|
||||
#define PARAM_UINT( NAME )
|
||||
#define PARAM_ULONG( NAME )
|
||||
#define PARAM_BOOL( NAME )
|
||||
#define PARAM_DOUBLE( NAME )
|
||||
#define PARAM_STRING( NAME ) \
|
||||
if (NAME != NULL) { \
|
||||
free( NAME ); \
|
||||
NAME = NULL; \
|
||||
}
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE )
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
if (m_name) {
|
||||
free( m_name );
|
||||
}
|
||||
if (m_rel_include_path) {
|
||||
free( m_rel_include_path );
|
||||
}
|
||||
if (m_config_reader) {
|
||||
delete m_config_reader;
|
||||
}
|
||||
if (m_config_filename) {
|
||||
delete m_config_filename;
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
void initvar_t::init_config_reader( const char *initString )
|
||||
{
|
||||
int rc;
|
||||
const char *name;
|
||||
|
||||
m_config_reader = new confio_t();
|
||||
m_config_reader->setVerbosity( false );
|
||||
|
||||
// Initialize the config reader object to identify each parameter
|
||||
#define PARAM_UINT PARAM
|
||||
#define PARAM_ULONG PARAM
|
||||
#define PARAM_BOOL PARAM
|
||||
#define PARAM_DOUBLE PARAM
|
||||
#define PARAM( NAME ) \
|
||||
name = #NAME; \
|
||||
rc = m_config_reader->register_attribute( name, \
|
||||
initvar_get_attr, (void *) name, \
|
||||
initvar_set_attr, (void *) name );
|
||||
#define PARAM_STRING( NAME ) \
|
||||
NAME = NULL; \
|
||||
name = #NAME; \
|
||||
rc = m_config_reader->register_attribute( name, \
|
||||
initvar_get_attr, (void *) name, \
|
||||
initvar_set_attr, (void *) name );
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
name = #NAME; \
|
||||
rc = m_config_reader->register_attribute( name, \
|
||||
initvar_get_attr, (void *) name, \
|
||||
initvar_set_attr, (void *) name );
|
||||
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
|
||||
// read the default configuration from the embedded text file
|
||||
rc = m_config_reader->readConfigurationString( initString );
|
||||
(*m_generate_values_f)();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Public methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
void initvar_t::allocate( void )
|
||||
{
|
||||
if ( confirm_init() ) {
|
||||
DEBUG_OUT("error: %s initvar::allocate() called twice\n", m_name);
|
||||
return;
|
||||
}
|
||||
|
||||
(*m_generate_values_f)();
|
||||
(*m_allocate_f)();
|
||||
m_is_init = true;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
void initvar_t::checkInitialization( void )
|
||||
{
|
||||
m_config_reader->checkInitialization();
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
attr_value_t initvar_t::dispatch_get( void *id, void *obj,
|
||||
attr_value_t *idx )
|
||||
{
|
||||
const char *command = (const char *) id;
|
||||
if ( !confirm_init() ) {
|
||||
DEBUG_OUT("error: %s is uninitialized. unable to get \'%s\'\n", m_name, command);
|
||||
DEBUG_OUT(" : you must initialize %s with a configuration file first.\n", m_name);
|
||||
DEBUG_OUT(" : use the command \'%s0.init\'\n", m_name);
|
||||
|
||||
attr_value_t ret;
|
||||
ret.kind = Sim_Val_Invalid;
|
||||
ret.u.integer = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ((*m_my_get_attr)(id, obj, idx));
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
set_error_t initvar_t::dispatch_set( void *id, void *obj,
|
||||
attr_value_t *val, attr_value_t *idx )
|
||||
{
|
||||
const char *command = (const char *) id;
|
||||
|
||||
// DEBUG_OUT("set attribute: %s\n", command);
|
||||
if (!strcmp(command, "init")) {
|
||||
if (val->kind == Sim_Val_String) {
|
||||
if (!strcmp( val->u.string, "" )) {
|
||||
// update generated values, then allocate
|
||||
allocate();
|
||||
} else {
|
||||
read_config( val->u.string );
|
||||
allocate();
|
||||
}
|
||||
return Sim_Set_Ok;
|
||||
} else {
|
||||
return Sim_Set_Need_String;
|
||||
}
|
||||
} else if (!strcmp(command, "readparam")) {
|
||||
if (val->kind == Sim_Val_String) {
|
||||
read_config( val->u.string );
|
||||
return Sim_Set_Ok;
|
||||
} else {
|
||||
return Sim_Set_Need_String;
|
||||
}
|
||||
} else if (!strcmp(command, "saveparam")) {
|
||||
if (val->kind == Sim_Val_String) {
|
||||
FILE *fp = fopen( val->u.string, "w" );
|
||||
if (fp == NULL) {
|
||||
ERROR_OUT("error: unable to open file: %s\n", val->u.string);
|
||||
return Sim_Set_Illegal_Value;
|
||||
}
|
||||
list_param( fp );
|
||||
if (fp != NULL) {
|
||||
fclose( fp );
|
||||
}
|
||||
return Sim_Set_Ok;
|
||||
} else {
|
||||
ERROR_OUT("error: saveparam given wrong type.\n");
|
||||
return Sim_Set_Illegal_Value;
|
||||
}
|
||||
} else if (!strcmp(command, "param")) {
|
||||
if (val->kind == Sim_Val_Integer) {
|
||||
list_param( stdout );
|
||||
return Sim_Set_Ok;
|
||||
} else if ( val->kind == Sim_Val_List &&
|
||||
val->u.list.size == 2 &&
|
||||
val->u.list.vector[0].kind == Sim_Val_String ) {
|
||||
return (set_param( val->u.list.vector[0].u.string,
|
||||
&val->u.list.vector[1] ));
|
||||
} else {
|
||||
DEBUG_OUT("error: set parameter given wrong type.\n");
|
||||
return Sim_Set_Illegal_Value;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !confirm_init() ) {
|
||||
DEBUG_OUT("error: %s is uninitialized. unable to set \'%s\'\n", m_name, id);
|
||||
DEBUG_OUT(" : you must initialize %s with a configuration file first.\n", m_name);
|
||||
DEBUG_OUT(" : use the command \'%s0.init\'\n", m_name);
|
||||
return Sim_Set_Illegal_Value;
|
||||
}
|
||||
|
||||
return (*m_my_set_attr)( id, obj, val, idx );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Accessor(s) / mutator(s) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Private methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Static methods */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
static attr_value_t initvar_get_attr( void *ptr, void *obj )
|
||||
{
|
||||
const char *name = (const char *) ptr;
|
||||
attr_value_t ret;
|
||||
memset( &ret, 0, sizeof(attr_value_t) );
|
||||
|
||||
#define PARAM_UINT PARAM
|
||||
#define PARAM_ULONG PARAM
|
||||
#define PARAM_BOOL PARAM
|
||||
#define PARAM( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
ret.kind = Sim_Val_Integer; \
|
||||
ret.u.integer = NAME; \
|
||||
return (ret); \
|
||||
}
|
||||
#define PARAM_DOUBLE( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
ret.kind = Sim_Val_Floating; \
|
||||
ret.u.floating = NAME; \
|
||||
return (ret); \
|
||||
}
|
||||
#define PARAM_STRING( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
ret.kind = Sim_Val_String; \
|
||||
ret.u.string = NAME; \
|
||||
return (ret); \
|
||||
}
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
ret.kind = Sim_Val_List; \
|
||||
ret.u.list.size = ARRAY_SIZE; \
|
||||
ret.u.list.vector = mallocAttribute( ARRAY_SIZE ); \
|
||||
for (int i = 0; i < ARRAY_SIZE; i++) { \
|
||||
ret.u.list.vector[i].u.integer = NAME[i]; \
|
||||
} \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
|
||||
DEBUG_OUT("error: %s not found.\n", name);
|
||||
ret.kind = Sim_Val_Invalid;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
static set_error_t initvar_set_attr( void *ptr, void *obj,
|
||||
attr_value_t *value )
|
||||
{
|
||||
const char *name = (const char *) ptr;
|
||||
|
||||
#define PARAM_UINT PARAM
|
||||
#define PARAM_ULONG PARAM
|
||||
#define PARAM( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
if ( value->kind != Sim_Val_Integer ) { \
|
||||
ERROR_OUT("error: %s is not an integer\n", name );\
|
||||
return Sim_Set_Need_Integer; \
|
||||
} \
|
||||
NAME = value->u.integer; \
|
||||
return Sim_Set_Ok; \
|
||||
}
|
||||
#define PARAM_BOOL( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
if ( value->kind != Sim_Val_String ) { \
|
||||
ERROR_OUT("error: %s is not an bool string\n", name );\
|
||||
return Sim_Set_Need_String; \
|
||||
} \
|
||||
if (!strcmp(value->u.string, "true")) { \
|
||||
NAME = true; \
|
||||
} else if (!strcmp(value->u.string, "false")) { \
|
||||
NAME = false; \
|
||||
} else { \
|
||||
ERROR_OUT("error: value %s for %s is not an bool string (set to false)\n", value->u.string, name );\
|
||||
NAME = false; \
|
||||
} \
|
||||
return Sim_Set_Ok; \
|
||||
}
|
||||
#define PARAM_DOUBLE( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
if ( value->kind != Sim_Val_String ) { \
|
||||
ERROR_OUT("error: %s is not a float\n", name );\
|
||||
return Sim_Set_Need_Floating; \
|
||||
} \
|
||||
NAME = atof( value->u.string ); \
|
||||
return Sim_Set_Ok; \
|
||||
}
|
||||
#define PARAM_STRING( NAME ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
if ( value->kind != Sim_Val_String ) { \
|
||||
ERROR_OUT("error: %s is not an string\n", name ); \
|
||||
return Sim_Set_Need_String; \
|
||||
} \
|
||||
if (NAME != NULL) { \
|
||||
free( NAME ); \
|
||||
} \
|
||||
NAME = strdup( value->u.string ); \
|
||||
return Sim_Set_Ok; \
|
||||
}
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
if (!strcmp(name, #NAME)) { \
|
||||
if ( value->kind != Sim_Val_List ) { \
|
||||
ERROR_OUT("error: %s is not an list\n", name ); \
|
||||
return Sim_Set_Need_List; \
|
||||
} \
|
||||
if ( value->u.list.size != ARRAY_SIZE ) { \
|
||||
ERROR_OUT("error: %s has %lld elements (should be %d)\n", name, value->u.list.size, ARRAY_SIZE); \
|
||||
return Sim_Set_Illegal_Value; \
|
||||
} \
|
||||
for (int i = 0; i < ARRAY_SIZE; i++) { \
|
||||
NAME[i] = value->u.list.vector[i].u.integer; \
|
||||
} \
|
||||
return Sim_Set_Ok; \
|
||||
}
|
||||
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
|
||||
ERROR_OUT("error: %s not a parameter\n", name);
|
||||
return Sim_Set_Illegal_Value;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
void initvar_t::read_config( const char *parameterFile )
|
||||
{
|
||||
DEBUG_OUT("read configuration: %s\n", parameterFile );
|
||||
m_config_filename = strdup( parameterFile );
|
||||
int rc = m_config_reader->readConfiguration( parameterFile,
|
||||
m_rel_include_path );
|
||||
if ( rc < 0 ) {
|
||||
ERROR_OUT("fatal error in read configuration: unable to continue.\n");
|
||||
exit(1);
|
||||
}
|
||||
// update generated values
|
||||
(*m_generate_values_f)();
|
||||
}
|
||||
|
||||
/** sets one of the parameters */
|
||||
//**************************************************************************
|
||||
set_error_t initvar_t::set_param( const char *name, attr_value_t *value )
|
||||
{
|
||||
|
||||
// [dann 2007-04-04] ATMTP VV
|
||||
//
|
||||
// HACK ALERT: allow setting REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH,
|
||||
// PROFILE_EXCEPTIONS, PROFILE_XACT, ATMTP_DEBUG_LEVEL and
|
||||
// ATMTP_ENABLED after initialization. This works is because ruby's
|
||||
// m_generate_values_f() does nothing -- more particularly, nothing
|
||||
// that depends on any of these parameters is pre-calculated
|
||||
// anywhere.
|
||||
//
|
||||
if (strcmp(name, "REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH") != 0 &&
|
||||
strcmp(name, "PROFILE_EXCEPTIONS") != 0 &&
|
||||
strcmp(name, "PROFILE_XACT") != 0 &&
|
||||
strcmp(name, "ATMTP_DEBUG_LEVEL") != 0 &&
|
||||
strcmp(name, "ATMTP_ENABLED") != 0) {
|
||||
//
|
||||
// [dann 2007-04-04] ATMTP ^^
|
||||
if ( confirm_init() ) {
|
||||
DEBUG_OUT("error: %s is already initialized.\n", m_name);
|
||||
DEBUG_OUT(" : setting parameters after initialization is unsupported\n");
|
||||
return (Sim_Set_Illegal_Value);
|
||||
}
|
||||
// [dann 2007-04-04] ATMTP VV
|
||||
//
|
||||
}
|
||||
//
|
||||
// [dann 2007-04-04] ATMTP ^^
|
||||
|
||||
set_error_t result = initvar_set_attr( (void *) name, NULL, value );
|
||||
(*m_generate_values_f)();
|
||||
return (result);
|
||||
}
|
||||
|
||||
/** print out a list of valid parameters */
|
||||
//**************************************************************************
|
||||
void initvar_t::list_param( FILE *fp )
|
||||
{
|
||||
if (!fp)
|
||||
fp = stdout;
|
||||
|
||||
#define PARAM( NAME ) \
|
||||
fprintf( fp, "%-44.44s: %26d\n", #NAME, NAME );
|
||||
#define PARAM_UINT( NAME ) \
|
||||
fprintf( fp, "%-44.44s: %26u\n", #NAME, NAME );
|
||||
#define PARAM_ULONG( NAME ) \
|
||||
fprintf( fp, "%-44.44s: %26llu\n", #NAME, NAME );
|
||||
#define PARAM_BOOL( NAME ) \
|
||||
if (NAME == true) { \
|
||||
fprintf( fp, "%-44.44s: %26.26s\n", #NAME, "true" ); \
|
||||
} else { \
|
||||
fprintf( fp, "%-44.44s: %26.26s\n", #NAME, "false" );\
|
||||
}
|
||||
#define PARAM_DOUBLE( NAME ) \
|
||||
fprintf( fp, "%-44.44s: %26f\n", #NAME, NAME );
|
||||
#define PARAM_STRING( NAME ) \
|
||||
if ( NAME != NULL ) { \
|
||||
fprintf( fp, "%-44.44s: %26.26s\n", #NAME, NAME ); \
|
||||
}
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
fprintf( fp, "%-44.44s: (", #NAME ); \
|
||||
for (int i = 0; i < ARRAY_SIZE; i++) { \
|
||||
if ( i != 0 ) { \
|
||||
fprintf( fp, ", " ); \
|
||||
} \
|
||||
fprintf( fp, "%d", NAME[i] ); \
|
||||
} \
|
||||
fprintf( fp, ")\n" );
|
||||
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
const char *initvar_t::get_config_name( void )
|
||||
{
|
||||
if (m_config_filename == NULL) {
|
||||
return "default";
|
||||
}
|
||||
return m_config_filename;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
//**************************************************************************
|
||||
attr_value_t initvar_dispatch_get( void *id, void *obj,
|
||||
attr_value_t *idx )
|
||||
{
|
||||
initvar_t *init_obj = initvar_t::m_inst;
|
||||
return (init_obj->dispatch_get( id, obj, idx ));
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
set_error_t initvar_dispatch_set( void *id, void *obj,
|
||||
attr_value_t *val, attr_value_t *idx )
|
||||
{
|
||||
initvar_t *init_obj = initvar_t::m_inst;
|
||||
return (init_obj->dispatch_set( id, obj, val, idx ));
|
||||
}
|
181
src/mem/gems_common/ioutil/initvar.hh
Normal file
181
src/mem/gems_common/ioutil/initvar.hh
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_H_
|
||||
#define _INCLUDE_H_
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Macro declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Class declaration(s) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* This class deals with initializing the global variables in the object,
|
||||
* setting the varibles (from the command line), printing the configuration,
|
||||
* and saving it to a file.
|
||||
*
|
||||
* Before including this file, you must define the variable CONFIG_VAR_FILENAME
|
||||
* to define which variables are to be used.
|
||||
*
|
||||
* @see confio_t
|
||||
* @author cmauer
|
||||
* @version $Id$
|
||||
*/
|
||||
class initvar_t {
|
||||
public:
|
||||
/**
|
||||
* @name Constructor(s) / destructor
|
||||
*/
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Constructor: creates object
|
||||
* @param name The name of this object
|
||||
* @param relativeIncludePath The relative path to config files
|
||||
* @param initializingString A string (with value pairs) for initialization
|
||||
* @param allocate_f A ptr to the allocate function
|
||||
* @param generate_values A ptr to the generate values function
|
||||
* @param my_get_attr A ptr to the get attribute function
|
||||
* @param my_set_attr A ptr to the set attribute function
|
||||
*/
|
||||
initvar_t( const char *name, const char *relativeIncludePath,
|
||||
const char *initializingString,
|
||||
void (*allocate_fn)(void),
|
||||
void (*my_generate_fn)(void),
|
||||
get_attr_t my_get_attr, set_attr_t my_set_attr );
|
||||
|
||||
/**
|
||||
* Destructor: frees object.
|
||||
*/
|
||||
~initvar_t();
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @name Methods
|
||||
*/
|
||||
//@{
|
||||
/// calls the allocation routine explicitly (used by the tester)
|
||||
void allocate( void );
|
||||
|
||||
/// checks to see if all vars have been initialized
|
||||
void checkInitialization( void );
|
||||
|
||||
/// list all parameters: to a file (or stdout if file is NULL)
|
||||
void list_param( FILE *fp );
|
||||
|
||||
/// returns the name of the last config file to be read ("default" is none)
|
||||
const char *get_config_name( void );
|
||||
|
||||
/// calls through to the get_attr function, if object is initialized
|
||||
attr_value_t dispatch_get( void *id, void *obj,
|
||||
attr_value_t *idx );
|
||||
|
||||
/** adds initialization attributes, calls through to the set_attr function,
|
||||
* if object is initialized.
|
||||
*/
|
||||
set_error_t dispatch_set( void *id, void *obj,
|
||||
attr_value_t *val, attr_value_t *idx );
|
||||
//@}
|
||||
/// (single) instance of the init var object
|
||||
static initvar_t *m_inst;
|
||||
|
||||
protected:
|
||||
///returns true if the variables are initialized
|
||||
bool confirm_init( void ) {
|
||||
return m_is_init;
|
||||
}
|
||||
|
||||
///read a configuration file
|
||||
void read_config( const char *parameterFile );
|
||||
|
||||
/// set a parameter to be a particular value
|
||||
set_error_t set_param( const char *name, attr_value_t *value );
|
||||
|
||||
/// initializes the configuration reader
|
||||
void init_config_reader( const char *initString );
|
||||
|
||||
/// bool value (true if initialized)
|
||||
bool m_is_init;
|
||||
|
||||
/// configuration reader
|
||||
confio_t *m_config_reader;
|
||||
|
||||
/// a pointer to a string (corresponding to this objects name)
|
||||
char *m_name;
|
||||
|
||||
/// a pointer to a string (representing the last config file read)
|
||||
char *m_config_filename;
|
||||
|
||||
/// the relative include path to the configuration files
|
||||
char *m_rel_include_path;
|
||||
|
||||
/// a pointer to the allocation function
|
||||
void (*m_allocate_f)(void);
|
||||
|
||||
/// a pointer to the generate values function
|
||||
void (*m_generate_values_f)(void);
|
||||
|
||||
/// a pointer to the session get function
|
||||
get_attr_t m_my_get_attr;
|
||||
/// a pointer to the session set function
|
||||
set_attr_t m_my_set_attr;
|
||||
};
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global variables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///provides a dispatch mechanism that catches a few commands to get variables
|
||||
attr_value_t initvar_dispatch_get( void *id, void *obj,
|
||||
attr_value_t *idx );
|
||||
|
||||
///provides a dispatch mechanism that catches a few commands to set variables
|
||||
set_error_t initvar_dispatch_set( void *id, void *obj,
|
||||
attr_value_t *val, attr_value_t *idx );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_H_ */
|
75
src/mem/gems_common/ioutil/vardecl.hh
Normal file
75
src/mem/gems_common/ioutil/vardecl.hh
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _VARDECL_H_
|
||||
#define _VARDECL_H_
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Includes */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Macro declarations */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Class declaration(s) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global variables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#define PARAM( NAME ) \
|
||||
extern int32 NAME;
|
||||
#define PARAM_UINT( NAME ) \
|
||||
extern uint32 NAME;
|
||||
#define PARAM_ULONG( NAME ) \
|
||||
extern uint64 NAME;
|
||||
#define PARAM_BOOL( NAME ) \
|
||||
extern bool NAME;
|
||||
#define PARAM_DOUBLE( NAME ) \
|
||||
extern double NAME;
|
||||
#define PARAM_STRING( NAME ) \
|
||||
extern char *NAME;
|
||||
#define PARAM_ARRAY( PTYPE, NAME, ARRAY_SIZE ) \
|
||||
extern PTYPE NAME[ARRAY_SIZE];
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Global functions */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* _VARDECL_H_ */
|
51
src/mem/gems_common/std-includes.hh
Normal file
51
src/mem/gems_common/std-includes.hh
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <ext/hash_map>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace std;
|
||||
using namespace __gnu_cxx;
|
||||
|
||||
#endif //INCLUDES_H
|
109
src/mem/gems_common/util.cc
Normal file
109
src/mem/gems_common/util.cc
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "util.hh"
|
||||
|
||||
// Split a string into a head and tail strings on the specified
|
||||
// character. Return the head and the string passed in is modified by
|
||||
// removing the head, leaving just the tail.
|
||||
|
||||
string string_split(string& str, char split_character)
|
||||
{
|
||||
string head = "";
|
||||
string tail = "";
|
||||
|
||||
uint counter = 0;
|
||||
while(counter < str.size()) {
|
||||
if (str[counter] == split_character) {
|
||||
counter++;
|
||||
break;
|
||||
} else {
|
||||
head += str[counter];
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
while(counter < str.size()) {
|
||||
tail += str[counter];
|
||||
counter++;
|
||||
}
|
||||
str = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
string bool_to_string(bool value)
|
||||
{
|
||||
if (value) {
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
string int_to_string(int n, bool zero_fill, int width)
|
||||
{
|
||||
ostringstream sstr;
|
||||
if(zero_fill) {
|
||||
sstr << setw(width) << setfill('0') << n;
|
||||
} else {
|
||||
sstr << n;
|
||||
}
|
||||
string str = sstr.str();
|
||||
return str;
|
||||
}
|
||||
|
||||
float string_to_float(string& str)
|
||||
{
|
||||
stringstream sstr(str);
|
||||
float ret;
|
||||
sstr >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Log functions
|
||||
int log_int(long long n)
|
||||
{
|
||||
assert(n > 0);
|
||||
int counter = 0;
|
||||
while (n >= 2) {
|
||||
counter++;
|
||||
n = n>>(long long)(1);
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
bool is_power_of_2(long long n)
|
||||
{
|
||||
return (n == ((long long)(1) << log_int(n)));
|
||||
}
|
||||
|
68
src/mem/gems_common/util.hh
Normal file
68
src/mem/gems_common/util.hh
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include "std-includes.hh"
|
||||
|
||||
string string_split(string& str, char split_character);
|
||||
string bool_to_string(bool value);
|
||||
string int_to_string(int n, bool zero_fill = false, int width = 0);
|
||||
float string_to_float(string& str);
|
||||
int log_int(long long n);
|
||||
bool is_power_of_2(long long n);
|
||||
|
||||
// Min and Max functions (since they are extern inline, they are as
|
||||
// fast as macros)
|
||||
|
||||
extern inline
|
||||
int max(int n1, int n2)
|
||||
{
|
||||
if (n1 > n2) {
|
||||
return n1;
|
||||
} else {
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
|
||||
extern inline
|
||||
int min(int n1, int n2)
|
||||
{
|
||||
if (n1 < n2) {
|
||||
return n1;
|
||||
} else {
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //UTIL_H
|
83
src/mem/protocol/LogTM.sm
Normal file
83
src/mem/protocol/LogTM.sm
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file has been modified by Kevin Moore and Dan Nussbaum of the
|
||||
Scalable Systems Research Group at Sun Microsystems Laboratories
|
||||
(http://research.sun.com/scalable/) to support the Adaptive
|
||||
Transactional Memory Test Platform (ATMTP).
|
||||
|
||||
Please send email to atmtp-interest@sun.com with feedback, questions, or
|
||||
to request future announcements about ATMTP.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
File modification date: 2008-02-23
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
external_type(PartialAddressFilter, desc="Bloom filter for tracking transaction locks."){
|
||||
bool isRead(Address);
|
||||
bool isWrite(Address);
|
||||
|
||||
void addEntry(Address, bool);
|
||||
void clear();
|
||||
}
|
||||
|
||||
external_type(TransactionInterfaceManager) {
|
||||
bool shouldNackLoad(Address, uint64, MachineID);
|
||||
bool shouldNackStore(Address, uint64, MachineID);
|
||||
bool checkReadWriteSignatures(Address);
|
||||
bool checkWriteSignatures(Address);
|
||||
|
||||
void notifySendNack(Address, uint64, MachineID);
|
||||
void notifyReceiveNack(int, Address, uint64, uint64, MachineID);
|
||||
void notifyReceiveNackFinal(int, Address);
|
||||
|
||||
uint64 getTimestamp(int);
|
||||
uint64 getOldestTimestamp();
|
||||
|
||||
bool existGlobalLoadConflict(int, Address);
|
||||
bool existGlobalStoreConflict(int, Address);
|
||||
|
||||
void profileTransactionMiss(int, bool);
|
||||
|
||||
void xactReplacement(Address);
|
||||
|
||||
/* DEPRECATED */
|
||||
bool existLoadConflict(Address);
|
||||
bool existStoreConflict(Address);
|
||||
bool isInReadFilterSummary(Address);
|
||||
bool isInWriteFilterSummary(Address);
|
||||
bool isTokenOwner(int);
|
||||
void setAbortFlag(int, Address);
|
||||
void setEnemyProcessor(int, MachineID);
|
||||
bool isRemoteOlder(uint64);
|
||||
|
||||
}
|
867
src/mem/protocol/MESI_CMP_directory-L1cache.sm
Normal file
867
src/mem/protocol/MESI_CMP_directory-L1cache.sm
Normal file
|
@ -0,0 +1,867 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MSI_MOSI_CMP_directory-L1cache.sm 1.10 05/01/19 15:55:40-06:00 beckmann@s0-28.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
||||
|
||||
// NODE L1 CACHE
|
||||
// From this node's L1 cache TO the network
|
||||
// a local L1 -> this L2 bank, currently ordered with directory forwarded requests
|
||||
MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false";
|
||||
// a local L1 -> this L2 bank
|
||||
MessageBuffer responseFromL1Cache, network="To", virtual_network="3", ordered="false";
|
||||
MessageBuffer unblockFromL1Cache, network="To", virtual_network="4", ordered="false";
|
||||
|
||||
|
||||
// To this node's L1 cache FROM the network
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer requestToL1Cache, network="From", virtual_network="1", ordered="false";
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer responseToL1Cache, network="From", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||||
// Base states
|
||||
NP, desc="Not present in either cache";
|
||||
I, desc="a L1 cache entry Idle";
|
||||
S, desc="a L1 cache entry Shared";
|
||||
E, desc="a L1 cache entry Exclusive";
|
||||
M, desc="a L1 cache entry Modified", format="!b";
|
||||
|
||||
// Transient States
|
||||
IS, desc="L1 idle, issued GETS, have not seen response yet";
|
||||
IM, desc="L1 idle, issued GETX, have not seen response yet";
|
||||
SM, desc="L1 idle, issued GETX, have not seen response yet";
|
||||
IS_I, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
|
||||
|
||||
M_I, desc="L1 replacing, waiting for ACK";
|
||||
E_I, desc="L1 replacing, waiting for ACK";
|
||||
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
// L1 events
|
||||
Load, desc="Load request from the home processor";
|
||||
Ifetch, desc="I-fetch request from the home processor";
|
||||
Store, desc="Store request from the home processor";
|
||||
|
||||
Inv, desc="Invalidate request from L2 bank";
|
||||
|
||||
// internal generated request
|
||||
L1_Replacement, desc="L1 Replacement", format="!r";
|
||||
|
||||
// other requests
|
||||
Fwd_GETX, desc="GETX from other processor";
|
||||
Fwd_GETS, desc="GETS from other processor";
|
||||
Fwd_GET_INSTR, desc="GET_INSTR from other processor";
|
||||
|
||||
Data, desc="Data for processor";
|
||||
Data_Exclusive, desc="Data for processor";
|
||||
DataS_fromL1, desc="data for GETS request, need to unblock directory";
|
||||
Data_all_Acks, desc="Data for processor, all acks";
|
||||
|
||||
Ack, desc="Ack for processor";
|
||||
Ack_all, desc="Last ack for processor";
|
||||
|
||||
WB_Ack, desc="Ack for replacement";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
|
||||
State CacheState, desc="cache state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
bool Dirty, default="false", desc="data is dirty";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
Address Address, desc="Physical address for this TBE";
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="Buffer for the data block";
|
||||
bool Dirty, default="false", desc="data is dirty";
|
||||
bool isPrefetch, desc="Set if this was caused by a prefetch";
|
||||
int pendingAcks, default="0", desc="number of pending acks";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
|
||||
|
||||
CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
|
||||
CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
|
||||
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
int cache_state_to_int(State state);
|
||||
|
||||
// inclusive cache returns L1 entries only
|
||||
Entry getL1CacheEntry(Address addr), return_by_ref="yes" {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory[addr];
|
||||
} else {
|
||||
return L1IcacheMemory[addr];
|
||||
}
|
||||
}
|
||||
|
||||
void changeL1Permission(Address addr, AccessPermission permission) {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory.changePermission(addr, permission);
|
||||
} else if(L1IcacheMemory.isTagPresent(addr)) {
|
||||
return L1IcacheMemory.changePermission(addr, permission);
|
||||
} else {
|
||||
error("cannot change permission, L1 block not present");
|
||||
}
|
||||
}
|
||||
|
||||
bool isL1CacheTagPresent(Address addr) {
|
||||
return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
|
||||
}
|
||||
|
||||
State getState(Address addr) {
|
||||
if((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == true){
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(addr);
|
||||
}
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
return L1_TBEs[addr].TBEState;
|
||||
} else if (isL1CacheTagPresent(addr)) {
|
||||
return getL1CacheEntry(addr).CacheState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
// MUST CHANGE
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
L1_TBEs[addr].TBEState := state;
|
||||
}
|
||||
|
||||
if (isL1CacheTagPresent(addr)) {
|
||||
getL1CacheEntry(addr).CacheState := state;
|
||||
|
||||
// Set permission
|
||||
if (state == State:I) {
|
||||
changeL1Permission(addr, AccessPermission:Invalid);
|
||||
} else if (state == State:S || state == State:E) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Only);
|
||||
} else if (state == State:M) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
changeL1Permission(addr, AccessPermission:Busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event mandatory_request_type_to_event(CacheRequestType type) {
|
||||
if (type == CacheRequestType:LD) {
|
||||
return Event:Load;
|
||||
} else if (type == CacheRequestType:IFETCH) {
|
||||
return Event:Ifetch;
|
||||
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
|
||||
return Event:Store;
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache);
|
||||
out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache);
|
||||
out_port(unblockNetwork_out, ResponseMsg, unblockFromL1Cache);
|
||||
|
||||
// Response IntraChip L1 Network - response msg to this L1 cache
|
||||
in_port(responseIntraChipL1Network_in, ResponseMsg, responseToL1Cache) {
|
||||
if (responseIntraChipL1Network_in.isReady()) {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
|
||||
trigger(Event:Data_Exclusive, in_msg.Address);
|
||||
} else if(in_msg.Type == CoherenceResponseType:DATA) {
|
||||
if ( (getState(in_msg.Address) == State:IS || getState(in_msg.Address) == State:IS_I) &&
|
||||
machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache ) {
|
||||
|
||||
trigger(Event:DataS_fromL1, in_msg.Address);
|
||||
|
||||
} else if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) {
|
||||
trigger(Event:Data_all_Acks, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:ACK) {
|
||||
if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) {
|
||||
trigger(Event:Ack_all, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Ack, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
|
||||
trigger(Event:WB_Ack, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid L1 response type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request InterChip network - request from this L1 cache to the shared L2
|
||||
in_port(requestIntraChipL1Network_in, RequestMsg, requestToL1Cache) {
|
||||
if(requestIntraChipL1Network_in.isReady()) {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:Inv, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:UPGRADE) {
|
||||
// upgrade transforms to GETX due to race
|
||||
trigger(Event:Fwd_GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fwd_GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
trigger(Event:Fwd_GET_INSTR, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid forwarded request type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue betweens Node's CPU and it's L1 caches
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
// Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
|
||||
|
||||
if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
// ** INSTRUCTION ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
}
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 asks the L2 for it.
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// *** DATA ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
}
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 ask the L2 for it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
action(a_issueGETS, "a", desc="Issue GETS") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(ai_issueGETINSTR, "ai", desc="Issue GETINSTR") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GET_INSTR;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(b_issueGETX, "b", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.Requestor := machineID;
|
||||
DEBUG_EXPR(machineID);
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_issueUPGRADE, "c", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:UPGRADE;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendDataToRequestor, "d", desc="send data to requestor") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
out_msg.AckCount := 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(g_issuePUTX, "g", desc="send data to the L2 cache") {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Requestor:= machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
if (getL1CacheEntry(address).Dirty) {
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
} else {
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(getL1CacheEntry(address).DataBlk);
|
||||
sequencer.readCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
}
|
||||
|
||||
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(getL1CacheEntry(address).DataBlk);
|
||||
sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
getL1CacheEntry(address).Dirty := true;
|
||||
}
|
||||
|
||||
action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
|
||||
check_allocate(L1_TBEs);
|
||||
L1_TBEs.allocate(address);
|
||||
L1_TBEs[address].isPrefetch := false;
|
||||
L1_TBEs[address].Dirty := getL1CacheEntry(address).Dirty;
|
||||
L1_TBEs[address].DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popRequestQueue, "l", desc="Pop incoming request queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(2, requestIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(3, responseIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||||
L1_TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(u_writeDataToL1Cache, "u", desc="Write data to cache") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
getL1CacheEntry(address).DataBlk := in_msg.DataBlk;
|
||||
getL1CacheEntry(address).Dirty := in_msg.Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
action(q_updateAckCount, "q", desc="Update ack count") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
L1_TBEs[address].pendingAcks := L1_TBEs[address].pendingAcks - in_msg.AckCount;
|
||||
APPEND_TRANSITION_COMMENT(in_msg.AckCount);
|
||||
APPEND_TRANSITION_COMMENT(" p: ");
|
||||
APPEND_TRANSITION_COMMENT(L1_TBEs[address].pendingAcks);
|
||||
}
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="Stall") {
|
||||
}
|
||||
|
||||
action(ff_deallocateL1CacheBlock, "\f", desc="Deallocate L1 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L1DcacheMemory.deallocate(address);
|
||||
} else {
|
||||
L1IcacheMemory.deallocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") {
|
||||
if (L1DcacheMemory.isTagPresent(address) == false) {
|
||||
L1DcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
|
||||
if (L1IcacheMemory.isTagPresent(address) == false) {
|
||||
L1IcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(zz_recycleRequestQueue, "zz", desc="recycle L1 request queue") {
|
||||
requestIntraChipL1Network_in.recycle();
|
||||
}
|
||||
|
||||
action(z_recycleMandatoryQueue, "\z", desc="recycle L1 request queue") {
|
||||
mandatoryQueue_in.recycle();
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************
|
||||
// TRANSITIONS
|
||||
//*****************************************************
|
||||
|
||||
// Transitions for Load/Store/Replacement/WriteBack from transient states
|
||||
transition({IS, IM, IS_I, M_I, E_I, SM}, {Load, Ifetch, Store, L1_Replacement}) {
|
||||
z_recycleMandatoryQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP,I}, L1_Replacement) {
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition({NP,I}, Load, IS) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,I}, Ifetch, IS) {
|
||||
pp_allocateL1ICacheBlock;
|
||||
i_allocateTBE;
|
||||
ai_issueGETINSTR;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,I}, Store, IM) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Inv) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition(S, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Store, SM) {
|
||||
i_allocateTBE;
|
||||
c_issueUPGRADE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, L1_Replacement, I) {
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(S, Inv, I) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Exclusive
|
||||
|
||||
transition(E, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(E, Store, M) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(E, L1_Replacement, M_I) {
|
||||
// silent E replacement??
|
||||
i_allocateTBE;
|
||||
g_issuePUTX; // send data, but hold in case forwarded request
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(E, Inv, I) {
|
||||
// don't send data
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(E, Fwd_GETX, I) {
|
||||
d_sendDataToRequestor;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(E, {Fwd_GETS, Fwd_GET_INSTR}, S) {
|
||||
d_sendDataToRequestor;
|
||||
d2_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, L1_Replacement, M_I) {
|
||||
i_allocateTBE;
|
||||
g_issuePUTX; // send data, but hold in case forwarded request
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(M_I, WB_Ack, I) {
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(M, Inv, I) {
|
||||
f_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, Inv, I) {
|
||||
ft_sendDataToL2_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, Fwd_GETX, I) {
|
||||
d_sendDataToRequestor;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, {Fwd_GETS, Fwd_GET_INSTR}, S) {
|
||||
d_sendDataToRequestor;
|
||||
d2_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, Fwd_GETX, I) {
|
||||
dt_sendDataToRequestor_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, {Fwd_GETS, Fwd_GET_INSTR}, I) {
|
||||
dt_sendDataToRequestor_fromTBE;
|
||||
d2t_sendDataToL2_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from IS
|
||||
transition({IS, IS_I}, Inv, IS_I) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data_all_Acks, S) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS_I, Data_all_Acks, I) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(IS, DataS_fromL1, S) {
|
||||
u_writeDataToL1Cache;
|
||||
j_sendUnblock;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS_I, DataS_fromL1, I) {
|
||||
u_writeDataToL1Cache;
|
||||
j_sendUnblock;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// directory is blocked when sending exclusive data
|
||||
transition(IS_I, Data_Exclusive, E) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data_Exclusive, E) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM
|
||||
transition({IM, SM}, Inv, IM) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data, SM) {
|
||||
u_writeDataToL1Cache;
|
||||
q_updateAckCount;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data_all_Acks, M) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from SM
|
||||
transition({SM, IM}, Ack) {
|
||||
q_updateAckCount;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(SM, Ack_all, M) {
|
||||
jj_sendExclusiveUnblock;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
1036
src/mem/protocol/MESI_CMP_directory-L2cache.sm
Normal file
1036
src/mem/protocol/MESI_CMP_directory-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
166
src/mem/protocol/MESI_CMP_directory-mem.sm
Normal file
166
src/mem/protocol/MESI_CMP_directory-mem.sm
Normal file
|
@ -0,0 +1,166 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
|
||||
machine(Directory, "Token protocol") {
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A GETX arrives";
|
||||
Data, desc="A GETS arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
action(a_sendAck, "a", desc="Send ack to L2") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Sender);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
d_sendData;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
a_sendAck;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
112
src/mem/protocol/MESI_CMP_directory-msg.sm
Normal file
112
src/mem/protocol/MESI_CMP_directory-msg.sm
Normal file
|
@ -0,0 +1,112 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MSI_MOSI_CMP_directory-msg.sm 1.5 05/01/19 15:48:37-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
UPGRADE, desc="UPGRADE to exclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
INV, desc="INValidate";
|
||||
PUTX, desc="replacement message";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
MEMORY_ACK, desc="Ack from memory controller";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE, desc="Data";
|
||||
MEMORY_DATA, desc="Data";
|
||||
ACK, desc="Generic invalidate ack";
|
||||
WB_ACK, desc="writeback ack";
|
||||
UNBLOCK, desc="unblock";
|
||||
EXCLUSIVE_UNBLOCK, desc="exclusive unblock";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
MachineID Requestor , desc="What component request";
|
||||
NetDest Destination, desc="What components receive the request, includes MachineType and num";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
DataBlock DataBlk, desc="Data for the cache line (if PUTX)";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="Data for the cache line";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
int AckCount, default="0", desc="number of acks in this message";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
/*
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:UPGRADE) {
|
||||
return GenericRequestType:UPGRADE;
|
||||
} else if(type == CoherenceRequestType:PUTS) {
|
||||
return GenericRequestType:PUTS;
|
||||
} else if(type == CoherenceRequestType:INV) {
|
||||
return GenericRequestType:INV;
|
||||
} else if(type == CoherenceRequestType:INV_S) {
|
||||
return GenericRequestType:INV_S;
|
||||
} else if(type == CoherenceRequestType:L1_DG) {
|
||||
return GenericRequestType:DOWNGRADE;
|
||||
} else if(type == CoherenceRequestType:WB_ACK) {
|
||||
return GenericRequestType:WB_ACK;
|
||||
} else if(type == CoherenceRequestType:EXE_ACK) {
|
||||
return GenericRequestType:EXE_ACK;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
5
src/mem/protocol/MESI_CMP_directory.slicc
Normal file
5
src/mem/protocol/MESI_CMP_directory.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MESI_CMP_directory-msg.sm
|
||||
MESI_CMP_directory-L2cache.sm
|
||||
MESI_CMP_directory-L1cache.sm
|
||||
MESI_CMP_directory-mem.sm
|
||||
standard_CMP-protocol.sm
|
1800
src/mem/protocol/MESI_CMP_filter_directory-L1cache.sm
Normal file
1800
src/mem/protocol/MESI_CMP_filter_directory-L1cache.sm
Normal file
File diff suppressed because it is too large
Load diff
2123
src/mem/protocol/MESI_CMP_filter_directory-L2cache.sm
Normal file
2123
src/mem/protocol/MESI_CMP_filter_directory-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
166
src/mem/protocol/MESI_CMP_filter_directory-mem.sm
Normal file
166
src/mem/protocol/MESI_CMP_filter_directory-mem.sm
Normal file
|
@ -0,0 +1,166 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
|
||||
machine(Directory, "Token protocol") {
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A GETX arrives";
|
||||
Data, desc="A GETS arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
action(a_sendAck, "a", desc="Send ack to L2") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Sender);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
d_sendData;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
a_sendAck;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
153
src/mem/protocol/MESI_CMP_filter_directory-msg.sm
Normal file
153
src/mem/protocol/MESI_CMP_filter_directory-msg.sm
Normal file
|
@ -0,0 +1,153 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MSI_MOSI_CMP_directory-msg.sm 1.5 05/01/19 15:48:37-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETX_ESCAPE, desc="Get eXclusive, while in escape action";
|
||||
UPGRADE, desc="UPGRADE to exclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GETS_ESCAPE, desc="Get Shared, while in escape action";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
GET_INSTR_ESCAPE, desc="Get Instruction, while in escape action";
|
||||
INV, desc="INValidate, could be NACKed";
|
||||
INV_ESCAPE, desc="INValidate, cannot be NACKed";
|
||||
PUTX, desc="replacement message, for writeback to lower caches";
|
||||
PUTS, desc="clean replacement message, for writeback to lower caches";
|
||||
REPLACE, desc="replacement message, from lowest cache";
|
||||
CHECK_WRITE_FILTER, desc="check write filter message";
|
||||
CHECK_READ_WRITE_FILTER, desc="check both read and write filters message";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
MEMORY_ACK, desc="Ack from memory controller";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE, desc="Data";
|
||||
L2_DATA, desc="data from L2, in shared mode";
|
||||
L2_DATA_EXCLUSIVE, desc="data from L2, in exclusive mode";
|
||||
MEMORY_DATA, desc="Data";
|
||||
ACK, desc="Generic invalidate ack";
|
||||
NACK, desc="NACK used to maintain transactional isolation";
|
||||
WB_ACK, desc="writeback ack";
|
||||
UNBLOCK, desc="unblock";
|
||||
EXCLUSIVE_UNBLOCK, desc="exclusive unblock";
|
||||
UNBLOCK_CANCEL, desc="unblock when trans. request fails";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Line address for this request";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
MachineID Requestor , desc="What component request";
|
||||
NetDest Destination, desc="What components receive the request, includes MachineType and num";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
DataBlock DataBlk, desc="Data for the cache line (if PUTX)";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
uint64 Timestamp, desc="TLR-like Timestamp";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Line address for this request";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="Data for the cache line";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
int AckCount, default="0", desc="number of acks in this message";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
uint64 Timestamp, desc="TLR-like Timestamp";
|
||||
NetDest Nackers, desc="The nodes which sent NACKs to requestor";
|
||||
bool Transactional, desc="Whether this address was transactional";
|
||||
bool RemoveLastOwnerFromDir, desc="To solve some races with PUTX/GETS";
|
||||
MachineID LastOwnerID, desc="What component sent the data";
|
||||
}
|
||||
|
||||
// TriggerType
|
||||
enumeration(TriggerType, desc="...") {
|
||||
ALL_ACKS, desc="When all acks/nacks have been received";
|
||||
}
|
||||
|
||||
// TriggerMsg
|
||||
structure(TriggerMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Line address for this request";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
TriggerType Type, desc="Type of trigger";
|
||||
}
|
||||
|
||||
/*
|
||||
GETX, desc="Get eXclusive";
|
||||
UPGRADE, desc="UPGRADE to exclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
INV, desc="INValidate";
|
||||
PUTX, desc="replacement message, for writeback to lower caches";
|
||||
REPLACE, desc="replacement message, from lowest cache";
|
||||
CHECK_WRITE_FILTER, desc="check write filter message";
|
||||
CHECK_READ_WRITE_FILTER, desc="check both read and write filters message";
|
||||
*/
|
||||
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GETS_ESCAPE) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR_ESCAPE) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:GETX_ESCAPE) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:UPGRADE) {
|
||||
return GenericRequestType:UPGRADE;
|
||||
} else if(type == CoherenceRequestType:INV) {
|
||||
return GenericRequestType:INV;
|
||||
} else if( type == CoherenceRequestType:REPLACE) {
|
||||
return GenericRequestType:REPLACEMENT;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/mem/protocol/MESI_CMP_filter_directory.slicc
Normal file
7
src/mem/protocol/MESI_CMP_filter_directory.slicc
Normal file
|
@ -0,0 +1,7 @@
|
|||
../protocols/LogTM.sm
|
||||
../protocols/MESI_CMP_filter_directory-msg.sm
|
||||
../protocols/MESI_CMP_filter_directory-L2cache.sm
|
||||
../protocols/MESI_CMP_filter_directory-L1cache.sm
|
||||
../protocols/MESI_CMP_filter_directory-mem.sm
|
||||
../protocols/standard_CMP-protocol.sm
|
||||
|
250
src/mem/protocol/MESI_CMP_filter_directory_m-mem.sm
Normal file
250
src/mem/protocol/MESI_CMP_filter_directory_m-mem.sm
Normal file
|
@ -0,0 +1,250 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
// This file is copied from Yasuko Watanabe's prefetch / memory protocol
|
||||
// Copied here by aep 12/14/07
|
||||
|
||||
|
||||
machine(Directory, "MESI_CMP_filter_directory protocol") {
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A memory fetch arrives";
|
||||
Data, desc="writeback data arrives";
|
||||
Memory_Data, desc="Fetched data from memory arrives";
|
||||
Memory_Ack, desc="Writeback Ack from memory arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// to simulate detailed DRAM
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
MemoryControl memBuffer, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
}
|
||||
|
||||
bool isGETRequest(CoherenceRequestType type) {
|
||||
return (type == CoherenceRequestType:GETS) ||
|
||||
(type == CoherenceRequestType:GET_INSTR) ||
|
||||
(type == CoherenceRequestType:GETX);
|
||||
}
|
||||
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(memQueue_out, MemoryMsg, memBuffer);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (isGETRequest(in_msg.Type)) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// off-chip memory request/response is done
|
||||
in_port(memQueue_in, MemoryMsg, memBuffer) {
|
||||
if (memQueue_in.isReady()) {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
|
||||
trigger(Event:Memory_Data, in_msg.Address);
|
||||
} else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
|
||||
trigger(Event:Memory_Ack, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Actions
|
||||
action(a_sendAck, "a", desc="Send ack to L2") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
|
||||
memQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Sender;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
//d_sendData;
|
||||
qf_queueMemoryFetchRequest;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
//a_sendAck;
|
||||
qw_queueMemoryWBRequest;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Data) {
|
||||
d_sendData;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Ack) {
|
||||
a_sendAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
}
|
7
src/mem/protocol/MESI_CMP_filter_directory_m.slicc
Normal file
7
src/mem/protocol/MESI_CMP_filter_directory_m.slicc
Normal file
|
@ -0,0 +1,7 @@
|
|||
../protocols/LogTM.sm
|
||||
../protocols/MESI_CMP_filter_directory-msg.sm
|
||||
../protocols/MESI_CMP_filter_directory-L2cache.sm
|
||||
../protocols/MESI_CMP_filter_directory-L1cache.sm
|
||||
../protocols/MESI_CMP_filter_directory_m-mem.sm
|
||||
../protocols/standard_CMP-protocol.sm
|
||||
|
894
src/mem/protocol/MESI_SCMP_bankdirectory-L1cache.sm
Normal file
894
src/mem/protocol/MESI_SCMP_bankdirectory-L1cache.sm
Normal file
|
@ -0,0 +1,894 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MSI_MOSI_CMP_directory-L1cache.sm 1.10 05/01/19 15:55:40-06:00 beckmann@s0-28.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
||||
|
||||
// NODE L1 CACHE
|
||||
// From this node's L1 cache TO the network
|
||||
// a local L1 -> this L2 bank, currently ordered with directory forwarded requests
|
||||
MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false";
|
||||
// a local L1 -> this L2 bank
|
||||
MessageBuffer responseFromL1Cache, network="To", virtual_network="3", ordered="false";
|
||||
MessageBuffer unblockFromL1Cache, network="To", virtual_network="4", ordered="false";
|
||||
|
||||
|
||||
// To this node's L1 cache FROM the network
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer requestToL1Cache, network="From", virtual_network="1", ordered="false";
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer responseToL1Cache, network="From", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||||
// Base states
|
||||
NP, desc="Not present in either cache";
|
||||
I, desc="a L1 cache entry Idle";
|
||||
S, desc="a L1 cache entry Shared";
|
||||
E, desc="a L1 cache entry Exclusive";
|
||||
M, desc="a L1 cache entry Modified", format="!b";
|
||||
|
||||
// Transient States
|
||||
IS, desc="L1 idle, issued GETS, have not seen response yet";
|
||||
IM, desc="L1 idle, issued GETX, have not seen response yet";
|
||||
SM, desc="L1 idle, issued GETX, have not seen response yet";
|
||||
IS_I, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
|
||||
|
||||
M_I, desc="L1 replacing, waiting for ACK";
|
||||
E_I, desc="L1 replacing, waiting for ACK";
|
||||
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
// L1 events
|
||||
Load, desc="Load request from the home processor";
|
||||
Ifetch, desc="I-fetch request from the home processor";
|
||||
Store, desc="Store request from the home processor";
|
||||
|
||||
Inv, desc="Invalidate request from L2 bank";
|
||||
|
||||
// internal generated request
|
||||
L1_Replacement, desc="L1 Replacement", format="!r";
|
||||
|
||||
// other requests
|
||||
Fwd_GETX, desc="GETX from other processor";
|
||||
Fwd_GETS, desc="GETS from other processor";
|
||||
Fwd_GET_INSTR, desc="GET_INSTR from other processor";
|
||||
|
||||
Data, desc="Data for processor";
|
||||
Data_Exclusive, desc="Data for processor";
|
||||
DataS_fromL1, desc="data for GETS request, need to unblock directory";
|
||||
Data_all_Acks, desc="Data for processor, all acks";
|
||||
|
||||
Ack, desc="Ack for processor";
|
||||
Ack_all, desc="Last ack for processor";
|
||||
|
||||
WB_Ack, desc="Ack for replacement";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
|
||||
State CacheState, desc="cache state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
bool Dirty, default="false", desc="data is dirty";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
Address Address, desc="Physical address for this TBE";
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="Buffer for the data block";
|
||||
bool Dirty, default="false", desc="data is dirty";
|
||||
bool isPrefetch, desc="Set if this was caused by a prefetch";
|
||||
int pendingAcks, default="0", desc="number of pending acks";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
|
||||
|
||||
CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
|
||||
CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
|
||||
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
int cache_state_to_int(State state);
|
||||
|
||||
// inclusive cache returns L1 entries only
|
||||
Entry getL1CacheEntry(Address addr), return_by_ref="yes" {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory[addr];
|
||||
} else {
|
||||
return L1IcacheMemory[addr];
|
||||
}
|
||||
}
|
||||
|
||||
void changeL1Permission(Address addr, AccessPermission permission) {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory.changePermission(addr, permission);
|
||||
} else if(L1IcacheMemory.isTagPresent(addr)) {
|
||||
return L1IcacheMemory.changePermission(addr, permission);
|
||||
} else {
|
||||
error("cannot change permission, L1 block not present");
|
||||
}
|
||||
}
|
||||
|
||||
bool isL1CacheTagPresent(Address addr) {
|
||||
return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
|
||||
}
|
||||
|
||||
State getState(Address addr) {
|
||||
if((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == true){
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(addr);
|
||||
}
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
return L1_TBEs[addr].TBEState;
|
||||
} else if (isL1CacheTagPresent(addr)) {
|
||||
return getL1CacheEntry(addr).CacheState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
// MUST CHANGE
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
L1_TBEs[addr].TBEState := state;
|
||||
}
|
||||
|
||||
if (isL1CacheTagPresent(addr)) {
|
||||
getL1CacheEntry(addr).CacheState := state;
|
||||
|
||||
// Set permission
|
||||
if (state == State:I) {
|
||||
changeL1Permission(addr, AccessPermission:Invalid);
|
||||
} else if (state == State:S || state == State:E) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Only);
|
||||
} else if (state == State:M) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
changeL1Permission(addr, AccessPermission:Busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event mandatory_request_type_to_event(CacheRequestType type) {
|
||||
if (type == CacheRequestType:LD) {
|
||||
return Event:Load;
|
||||
} else if (type == CacheRequestType:IFETCH) {
|
||||
return Event:Ifetch;
|
||||
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
|
||||
return Event:Store;
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
GenericMachineType getNondirectHitMachType(Address addr, MachineID sender) {
|
||||
if (machineIDToMachineType(sender) == MachineType:L1Cache) {
|
||||
return GenericMachineType:L1Cache_wCC; // NOTE direct L1 hits should not call this
|
||||
} else if (machineIDToMachineType(sender) == MachineType:L2Cache) {
|
||||
return GenericMachineType:L2Cache;
|
||||
} else {
|
||||
return ConvertMachToGenericMach(machineIDToMachineType(sender));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache);
|
||||
out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache);
|
||||
out_port(unblockNetwork_out, ResponseMsg, unblockFromL1Cache);
|
||||
|
||||
// Response IntraChip L1 Network - response msg to this L1 cache
|
||||
in_port(responseIntraChipL1Network_in, ResponseMsg, responseToL1Cache) {
|
||||
if (responseIntraChipL1Network_in.isReady()) {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) {
|
||||
trigger(Event:Data_Exclusive, in_msg.Address);
|
||||
} else if(in_msg.Type == CoherenceResponseType:DATA) {
|
||||
if ( (getState(in_msg.Address) == State:IS || getState(in_msg.Address) == State:IS_I) &&
|
||||
machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache ) {
|
||||
|
||||
trigger(Event:DataS_fromL1, in_msg.Address);
|
||||
|
||||
} else if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) {
|
||||
trigger(Event:Data_all_Acks, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:ACK) {
|
||||
if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) {
|
||||
trigger(Event:Ack_all, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Ack, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:WB_ACK) {
|
||||
trigger(Event:WB_Ack, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid L1 response type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request InterChip network - request from this L1 cache to the shared L2
|
||||
in_port(requestIntraChipL1Network_in, RequestMsg, requestToL1Cache) {
|
||||
if(requestIntraChipL1Network_in.isReady()) {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:Inv, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:UPGRADE) {
|
||||
// upgrade transforms to GETX due to race
|
||||
trigger(Event:Fwd_GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fwd_GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
trigger(Event:Fwd_GET_INSTR, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid forwarded request type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue betweens Node's CPU and it's L1 caches
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
// Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
|
||||
|
||||
if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
// ** INSTRUCTION ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
}
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 asks the L2 for it.
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// *** DATA ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
}
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 ask the L2 for it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
action(a_issueGETS, "a", desc="Issue GETS") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(ai_issueGETINSTR, "ai", desc="Issue GETINSTR") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GET_INSTR;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(b_issueGETX, "b", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.Requestor := machineID;
|
||||
DEBUG_EXPR(machineID);
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_issueUPGRADE, "c", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:UPGRADE;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendDataToRequestor, "d", desc="send data to requestor") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(e_sendAckToRequestor, "e", desc="send invalidate ack to requestor (could be L2 or L1)") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_sendDataToL2, "f", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.DataBlk := L1_TBEs[address].DataBlk;
|
||||
out_msg.Dirty := L1_TBEs[address].Dirty;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(fi_sendInvAck, "fi", desc="send data to the L2 cache") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
out_msg.AckCount := 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(g_issuePUTX, "g", desc="send data to the L2 cache") {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getL1CacheEntry(address).Dirty;
|
||||
out_msg.Requestor:= machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
if (getL1CacheEntry(address).Dirty) {
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
} else {
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(getL1CacheEntry(address).DataBlk);
|
||||
sequencer.readCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
}
|
||||
|
||||
action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
sequencer.readCallback(address, getL1CacheEntry(address).DataBlk, getNondirectHitMachType(in_msg.Address, in_msg.Sender), PrefetchBit:No);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||||
sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
getL1CacheEntry(address).Dirty := true;
|
||||
}
|
||||
|
||||
action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk, getNondirectHitMachType(in_msg.Address, in_msg.Sender), PrefetchBit:No);
|
||||
}
|
||||
getL1CacheEntry(address).Dirty := true;
|
||||
}
|
||||
|
||||
|
||||
action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
|
||||
check_allocate(L1_TBEs);
|
||||
L1_TBEs.allocate(address);
|
||||
L1_TBEs[address].isPrefetch := false;
|
||||
L1_TBEs[address].Dirty := getL1CacheEntry(address).Dirty;
|
||||
L1_TBEs[address].DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popRequestQueue, "l", desc="Pop incoming request queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(2, requestIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(3, responseIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||||
L1_TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(u_writeDataToL1Cache, "u", desc="Write data to cache") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
getL1CacheEntry(address).DataBlk := in_msg.DataBlk;
|
||||
getL1CacheEntry(address).Dirty := in_msg.Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
action(q_updateAckCount, "q", desc="Update ack count") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
L1_TBEs[address].pendingAcks := L1_TBEs[address].pendingAcks - in_msg.AckCount;
|
||||
APPEND_TRANSITION_COMMENT(in_msg.AckCount);
|
||||
APPEND_TRANSITION_COMMENT(" p: ");
|
||||
APPEND_TRANSITION_COMMENT(L1_TBEs[address].pendingAcks);
|
||||
}
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="Stall") {
|
||||
}
|
||||
|
||||
action(ff_deallocateL1CacheBlock, "\f", desc="Deallocate L1 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L1DcacheMemory.deallocate(address);
|
||||
} else {
|
||||
L1IcacheMemory.deallocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") {
|
||||
if (L1DcacheMemory.isTagPresent(address) == false) {
|
||||
L1DcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
|
||||
if (L1IcacheMemory.isTagPresent(address) == false) {
|
||||
L1IcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(zz_recycleRequestQueue, "zz", desc="recycle L1 request queue") {
|
||||
requestIntraChipL1Network_in.recycle();
|
||||
}
|
||||
|
||||
action(z_recycleMandatoryQueue, "\z", desc="recycle L1 request queue") {
|
||||
mandatoryQueue_in.recycle();
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************
|
||||
// TRANSITIONS
|
||||
//*****************************************************
|
||||
|
||||
// Transitions for Load/Store/Replacement/WriteBack from transient states
|
||||
transition({IS, IM, IS_I, M_I, E_I, SM}, {Load, Ifetch, Store, L1_Replacement}) {
|
||||
z_recycleMandatoryQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP,I}, L1_Replacement) {
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition({NP,I}, Load, IS) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,I}, Ifetch, IS) {
|
||||
pp_allocateL1ICacheBlock;
|
||||
i_allocateTBE;
|
||||
ai_issueGETINSTR;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,I}, Store, IM) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Inv) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition(S, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Store, SM) {
|
||||
i_allocateTBE;
|
||||
c_issueUPGRADE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, L1_Replacement, I) {
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(S, Inv, I) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Exclusive
|
||||
|
||||
transition(E, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(E, Store, M) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(E, L1_Replacement, M_I) {
|
||||
// silent E replacement??
|
||||
i_allocateTBE;
|
||||
g_issuePUTX; // send data, but hold in case forwarded request
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(E, Inv, I) {
|
||||
// don't send data
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(E, Fwd_GETX, I) {
|
||||
d_sendDataToRequestor;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(E, {Fwd_GETS, Fwd_GET_INSTR}, S) {
|
||||
d_sendDataToRequestor;
|
||||
d2_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, L1_Replacement, M_I) {
|
||||
i_allocateTBE;
|
||||
g_issuePUTX; // send data, but hold in case forwarded request
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(M_I, WB_Ack, I) {
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(M, Inv, I) {
|
||||
f_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, Inv, I) {
|
||||
ft_sendDataToL2_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, Fwd_GETX, I) {
|
||||
d_sendDataToRequestor;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, {Fwd_GETS, Fwd_GET_INSTR}, S) {
|
||||
d_sendDataToRequestor;
|
||||
d2_sendDataToL2;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, Fwd_GETX, I) {
|
||||
dt_sendDataToRequestor_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_I, {Fwd_GETS, Fwd_GET_INSTR}, I) {
|
||||
dt_sendDataToRequestor_fromTBE;
|
||||
d2t_sendDataToL2_fromTBE;
|
||||
s_deallocateTBE;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from IS
|
||||
transition({IS, IS_I}, Inv, IS_I) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data_all_Acks, S) {
|
||||
u_writeDataToL1Cache;
|
||||
x_external_load_hit;
|
||||
s_deallocateTBE;
|
||||
j_sendUnblock;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS_I, Data_all_Acks, I) {
|
||||
u_writeDataToL1Cache;
|
||||
x_external_load_hit;
|
||||
s_deallocateTBE;
|
||||
j_sendUnblock;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(IS, DataS_fromL1, S) {
|
||||
u_writeDataToL1Cache;
|
||||
j_sendUnblock;
|
||||
x_external_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS_I, DataS_fromL1, I) {
|
||||
u_writeDataToL1Cache;
|
||||
j_sendUnblock;
|
||||
x_external_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// directory is blocked when sending exclusive data
|
||||
transition(IS_I, Data_Exclusive, E) {
|
||||
u_writeDataToL1Cache;
|
||||
x_external_load_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data_Exclusive, E) {
|
||||
u_writeDataToL1Cache;
|
||||
x_external_load_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM
|
||||
transition({IM, SM}, Inv, IM) {
|
||||
fi_sendInvAck;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data, SM) {
|
||||
u_writeDataToL1Cache;
|
||||
q_updateAckCount;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data_all_Acks, M) {
|
||||
u_writeDataToL1Cache;
|
||||
xx_external_store_hit;
|
||||
jj_sendExclusiveUnblock;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from SM
|
||||
transition({SM, IM}, Ack) {
|
||||
q_updateAckCount;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(SM, Ack_all, M) {
|
||||
jj_sendExclusiveUnblock;
|
||||
xx_external_store_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
1052
src/mem/protocol/MESI_SCMP_bankdirectory-L2cache.sm
Normal file
1052
src/mem/protocol/MESI_SCMP_bankdirectory-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
166
src/mem/protocol/MESI_SCMP_bankdirectory-mem.sm
Normal file
166
src/mem/protocol/MESI_SCMP_bankdirectory-mem.sm
Normal file
|
@ -0,0 +1,166 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
|
||||
machine(Directory, "Token protocol") {
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A GETX arrives";
|
||||
Data, desc="A GETS arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
action(a_sendAck, "a", desc="Send ack to L2") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Sender);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
d_sendData;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
a_sendAck;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
112
src/mem/protocol/MESI_SCMP_bankdirectory-msg.sm
Normal file
112
src/mem/protocol/MESI_SCMP_bankdirectory-msg.sm
Normal file
|
@ -0,0 +1,112 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MSI_MOSI_CMP_directory-msg.sm 1.5 05/01/19 15:48:37-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
UPGRADE, desc="UPGRADE to exclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
INV, desc="INValidate";
|
||||
PUTX, desc="replacement message";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
MEMORY_ACK, desc="Ack from memory controller";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE, desc="Data";
|
||||
MEMORY_DATA, desc="Data";
|
||||
ACK, desc="Generic invalidate ack";
|
||||
WB_ACK, desc="writeback ack";
|
||||
UNBLOCK, desc="unblock";
|
||||
EXCLUSIVE_UNBLOCK, desc="exclusive unblock";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
MachineID Requestor , desc="What component request";
|
||||
NetDest Destination, desc="What components receive the request, includes MachineType and num";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
DataBlock DataBlk, desc="Data for the cache line (if PUTX)";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="Data for the cache line";
|
||||
bool Dirty, default="false", desc="Dirty bit";
|
||||
int AckCount, default="0", desc="number of acks in this message";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
/*
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:UPGRADE) {
|
||||
return GenericRequestType:UPGRADE;
|
||||
} else if(type == CoherenceRequestType:PUTS) {
|
||||
return GenericRequestType:PUTS;
|
||||
} else if(type == CoherenceRequestType:INV) {
|
||||
return GenericRequestType:INV;
|
||||
} else if(type == CoherenceRequestType:INV_S) {
|
||||
return GenericRequestType:INV_S;
|
||||
} else if(type == CoherenceRequestType:L1_DG) {
|
||||
return GenericRequestType:DOWNGRADE;
|
||||
} else if(type == CoherenceRequestType:WB_ACK) {
|
||||
return GenericRequestType:WB_ACK;
|
||||
} else if(type == CoherenceRequestType:EXE_ACK) {
|
||||
return GenericRequestType:EXE_ACK;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
5
src/mem/protocol/MESI_SCMP_bankdirectory.slicc
Normal file
5
src/mem/protocol/MESI_SCMP_bankdirectory.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MESI_SCMP_bankdirectory-msg.sm
|
||||
MESI_SCMP_bankdirectory-L2cache.sm
|
||||
MESI_SCMP_bankdirectory-L1cache.sm
|
||||
MESI_SCMP_bankdirectory-mem.sm
|
||||
standard_CMP-protocol.sm
|
250
src/mem/protocol/MESI_SCMP_bankdirectory_m-mem.sm
Normal file
250
src/mem/protocol/MESI_SCMP_bankdirectory_m-mem.sm
Normal file
|
@ -0,0 +1,250 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_token-dir.sm 1.6 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
// This file is copied from Yasuko Watanabe's prefetch / memory protocol
|
||||
// Copied here by aep 12/14/07
|
||||
|
||||
|
||||
machine(Directory, "MESI_SCMP_bankdirectory protocol") {
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A memory fetch arrives";
|
||||
Data, desc="writeback data arrives";
|
||||
Memory_Data, desc="Fetched data from memory arrives";
|
||||
Memory_Ack, desc="Writeback Ack from memory arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// to simulate detailed DRAM
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
MemoryControl memBuffer, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
}
|
||||
|
||||
bool isGETRequest(CoherenceRequestType type) {
|
||||
return (type == CoherenceRequestType:GETS) ||
|
||||
(type == CoherenceRequestType:GET_INSTR) ||
|
||||
(type == CoherenceRequestType:GETX);
|
||||
}
|
||||
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(memQueue_out, MemoryMsg, memBuffer);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (isGETRequest(in_msg.Type)) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// off-chip memory request/response is done
|
||||
in_port(memQueue_in, MemoryMsg, memBuffer) {
|
||||
if (memQueue_in.isReady()) {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
|
||||
trigger(Event:Memory_Data, in_msg.Address);
|
||||
} else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
|
||||
trigger(Event:Memory_Ack, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Actions
|
||||
action(a_sendAck, "a", desc="Send ack to L2") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
|
||||
memQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Sender;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
//d_sendData;
|
||||
qf_queueMemoryFetchRequest;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
//a_sendAck;
|
||||
qw_queueMemoryWBRequest;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Data) {
|
||||
d_sendData;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Ack) {
|
||||
a_sendAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
}
|
5
src/mem/protocol/MESI_SCMP_bankdirectory_m.slicc
Normal file
5
src/mem/protocol/MESI_SCMP_bankdirectory_m.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MESI_SCMP_bankdirectory-msg.sm
|
||||
MESI_SCMP_bankdirectory-L2cache.sm
|
||||
MESI_SCMP_bankdirectory-L1cache.sm
|
||||
MESI_SCMP_bankdirectory_m-mem.sm
|
||||
standard_CMP-protocol.sm
|
369
src/mem/protocol/MI_example-cache.sm
Normal file
369
src/mem/protocol/MI_example-cache.sm
Normal file
|
@ -0,0 +1,369 @@
|
|||
|
||||
machine(L1Cache, "MI Example") {
|
||||
|
||||
// NETWORK BUFFERS
|
||||
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="true";
|
||||
MessageBuffer responseFromCache, network="To", virtual_network="1", ordered="true";
|
||||
|
||||
MessageBuffer forwardToCache, network="From", virtual_network="2", ordered="true";
|
||||
MessageBuffer responseToCache, network="From", virtual_network="1", ordered="true";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states") {
|
||||
I, desc="Not Present/Invalid";
|
||||
II, desc="Not Present/Invalid, issued PUT";
|
||||
M, desc="Modified";
|
||||
MI, desc="Modified, issued PUT";
|
||||
|
||||
IS, desc="Issued request for IFETCH/GETX";
|
||||
IM, desc="Issued request for STORE/ATOMIC";
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
// From processor
|
||||
|
||||
Load, desc="Load request from processor";
|
||||
Ifetch, desc="Ifetch request from processor";
|
||||
Store, desc="Store request from processor";
|
||||
|
||||
Data, desc="Data from network";
|
||||
Fwd_GETX, desc="Forward from network";
|
||||
|
||||
Replacement, desc="Replace a block";
|
||||
Writeback_Ack, desc="Ack from the directory for a writeback";
|
||||
Writeback_Nack, desc="Nack from the directory for a writeback";
|
||||
}
|
||||
|
||||
// STRUCTURE DEFINITIONS
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry") {
|
||||
State CacheState, desc="cache state";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
|
||||
bool Trans, desc="Is this block part of a the current transaction?";
|
||||
bool Logged, desc="Has this block been logged in the current transaction?";
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// STRUCTURES
|
||||
|
||||
CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS, L1_CACHE_ASSOC, MachineType_L1Cache, int_to_string(i)+"_L1"', abstract_chip_ptr="true";
|
||||
|
||||
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||||
|
||||
|
||||
|
||||
// FUNCTIONS
|
||||
Event mandatory_request_type_to_event(CacheRequestType type) {
|
||||
if (type == CacheRequestType:LD) {
|
||||
return Event:Load;
|
||||
} else if (type == CacheRequestType:IFETCH) {
|
||||
return Event:Ifetch;
|
||||
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
|
||||
return Event:Store;
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
State getState(Address addr) {
|
||||
|
||||
if (TBEs.isPresent(addr)) {
|
||||
return TBEs[addr].TBEState;
|
||||
}
|
||||
else if (cacheMemory.isTagPresent(addr)) {
|
||||
return cacheMemory[addr].CacheState;
|
||||
}
|
||||
else {
|
||||
return State:I;
|
||||
}
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
|
||||
if (TBEs.isPresent(addr)) {
|
||||
TBEs[addr].TBEState := state;
|
||||
}
|
||||
|
||||
if (cacheMemory.isTagPresent(addr)) {
|
||||
cacheMemory[addr].CacheState := state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NETWORK PORTS
|
||||
|
||||
out_port(requestNetwork_out, RequestMsg, requestFromCache);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromCache);
|
||||
|
||||
in_port(forwardRequestNetwork_in, RequestMsg, forwardToCache) {
|
||||
if (forwardRequestNetwork_in.isReady()) {
|
||||
peek(forwardRequestNetwork_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:Fwd_GETX, in_msg.Address);
|
||||
}
|
||||
else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
|
||||
trigger(Event:Writeback_Ack, in_msg.Address);
|
||||
}
|
||||
else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
|
||||
trigger(Event:Writeback_Nack, in_msg.Address);
|
||||
}
|
||||
else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToCache) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
}
|
||||
else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
|
||||
if (cacheMemory.isTagPresent(in_msg.Address) == false &&
|
||||
cacheMemory.cacheAvail(in_msg.Address) == false ) {
|
||||
// make room for the block
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
else {
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
|
||||
action(a_issueRequest, "a", desc="Issue a request") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(b_issuePUT, "b", desc="Issue a PUT request") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(e_sendData, "e", desc="Send data from cache to requestor") {
|
||||
peek(forwardRequestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(ee_sendDataFromTBE, "\e", desc="Send data from TBE to requestor") {
|
||||
peek(forwardRequestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") {
|
||||
if (cacheMemory.isTagPresent(address) == false) {
|
||||
cacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(h_deallocateL1CacheBlock, "h", desc="deallocate a cache block") {
|
||||
if (cacheMemory.isTagPresent(address) == true) {
|
||||
cacheMemory.deallocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(m_popMandatoryQueue, "m", desc="Pop the mandatory request queue") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(n_popResponseQueue, "n", desc="Pop the response queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
|
||||
forwardRequestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
sequencer.readCallback(address, cacheMemory[address].DataBlk);
|
||||
}
|
||||
|
||||
action(s_store_hit, "s", desc="Notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
sequencer.writeCallback(address, cacheMemory[address].DataBlk);
|
||||
}
|
||||
|
||||
|
||||
action(u_writeDataToCache, "u", desc="Write data to the cache") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
cacheMemory[address].DataBlk := in_msg.DataBlk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(v_allocateTBE, "v", desc="Allocate TBE") {
|
||||
TBEs.allocate(address);
|
||||
}
|
||||
|
||||
|
||||
action(w_deallocateTBE, "w", desc="Deallocate TBE") {
|
||||
TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") {
|
||||
TBEs[address].DataBlk := cacheMemory[address].DataBlk;
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="stall") {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition({IS, IM, MI, II}, {Load, Ifetch, Store, Replacement}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition({IS, IM}, Fwd_GETX) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
s_store_hit;
|
||||
m_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, {Load, Ifetch}) {
|
||||
r_load_hit;
|
||||
m_popMandatoryQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(I, Store, IM) {
|
||||
v_allocateTBE;
|
||||
i_allocateL1CacheBlock;
|
||||
a_issueRequest;
|
||||
m_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(I, {Load, Ifetch}, IS) {
|
||||
v_allocateTBE;
|
||||
i_allocateL1CacheBlock;
|
||||
a_issueRequest;
|
||||
m_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data, M) {
|
||||
u_writeDataToCache;
|
||||
r_load_hit;
|
||||
w_deallocateTBE;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data, M) {
|
||||
u_writeDataToCache;
|
||||
s_store_hit;
|
||||
w_deallocateTBE;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(M, Fwd_GETX, I) {
|
||||
e_sendData;
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Replacement) {
|
||||
h_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(M, Replacement, MI) {
|
||||
v_allocateTBE;
|
||||
b_issuePUT;
|
||||
x_copyDataFromCacheToTBE;
|
||||
h_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(MI, Writeback_Ack, I) {
|
||||
w_deallocateTBE;
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(MI, Fwd_GETX, II) {
|
||||
ee_sendDataFromTBE;
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(II, Writeback_Nack, I) {
|
||||
w_deallocateTBE;
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
}
|
||||
|
257
src/mem/protocol/MI_example-dir.sm
Normal file
257
src/mem/protocol/MI_example-dir.sm
Normal file
|
@ -0,0 +1,257 @@
|
|||
|
||||
machine(Directory, "Directory protocol") {
|
||||
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="2", ordered="true";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="1", ordered="false";
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="0", ordered="true";
|
||||
MessageBuffer unblockToDir, network="From", virtual_network="3", ordered="true";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Invalid";
|
||||
M, desc="Modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
PUTX, desc="A PUTX arrives";
|
||||
PUTX_NotOwner, desc="A PUTX arrives";
|
||||
PUTO, desc="A PUTO arrives";
|
||||
Unblock, desc="An unblock message arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
NetDest Sharers, desc="Sharers for this block";
|
||||
NetDest Owner, desc="Owner of this block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
||||
if (state == State:I) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (directory[in_msg.Address].Owner.isElement(in_msg.Requestor)) {
|
||||
trigger(Event:PUTX, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:PUTX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
|
||||
trigger(Event:PUTO, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
|
||||
if (unblockNetwork_in.isReady()) {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
|
||||
trigger(Event:Unblock, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_NACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_clearOwner, "c", desc="Clear the owner field") {
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
|
||||
if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
|
||||
// out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE_CLEAN;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
}
|
||||
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false; // By definition, the block is now clean
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(e_ownerIsRequestor, "e", desc="The owner is now the requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
directory[address].Owner.clear();
|
||||
directory[address].Owner.add(in_msg.Requestor);
|
||||
}
|
||||
}
|
||||
|
||||
action(f_forwardRequest, "f", desc="Forward request to owner") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
APPEND_TRANSITION_COMMENT("Own: ");
|
||||
APPEND_TRANSITION_COMMENT(directory[in_msg.Address].Owner);
|
||||
APPEND_TRANSITION_COMMENT("Req: ");
|
||||
APPEND_TRANSITION_COMMENT(in_msg.Requestor);
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination := directory[in_msg.Address].Owner;
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
|
||||
requestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
|
||||
unblockNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
// peek(unblockNetwork_in, ResponseMsg) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
// assert(in_msg.Dirty);
|
||||
// assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, M) {
|
||||
d_sendData;
|
||||
e_ownerIsRequestor;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
transition(M, GETX, M) {
|
||||
f_forwardRequest;
|
||||
e_ownerIsRequestor;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// transition(M, PUTX, MI) {
|
||||
transition(M, PUTX, I) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_NotOwner, M) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, PUTX_NotOwner, I) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(MI, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
}
|
92
src/mem/protocol/MI_example-msg.sm
Normal file
92
src/mem/protocol/MI_example-msg.sm
Normal file
|
@ -0,0 +1,92 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_SMP_directory-msg.sm 1.8 05/01/19 15:48:36-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
PUTX, desc="Put eXclusive";
|
||||
PUTO, desc="Put Owned";
|
||||
WB_ACK, desc="Writeback ack";
|
||||
WB_NACK, desc="Writeback neg. ack";
|
||||
INV, desc="Invalidation";
|
||||
FWD, desc="Generic FWD";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
ACK, desc="ACKnowledgment, responder doesn't have a copy";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE_CLEAN, desc="Data, no other processor has a copy, data is clean";
|
||||
DATA_EXCLUSIVE_DIRTY, desc="Data, no other processor has a copy, data is dirty";
|
||||
UNBLOCK, desc="Unblock";
|
||||
UNBLOCK_EXCLUSIVE, desc="Unblock, we're in E/M";
|
||||
WRITEBACK_CLEAN, desc="Clean writeback (no data)";
|
||||
WRITEBACK_DIRTY, desc="Dirty writeback (contains data)";
|
||||
WRITEBACK, desc="Generic writeback (contains data)";
|
||||
}
|
||||
|
||||
// TriggerType
|
||||
enumeration(TriggerType, desc="...") {
|
||||
ALL_ACKS, desc="See corresponding event";
|
||||
}
|
||||
|
||||
// TriggerMsg
|
||||
structure(TriggerMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
TriggerType Type, desc="Type of trigger";
|
||||
}
|
||||
|
||||
// RequestMsg (and also forwarded requests)
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
int Acks, desc="How many acks to expect";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// ResponseMsg (and also unblock requests)
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
int Acks, desc="How many acks to expect";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
4
src/mem/protocol/MI_example.slicc
Normal file
4
src/mem/protocol/MI_example.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MI_example-msg.sm
|
||||
MI_example-cache.sm
|
||||
MI_example-dir.sm
|
||||
standard_1level_SMP-protocol.sm
|
1153
src/mem/protocol/MOESI_CMP_directory-L1cache.sm
Normal file
1153
src/mem/protocol/MOESI_CMP_directory-L1cache.sm
Normal file
File diff suppressed because it is too large
Load diff
2569
src/mem/protocol/MOESI_CMP_directory-L2cache.sm
Normal file
2569
src/mem/protocol/MOESI_CMP_directory-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
573
src/mem/protocol/MOESI_CMP_directory-dir.sm
Normal file
573
src/mem/protocol/MOESI_CMP_directory-dir.sm
Normal file
|
@ -0,0 +1,573 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
machine(Directory, "Directory protocol") {
|
||||
|
||||
// ** IN QUEUES **
|
||||
MessageBuffer foo1, network="From", virtual_network="0", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
|
||||
MessageBuffer goo1, network="To", virtual_network="0", ordered="false";
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false"; // Dir -> mod-L2 bank
|
||||
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Invalid";
|
||||
S, desc="Shared";
|
||||
O, desc="Owner";
|
||||
M, desc="Modified";
|
||||
|
||||
IS, desc="Blocked, was in idle";
|
||||
SS, desc="Blocked, was in shared";
|
||||
OO, desc="Blocked, was in owned";
|
||||
MO, desc="Blocked, going to owner or maybe modified";
|
||||
MM, desc="Blocked, going to modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
MIS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
OS, desc="Blocked on a writeback";
|
||||
OSS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
PUTX, desc="A PUTX arrives";
|
||||
PUTO, desc="A PUTO arrives";
|
||||
PUTO_SHARERS, desc="A PUTO arrives, but don't remove from sharers list";
|
||||
Unblock, desc="An unblock message arrives";
|
||||
Last_Unblock, desc="An unblock message arrives, we're not waiting for any additional unblocks";
|
||||
Exclusive_Unblock, desc="The processor become the exclusive owner (E or M) of the line";
|
||||
Clean_Writeback, desc="The final message as part of a PutX/PutS, no data";
|
||||
Dirty_Writeback, desc="The final message as part of a PutX/PutS, contains data";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
NetDest Sharers, desc="Sharers for this block";
|
||||
NetDest Owner, desc="Owner of this block";
|
||||
int WaitingUnblocks, desc="Number of acks we're waiting for";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
||||
if (state == State:I) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:S) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:O) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.isSuperset(directory[addr].Owner) == false);
|
||||
}
|
||||
|
||||
if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if ((state != State:SS) && (state != State:OO)) {
|
||||
assert(directory[addr].WaitingUnblocks == 0);
|
||||
}
|
||||
|
||||
if ( (directory[addr].DirectoryState != State:I) && (state == State:I) ) {
|
||||
directory[addr].DirectoryState := state;
|
||||
// disable coherence checker
|
||||
// sequencer.checkCoherence(addr);
|
||||
}
|
||||
else {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking
|
||||
bool isBlockShared(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isBlockExclusive(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
// out_port(requestQueue_out, ResponseMsg, requestFromDir); // For recycling requests
|
||||
out_port(goo1_out, ResponseMsg, goo1);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(foo1_in, ResponseMsg, foo1) {
|
||||
|
||||
}
|
||||
|
||||
// in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
|
||||
// if (unblockNetwork_in.isReady()) {
|
||||
in_port(unblockNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (unblockNetwork_in.isReady()) {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
|
||||
if (directory[in_msg.Address].WaitingUnblocks == 1) {
|
||||
trigger(Event:Last_Unblock, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Unblock, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
|
||||
trigger(Event:Exclusive_Unblock, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
|
||||
trigger(Event:Dirty_Writeback, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_ACK) {
|
||||
trigger(Event:Clean_Writeback, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
trigger(Event:PUTX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
|
||||
trigger(Event:PUTO, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) {
|
||||
trigger(Event:PUTO_SHARERS, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_NACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_clearOwner, "c", desc="Clear the owner field") {
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(c_moveOwnerToSharer, "cc", desc="Move owner to sharers") {
|
||||
directory[address].Sharers.addNetDest(directory[address].Owner);
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(cc_clearSharers, "\c", desc="Clear the sharers field") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
// enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
|
||||
if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
|
||||
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
}
|
||||
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false; // By definition, the block is now clean
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Owner.clear();
|
||||
directory[address].Owner.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(f_forwardRequest, "f", desc="Forward request to owner") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Owner);
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if ((directory[in_msg.Address].Sharers.count() > 1) ||
|
||||
((directory[in_msg.Address].Sharers.count() > 0) && (directory[in_msg.Address].Sharers.isElement(in_msg.Requestor) == false))) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
// out_msg.Destination := directory[in_msg.Address].Sharers;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Sharers);
|
||||
out_msg.Destination.remove(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
|
||||
requestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
|
||||
unblockNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(ll_checkDataInMemory, "\l", desc="Check PUTX/PUTO data is same as in the memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Sharers.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks + 1;
|
||||
}
|
||||
|
||||
action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks - 1;
|
||||
assert(directory[address].WaitingUnblocks >= 0);
|
||||
}
|
||||
|
||||
// action(z_stall, "z", desc="Cannot be handled right now.") {
|
||||
// Special name recognized as do nothing case
|
||||
// }
|
||||
|
||||
action(zz_recycleRequest, "\z", desc="Recycle the request queue") {
|
||||
requestQueue_in.recycle();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, MM) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX, MM) {
|
||||
d_sendData;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETS, IS) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETS, SS) {
|
||||
d_sendData;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S}, PUTO) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O}, PUTX) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({O, OO}, GETS, OO) {
|
||||
f_forwardRequest;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETS, MO) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// happens if M->O transition happens on-chip
|
||||
transition(M, PUTO, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTO_SHARERS, MIS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO, OS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO_SHARERS, OSS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
transition({MM, MO, MI, MIS, OS, OSS}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition({MM, MO}, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MO, Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, GETS) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Last_Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Last_Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Dirty_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Dirty_Writeback, S) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Clean_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Clean_Writeback, S) {
|
||||
c_clearOwner;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({MI, MIS}, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({OS, OSS}, Unblock, O) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
}
|
126
src/mem/protocol/MOESI_CMP_directory-msg.sm
Normal file
126
src/mem/protocol/MOESI_CMP_directory-msg.sm
Normal file
|
@ -0,0 +1,126 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
PUTX, desc="Put eXclusive";
|
||||
PUTO, desc="Put Owned";
|
||||
PUTO_SHARERS, desc="Put Owned, but sharers exist so don't remove from sharers list";
|
||||
PUTS, desc="Put Shared";
|
||||
WB_ACK, desc="Writeback ack";
|
||||
WB_ACK_DATA, desc="Writeback ack";
|
||||
WB_NACK, desc="Writeback neg. ack";
|
||||
INV, desc="Invalidation";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
ACK, desc="ACKnowledgment, responder doesn't have a copy";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE, desc="Data, no processor has a copy";
|
||||
UNBLOCK, desc="Unblock";
|
||||
UNBLOCK_EXCLUSIVE, desc="Unblock, we're in E/M";
|
||||
WRITEBACK_CLEAN_DATA, desc="Clean writeback (contains data)";
|
||||
WRITEBACK_CLEAN_ACK, desc="Clean writeback (contains no data)";
|
||||
WRITEBACK_DIRTY_DATA, desc="Dirty writeback (contains data)";
|
||||
}
|
||||
|
||||
// TriggerType
|
||||
enumeration(TriggerType, desc="...") {
|
||||
ALL_ACKS, desc="See corresponding event";
|
||||
}
|
||||
|
||||
// TriggerMsg
|
||||
structure(TriggerMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
TriggerType Type, desc="Type of trigger";
|
||||
}
|
||||
|
||||
// RequestMsg (and also forwarded requests)
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
MachineType RequestorMachine, desc="type of component";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
int Acks, desc="How many acks to expect";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// ResponseMsg (and also unblock requests)
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
MachineType SenderMachine, desc="type of component sending msg";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
int Acks, desc="How many acks to expect";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:PUTS) {
|
||||
return GenericRequestType:PUTS;
|
||||
} else if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTS;
|
||||
} else if(type == CoherenceRequestType:PUTO) {
|
||||
return GenericRequestType:PUTO;
|
||||
} else if(type == CoherenceRequestType:PUTO_SHARERS) {
|
||||
return GenericRequestType:PUTO;
|
||||
} else if(type == CoherenceRequestType:INV) {
|
||||
return GenericRequestType:INV;
|
||||
} else if(type == CoherenceRequestType:WB_ACK) {
|
||||
return GenericRequestType:WB_ACK;
|
||||
} else if(type == CoherenceRequestType:WB_ACK_DATA) {
|
||||
return GenericRequestType:WB_ACK;
|
||||
} else if(type == CoherenceRequestType:WB_NACK) {
|
||||
return GenericRequestType:NACK;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
||||
|
573
src/mem/protocol/MOESI_CMP_directory-perfectDir.sm
Normal file
573
src/mem/protocol/MOESI_CMP_directory-perfectDir.sm
Normal file
|
@ -0,0 +1,573 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_CMP_directory-dir.sm 1.11 05/01/19 15:48:35-06:00 mikem@royal16.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
machine(Directory, "Directory protocol") {
|
||||
|
||||
// ** IN QUEUES **
|
||||
MessageBuffer foo1, network="From", virtual_network="0", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
|
||||
MessageBuffer goo1, network="To", virtual_network="0", ordered="false";
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false"; // Dir -> mod-L2 bank
|
||||
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Invalid";
|
||||
S, desc="Shared";
|
||||
O, desc="Owner";
|
||||
M, desc="Modified";
|
||||
|
||||
IS, desc="Blocked, was in idle";
|
||||
SS, desc="Blocked, was in shared";
|
||||
OO, desc="Blocked, was in owned";
|
||||
MO, desc="Blocked, going to owner or maybe modified";
|
||||
MM, desc="Blocked, going to modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
MIS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
OS, desc="Blocked on a writeback";
|
||||
OSS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
PUTX, desc="A PUTX arrives";
|
||||
PUTO, desc="A PUTO arrives";
|
||||
PUTO_SHARERS, desc="A PUTO arrives, but don't remove from sharers list";
|
||||
Unblock, desc="An unblock message arrives";
|
||||
Last_Unblock, desc="An unblock message arrives, we're not waiting for any additional unblocks";
|
||||
Exclusive_Unblock, desc="The processor become the exclusive owner (E or M) of the line";
|
||||
Clean_Writeback, desc="The final message as part of a PutX/PutS, no data";
|
||||
Dirty_Writeback, desc="The final message as part of a PutX/PutS, contains data";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
NetDest Sharers, desc="Sharers for this block";
|
||||
NetDest Owner, desc="Owner of this block";
|
||||
int WaitingUnblocks, desc="Number of acks we're waiting for";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
||||
if (state == State:I) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:S) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:O) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.isSuperset(directory[addr].Owner) == false);
|
||||
}
|
||||
|
||||
if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if ((state != State:SS) && (state != State:OO)) {
|
||||
assert(directory[addr].WaitingUnblocks == 0);
|
||||
}
|
||||
|
||||
if ( (directory[addr].DirectoryState != State:I) && (state == State:I) ) {
|
||||
directory[addr].DirectoryState := state;
|
||||
// disable coherence checker
|
||||
// sequencer.checkCoherence(addr);
|
||||
}
|
||||
else {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking
|
||||
bool isBlockShared(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isBlockExclusive(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
// out_port(requestQueue_out, ResponseMsg, requestFromDir); // For recycling requests
|
||||
out_port(goo1_out, ResponseMsg, goo1);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(foo1_in, ResponseMsg, foo1) {
|
||||
|
||||
}
|
||||
|
||||
// in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
|
||||
// if (unblockNetwork_in.isReady()) {
|
||||
in_port(unblockNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (unblockNetwork_in.isReady()) {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
|
||||
if (directory[in_msg.Address].WaitingUnblocks == 1) {
|
||||
trigger(Event:Last_Unblock, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Unblock, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
|
||||
trigger(Event:Exclusive_Unblock, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
|
||||
trigger(Event:Dirty_Writeback, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_ACK) {
|
||||
trigger(Event:Clean_Writeback, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
trigger(Event:PUTX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
|
||||
trigger(Event:PUTO, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) {
|
||||
trigger(Event:PUTO_SHARERS, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_CACHE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_CACHE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_NACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_clearOwner, "c", desc="Clear the owner field") {
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(c_moveOwnerToSharer, "cc", desc="Move owner to sharers") {
|
||||
directory[address].Sharers.addNetDest(directory[address].Owner);
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(cc_clearSharers, "\c", desc="Clear the sharers field") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
// enqueue(responseNetwork_out, ResponseMsg, latency="L2_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
|
||||
if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
|
||||
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
}
|
||||
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false; // By definition, the block is now clean
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Owner.clear();
|
||||
directory[address].Owner.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(f_forwardRequest, "f", desc="Forward request to owner") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_CACHE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Owner);
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if ((directory[in_msg.Address].Sharers.count() > 1) ||
|
||||
((directory[in_msg.Address].Sharers.count() > 0) && (directory[in_msg.Address].Sharers.isElement(in_msg.Requestor) == false))) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_CACHE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
// out_msg.Destination := directory[in_msg.Address].Sharers;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Sharers);
|
||||
out_msg.Destination.remove(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
|
||||
requestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
|
||||
unblockNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(ll_checkDataInMemory, "\l", desc="Check PUTX/PUTO data is same as in the memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Sharers.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks + 1;
|
||||
}
|
||||
|
||||
action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks - 1;
|
||||
assert(directory[address].WaitingUnblocks >= 0);
|
||||
}
|
||||
|
||||
// action(z_stall, "z", desc="Cannot be handled right now.") {
|
||||
// Special name recognized as do nothing case
|
||||
// }
|
||||
|
||||
action(zz_recycleRequest, "\z", desc="Recycle the request queue") {
|
||||
requestQueue_in.recycle();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, MM) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX, MM) {
|
||||
d_sendData;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETS, IS) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETS, SS) {
|
||||
d_sendData;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S}, PUTO) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O}, PUTX) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({O, OO}, GETS, OO) {
|
||||
f_forwardRequest;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETS, MO) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// happens if M->O transition happens on-chip
|
||||
transition(M, PUTO, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTO_SHARERS, MIS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO, OS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO_SHARERS, OSS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
transition({MM, MO, MI, MIS, OS, OSS}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition({MM, MO}, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MO, Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, GETS) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Last_Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Last_Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Dirty_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Dirty_Writeback, S) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Clean_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Clean_Writeback, S) {
|
||||
c_clearOwner;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({MI, MIS}, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({OS, OSS}, Unblock, O) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
}
|
5
src/mem/protocol/MOESI_CMP_directory.slicc
Normal file
5
src/mem/protocol/MOESI_CMP_directory.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MOESI_CMP_directory-msg.sm
|
||||
MOESI_CMP_directory-L2cache.sm
|
||||
MOESI_CMP_directory-L1cache.sm
|
||||
MOESI_CMP_directory-dir.sm
|
||||
standard_CMP-protocol.sm
|
652
src/mem/protocol/MOESI_CMP_directory_m-dir.sm
Normal file
652
src/mem/protocol/MOESI_CMP_directory_m-dir.sm
Normal file
|
@ -0,0 +1,652 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
machine(Directory, "Directory protocol") {
|
||||
|
||||
// ** IN QUEUES **
|
||||
MessageBuffer foo1, network="From", virtual_network="0", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
|
||||
MessageBuffer goo1, network="To", virtual_network="0", ordered="false";
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false"; // Dir -> mod-L2 bank
|
||||
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Invalid";
|
||||
S, desc="Shared";
|
||||
O, desc="Owner";
|
||||
M, desc="Modified";
|
||||
|
||||
IS, desc="Blocked, was in idle";
|
||||
SS, desc="Blocked, was in shared";
|
||||
OO, desc="Blocked, was in owned";
|
||||
MO, desc="Blocked, going to owner or maybe modified";
|
||||
MM, desc="Blocked, going to modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
MIS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
OS, desc="Blocked on a writeback";
|
||||
OSS, desc="Blocked on a writeback, but don't remove from sharers when received";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
PUTX, desc="A PUTX arrives";
|
||||
PUTO, desc="A PUTO arrives";
|
||||
PUTO_SHARERS, desc="A PUTO arrives, but don't remove from sharers list";
|
||||
Unblock, desc="An unblock message arrives";
|
||||
Last_Unblock, desc="An unblock message arrives, we're not waiting for any additional unblocks";
|
||||
Exclusive_Unblock, desc="The processor become the exclusive owner (E or M) of the line";
|
||||
Clean_Writeback, desc="The final message as part of a PutX/PutS, no data";
|
||||
Dirty_Writeback, desc="The final message as part of a PutX/PutS, contains data";
|
||||
Memory_Data, desc="Fetched data from memory arrives";
|
||||
Memory_Ack, desc="Writeback Ack from memory arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
NetDest Sharers, desc="Sharers for this block";
|
||||
NetDest Owner, desc="Owner of this block";
|
||||
int WaitingUnblocks, desc="Number of acks we're waiting for";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// to simulate detailed DRAM
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
MemoryControl memBuffer, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
||||
if (state == State:I) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:S) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
}
|
||||
|
||||
if (state == State:O) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.isSuperset(directory[addr].Owner) == false);
|
||||
}
|
||||
|
||||
if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if ((state != State:SS) && (state != State:OO)) {
|
||||
assert(directory[addr].WaitingUnblocks == 0);
|
||||
}
|
||||
|
||||
if ( (directory[addr].DirectoryState != State:I) && (state == State:I) ) {
|
||||
directory[addr].DirectoryState := state;
|
||||
// disable coherence checker
|
||||
// sequencer.checkCoherence(addr);
|
||||
}
|
||||
else {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking
|
||||
bool isBlockShared(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isBlockExclusive(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
if (directory[addr].DirectoryState == State:I) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
// out_port(requestQueue_out, ResponseMsg, requestFromDir); // For recycling requests
|
||||
out_port(goo1_out, ResponseMsg, goo1);
|
||||
out_port(memQueue_out, MemoryMsg, memBuffer);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(foo1_in, ResponseMsg, foo1) {
|
||||
|
||||
}
|
||||
|
||||
// in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
|
||||
// if (unblockNetwork_in.isReady()) {
|
||||
in_port(unblockNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (unblockNetwork_in.isReady()) {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
|
||||
if (directory[in_msg.Address].WaitingUnblocks == 1) {
|
||||
trigger(Event:Last_Unblock, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Unblock, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
|
||||
trigger(Event:Exclusive_Unblock, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
|
||||
trigger(Event:Dirty_Writeback, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_ACK) {
|
||||
trigger(Event:Clean_Writeback, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
trigger(Event:PUTX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
|
||||
trigger(Event:PUTO, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) {
|
||||
trigger(Event:PUTO_SHARERS, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// off-chip memory request/response is done
|
||||
in_port(memQueue_in, MemoryMsg, memBuffer) {
|
||||
if (memQueue_in.isReady()) {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
|
||||
trigger(Event:Memory_Data, in_msg.Address);
|
||||
} else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
|
||||
trigger(Event:Memory_Ack, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_NACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_clearOwner, "c", desc="Clear the owner field") {
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(c_moveOwnerToSharer, "cc", desc="Move owner to sharers") {
|
||||
directory[address].Sharers.addNetDest(directory[address].Owner);
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(cc_clearSharers, "\c", desc="Clear the sharers field") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
action(d_sendDataMsg, "d", desc="Send data to requestor") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
//out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := false; // By definition, the block is now clean
|
||||
out_msg.Acks := in_msg.Acks;
|
||||
if (in_msg.ReadX) {
|
||||
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Owner.clear();
|
||||
directory[address].Owner.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(f_forwardRequest, "f", desc="Forward request to owner") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Owner);
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if ((directory[in_msg.Address].Sharers.count() > 1) ||
|
||||
((directory[in_msg.Address].Sharers.count() > 0) && (directory[in_msg.Address].Sharers.isElement(in_msg.Requestor) == false))) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
// out_msg.Destination := directory[in_msg.Address].Sharers;
|
||||
out_msg.Destination.addNetDest(directory[in_msg.Address].Sharers);
|
||||
out_msg.Destination.remove(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Invalidate_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
|
||||
requestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
|
||||
unblockNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(ll_checkDataInMemory, "\l", desc="Check PUTX/PUTO data is same as in the memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Sharers.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks + 1;
|
||||
}
|
||||
|
||||
action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks - 1;
|
||||
assert(directory[address].WaitingUnblocks >= 0);
|
||||
}
|
||||
|
||||
action(q_popMemQueue, "q", desc="Pop off-chip request queue") {
|
||||
memQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := false;
|
||||
// These are not used by memory but are passed back here with the read data:
|
||||
out_msg.ReadX := (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0);
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.Sender := machineID;
|
||||
//out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := false;
|
||||
// Not used:
|
||||
out_msg.ReadX := false;
|
||||
out_msg.Acks := 0;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// action(z_stall, "z", desc="Cannot be handled right now.") {
|
||||
// Special name recognized as do nothing case
|
||||
// }
|
||||
|
||||
action(zz_recycleRequest, "\z", desc="Recycle the request queue") {
|
||||
requestQueue_in.recycle();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, MM) {
|
||||
qf_queueMemoryFetchRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX, MM) {
|
||||
qf_queueMemoryFetchRequest;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETS, IS) {
|
||||
qf_queueMemoryFetchRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETS, SS) {
|
||||
qf_queueMemoryFetchRequest;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S}, PUTO) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O}, PUTX) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({O, OO}, GETS, OO) {
|
||||
f_forwardRequest;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETS, MO) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// happens if M->O transition happens on-chip
|
||||
transition(M, PUTO, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTO_SHARERS, MIS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO, OS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO_SHARERS, OSS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
transition({MM, MO, MI, MIS, OS, OSS}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition({MM, MO}, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MO, Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, GETS) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Last_Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Last_Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Dirty_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
l_writeDataToMemory;
|
||||
qw_queueMemoryWBRequest;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
qw_queueMemoryWBRequest;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MIS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Dirty_Writeback, S) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
qw_queueMemoryWBRequest;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Dirty_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
l_writeDataToMemory;
|
||||
qw_queueMemoryWBRequest;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OSS, Clean_Writeback, S) {
|
||||
c_moveOwnerToSharer;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Clean_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Clean_Writeback, S) {
|
||||
c_clearOwner;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({MI, MIS}, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({OS, OSS}, Unblock, O) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS}, Memory_Data) {
|
||||
d_sendDataMsg;
|
||||
q_popMemQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O, M, IS, SS, OO, MO, MM, MI, MIS, OS, OSS}, Memory_Ack) {
|
||||
//a_sendAck;
|
||||
q_popMemQueue;
|
||||
}
|
||||
|
||||
}
|
5
src/mem/protocol/MOESI_CMP_directory_m.slicc
Normal file
5
src/mem/protocol/MOESI_CMP_directory_m.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MOESI_CMP_directory-msg.sm
|
||||
MOESI_CMP_directory-L2cache.sm
|
||||
MOESI_CMP_directory-L1cache.sm
|
||||
MOESI_CMP_directory_m-dir.sm
|
||||
standard_CMP-protocol.sm
|
2041
src/mem/protocol/MOESI_CMP_token-L1cache.sm
Normal file
2041
src/mem/protocol/MOESI_CMP_token-L1cache.sm
Normal file
File diff suppressed because it is too large
Load diff
1424
src/mem/protocol/MOESI_CMP_token-L2cache.sm
Normal file
1424
src/mem/protocol/MOESI_CMP_token-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
435
src/mem/protocol/MOESI_CMP_token-dir.sm
Normal file
435
src/mem/protocol/MOESI_CMP_token-dir.sm
Normal file
|
@ -0,0 +1,435 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
machine(Directory, "Token protocol") {
|
||||
|
||||
MessageBuffer requestFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false";
|
||||
|
||||
MessageBuffer persistentToDir, network="From", virtual_network="3", ordered="true";
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseToDir, network="From", virtual_network="2", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_O") {
|
||||
// Base states
|
||||
O, desc="Owner";
|
||||
NO, desc="Not Owner";
|
||||
L, desc="Locked";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
Lockdown, desc="A lockdown request arrives";
|
||||
Unlockdown, desc="An un-lockdown request arrives";
|
||||
Data_Owner, desc="Data arrive";
|
||||
Ack_Owner, desc="Owner token arrived without data because it was clean";
|
||||
Tokens, desc="Tokens arrive";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
int Tokens, default="max_tokens()", desc="Number of tokens for the line we're holding";
|
||||
|
||||
// The following state is provided to allow for bandwidth
|
||||
// efficient directory-like operation. However all of this state
|
||||
// is 'soft state' that does not need to be correct (as long as
|
||||
// you're eventually willing to resort to broadcast.)
|
||||
|
||||
Set Owner, desc="Probable Owner of the line. More accurately, the set of processors who need to see a GetS or GetO. We use a Set for convenience, but only one bit is set at a time.";
|
||||
Set Sharers, desc="Probable sharers of the line. More accurately, the set of processors who need to see a GetX";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
PersistentTable persistentTable, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
directory[addr].DirectoryState := state;
|
||||
|
||||
if (state == State:L) {
|
||||
assert(directory[addr].Tokens == 0);
|
||||
}
|
||||
|
||||
// We have one or zero owners
|
||||
assert((directory[addr].Owner.count() == 0) || (directory[addr].Owner.count() == 1));
|
||||
|
||||
// Make sure the token count is in range
|
||||
assert(directory[addr].Tokens >= 0);
|
||||
assert(directory[addr].Tokens <= max_tokens());
|
||||
|
||||
if (state == State:O) {
|
||||
assert(directory[addr].Tokens >= 1); // Must have at least one token
|
||||
// assert(directory[addr].Tokens >= (max_tokens() / 2)); // Only mostly true; this might not always hold
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(requestNetwork_out, RequestMsg, requestFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(persistentNetwork_in, PersistentMsg, persistentToDir) {
|
||||
if (persistentNetwork_in.isReady()) {
|
||||
peek(persistentNetwork_in, PersistentMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
|
||||
if (distributedPersistentEnabled()) {
|
||||
// Apply the lockdown or unlockdown message to the table
|
||||
if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
|
||||
persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Write);
|
||||
} else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
|
||||
persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Read);
|
||||
} else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
|
||||
persistentTable.persistentRequestUnlock(in_msg.Address, in_msg.Requestor);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
|
||||
// React to the message based on the current state of the table
|
||||
if (persistentTable.isLocked(in_msg.Address)) {
|
||||
trigger(Event:Lockdown, in_msg.Address); // locked
|
||||
} else {
|
||||
trigger(Event:Unlockdown, in_msg.Address); // unlocked
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
|
||||
trigger(Event:Lockdown, in_msg.Address); // locked
|
||||
} else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
|
||||
trigger(Event:Lockdown, in_msg.Address); // locked
|
||||
} else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
|
||||
trigger(Event:Unlockdown, in_msg.Address); // unlocked
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
|
||||
trigger(Event:Data_Owner, in_msg.Address);
|
||||
} else if ((in_msg.Type == CoherenceResponseType:ACK) ||
|
||||
(in_msg.Type == CoherenceResponseType:DATA_SHARED)) {
|
||||
trigger(Event:Tokens, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) {
|
||||
trigger(Event:Ack_Owner, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendTokens, "a", desc="Send tokens to requestor") {
|
||||
// Only send a message if we have tokens to send
|
||||
if (directory[address].Tokens > 0) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
// enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_CACHE_LATENCY") {// FIXME?
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_LATENCY") {// FIXME?
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.Tokens := directory[in_msg.Address].Tokens;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
}
|
||||
|
||||
action(aa_sendTokensToStarver, "\a", desc="Send tokens to starver") {
|
||||
// Only send a message if we have tokens to send
|
||||
if (directory[address].Tokens > 0) {
|
||||
// enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_CACHE_LATENCY") {// FIXME?
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_LATENCY") {// FIXME?
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.Tokens := directory[address].Tokens;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
}
|
||||
|
||||
action(d_sendDataWithAllTokens, "d", desc="Send data and tokens to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
assert(directory[address].Tokens > 0);
|
||||
out_msg.Tokens := directory[in_msg.Address].Tokens;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
|
||||
action(dd_sendDataWithAllTokensToStarver, "\d", desc="Send data and tokens to starver") {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
assert(directory[address].Tokens > 0);
|
||||
out_msg.Tokens := directory[address].Tokens;
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
|
||||
action(f_incrementTokens, "f", desc="Increment the number of tokens we're tracking") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Tokens >= 1);
|
||||
directory[address].Tokens := directory[address].Tokens + in_msg.Tokens;
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming response queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popIncomingPersistentQueue, "l", desc="Pop incoming persistent queue") {
|
||||
persistentNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_checkIncomingMsg, "n", desc="Check incoming token message") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Type == CoherenceResponseType:ACK_OWNER);
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(r_bounceResponse, "r", desc="Bounce response to starving processor") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.Tokens := in_msg.Tokens;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := in_msg.Dirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(s_bounceDatalessOwnerToken, "s", desc="Bounce clean owner token to starving processor") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Type == CoherenceResponseType:ACK_OWNER);
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
|
||||
// Bounce the message, but "re-associate" the data and the owner
|
||||
// token. In essence we're converting an ACK_OWNER message to a
|
||||
// DATA_OWNER message, keeping the number of tokens the same.
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.Tokens := in_msg.Tokens;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := in_msg.Dirty;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
// Trans. from O
|
||||
transition(O, GETX, NO) {
|
||||
d_sendDataWithAllTokens;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETS, NO) {
|
||||
d_sendDataWithAllTokens;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, Lockdown, L) {
|
||||
dd_sendDataWithAllTokensToStarver;
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
transition(O, Tokens) {
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Trans. from NO
|
||||
transition(NO, GETX) {
|
||||
a_sendTokens;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(NO, GETS) {
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(NO, Lockdown, L) {
|
||||
aa_sendTokensToStarver;
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
transition(NO, Data_Owner, O) {
|
||||
m_writeDataToMemory;
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(NO, Ack_Owner, O) {
|
||||
n_checkIncomingMsg;
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(NO, Tokens) {
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Trans. from L
|
||||
transition(L, {GETX, GETS}) {
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(L, Lockdown) {
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
// we could change this to write the data to memory and send it cleanly
|
||||
transition(L, Data_Owner) {
|
||||
r_bounceResponse;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L, Tokens) {
|
||||
r_bounceResponse;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L, Ack_Owner) {
|
||||
s_bounceDatalessOwnerToken;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(L, Unlockdown, NO) {
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
}
|
123
src/mem/protocol/MOESI_CMP_token-msg.sm
Normal file
123
src/mem/protocol/MOESI_CMP_token-msg.sm
Normal file
|
@ -0,0 +1,123 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
}
|
||||
|
||||
// PersistentType
|
||||
enumeration(PersistentRequestType, desc="...") {
|
||||
GETX_PERSISTENT, desc="...";
|
||||
GETS_PERSISTENT, desc="...";
|
||||
DEACTIVATE_PERSISTENT,desc="...";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
DATA_OWNER, desc="Data";
|
||||
ACK_OWNER, desc="data-less owner token";
|
||||
DATA_SHARED, desc="Data";
|
||||
ACK, desc="ACKnowledgment";
|
||||
WB_TOKENS, desc="L1 to L2 writeback";
|
||||
WB_SHARED_DATA, desc="L1 to L2 writeback with data";
|
||||
WB_OWNED, desc="L1 to L2 writeback with data";
|
||||
INV, desc="L1 informing L2 of loss of all tokens";
|
||||
}
|
||||
|
||||
// TriggerType
|
||||
enumeration(TriggerType, desc="...") {
|
||||
REQUEST_TIMEOUT, desc="See corresponding event";
|
||||
USE_TIMEOUT, desc="See corresponding event";
|
||||
}
|
||||
|
||||
// TriggerMsg
|
||||
structure(TriggerMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
TriggerType Type, desc="Type of trigger";
|
||||
}
|
||||
|
||||
// PersistentMsg
|
||||
structure(PersistentMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
PersistentRequestType Type, desc="Type of starvation request";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
MachineType RequestorMachine, desc="Type of machine who requested";
|
||||
NetDest Destination, desc="Destination set";
|
||||
MachineType DestMachine, desc="type of destination component";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
MachineType RequestorMachine, desc="Type of machine who requested";
|
||||
MachineType DestMachine, desc="Type of destination machine";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
bool isLocal, desc="Is this request from a local L1";
|
||||
int RetryNum, desc="retry sequence number";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
MachineType SenderMachine, desc="component that is sending";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
MachineType DestMachine, desc="What component receives the data";
|
||||
int Tokens, desc="Number of tokens being transfered for this line";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
5
src/mem/protocol/MOESI_CMP_token.slicc
Normal file
5
src/mem/protocol/MOESI_CMP_token.slicc
Normal file
|
@ -0,0 +1,5 @@
|
|||
MOESI_CMP_token-msg.sm
|
||||
MOESI_CMP_token-L1cache.sm
|
||||
MOESI_CMP_token-L2cache.sm
|
||||
MOESI_CMP_token-dir.sm
|
||||
standard_CMP-protocol.sm
|
981
src/mem/protocol/MOESI_SMP_directory-cache.sm
Normal file
981
src/mem/protocol/MOESI_SMP_directory-cache.sm
Normal file
|
@ -0,0 +1,981 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
machine(L1Cache, "Directory protocol") {
|
||||
|
||||
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="false";
|
||||
MessageBuffer responseFromCache, network="To", virtual_network="2", ordered="false";
|
||||
MessageBuffer unblockFromCache, network="To", virtual_network="3", ordered="false";
|
||||
|
||||
MessageBuffer forwardToCache, network="From", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseToCache, network="From", virtual_network="2", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||||
// Base states
|
||||
NP, desc="Not Present";
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
O, desc="Owned";
|
||||
E, desc="Exclusive (clean)";
|
||||
M, desc="Modified (dirty)";
|
||||
MM, desc="Modified (dirty and locally modified)";
|
||||
|
||||
// Transient States
|
||||
IM, "IM", desc="Issued GetX";
|
||||
SM, "SM", desc="Issued GetX, we still have an old copy of the line";
|
||||
OM, "OM", desc="Issued GetX, received data";
|
||||
IS, "IS", desc="Issued GetS";
|
||||
OI, "OI", desc="Issued PutO, waiting for ack";
|
||||
MI, "MI", desc="Issued PutX, waiting for ack";
|
||||
II, "II", desc="Issued PutX/O, saw Fwd_GETS or Fwd_GETX, waiting for ack";
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
Load, desc="Load request from the processor";
|
||||
Ifetch, desc="I-fetch request from the processor";
|
||||
Store, desc="Store request from the processor";
|
||||
L2_Replacement, desc="Replacement";
|
||||
L1_to_L2, desc="L1 to L2 transfer";
|
||||
L2_to_L1D, desc="L2 to L1-Data transfer";
|
||||
L2_to_L1I, desc="L2 to L1-Instruction transfer";
|
||||
|
||||
// Requests
|
||||
Own_GETX, desc="We observe our own GetX forwarded back to us";
|
||||
Fwd_GETX, desc="A GetX from another processor";
|
||||
Fwd_GETS, desc="A GetS from another processor";
|
||||
Inv, desc="Invalidations from the directory";
|
||||
|
||||
// Responses
|
||||
Ack, desc="Received an ack message";
|
||||
Data, desc="Received a data message, responder has a shared copy";
|
||||
Exclusive_Data_Clean, desc="Received a data message, no other processor has it, data is clean";
|
||||
Exclusive_Data_Dirty, desc="Received a data message, no other processor has it, data is dirty";
|
||||
|
||||
Writeback_Ack, desc="Writeback O.K. from directory";
|
||||
Writeback_Nack, desc="Writeback not O.K. from directory";
|
||||
|
||||
// Triggers
|
||||
All_acks, desc="Received all required data and message acks";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry") {
|
||||
State CacheState, desc="cache state";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
int NumPendingMsgs, default="0", desc="Number of acks/data messages that this processor is waiting for";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
MessageBuffer mandatoryQueue, abstract_chip_ptr="true", ordered="false";
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||||
CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
|
||||
CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
|
||||
CacheMemory L2cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L2"', abstract_chip_ptr="true";
|
||||
|
||||
Entry getCacheEntry(Address addr), return_by_ref="yes" {
|
||||
if (L2cacheMemory.isTagPresent(addr)) {
|
||||
return L2cacheMemory[addr];
|
||||
} else if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory[addr];
|
||||
} else {
|
||||
return L1IcacheMemory[addr];
|
||||
}
|
||||
}
|
||||
|
||||
void changePermission(Address addr, AccessPermission permission) {
|
||||
if (L2cacheMemory.isTagPresent(addr)) {
|
||||
return L2cacheMemory.changePermission(addr, permission);
|
||||
} else if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory.changePermission(addr, permission);
|
||||
} else {
|
||||
return L1IcacheMemory.changePermission(addr, permission);
|
||||
}
|
||||
}
|
||||
|
||||
bool isCacheTagPresent(Address addr) {
|
||||
return (L2cacheMemory.isTagPresent(addr) || L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
|
||||
}
|
||||
|
||||
State getState(Address addr) {
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
if(TBEs.isPresent(addr)) {
|
||||
return TBEs[addr].TBEState;
|
||||
} else if (isCacheTagPresent(addr)) {
|
||||
return getCacheEntry(addr).CacheState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
if (TBEs.isPresent(addr)) {
|
||||
TBEs[addr].TBEState := state;
|
||||
}
|
||||
|
||||
if (isCacheTagPresent(addr)) {
|
||||
getCacheEntry(addr).CacheState := state;
|
||||
|
||||
if (state == State:E) {
|
||||
assert(getCacheEntry(addr).Dirty == false);
|
||||
}
|
||||
|
||||
if ((state == State:M) || (state == State:MM)) {
|
||||
assert(getCacheEntry(addr).Dirty == true);
|
||||
}
|
||||
|
||||
// Set permission
|
||||
if (state == State:MM) {
|
||||
changePermission(addr, AccessPermission:Read_Write);
|
||||
} else if ((state == State:S) ||
|
||||
(state == State:O) ||
|
||||
(state == State:M) ||
|
||||
(state == State:E) ||
|
||||
(state == State:SM) ||
|
||||
(state == State:OM)) {
|
||||
changePermission(addr, AccessPermission:Read_Only);
|
||||
} else {
|
||||
changePermission(addr, AccessPermission:Invalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event mandatory_request_type_to_event(CacheRequestType type) {
|
||||
if (type == CacheRequestType:LD) {
|
||||
return Event:Load;
|
||||
} else if (type == CacheRequestType:IFETCH) {
|
||||
return Event:Ifetch;
|
||||
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
|
||||
return Event:Store;
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
MessageBuffer triggerQueue, ordered="true";
|
||||
|
||||
// ** OUT_PORTS **
|
||||
|
||||
out_port(requestNetwork_out, RequestMsg, requestFromCache);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromCache);
|
||||
out_port(unblockNetwork_out, ResponseMsg, unblockFromCache);
|
||||
out_port(triggerQueue_out, TriggerMsg, triggerQueue);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
// Trigger Queue
|
||||
in_port(triggerQueue_in, TriggerMsg, triggerQueue) {
|
||||
if (triggerQueue_in.isReady()) {
|
||||
peek(triggerQueue_in, TriggerMsg) {
|
||||
if (in_msg.Type == TriggerType:ALL_ACKS) {
|
||||
trigger(Event:All_acks, in_msg.Address);
|
||||
} else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing from the request network
|
||||
|
||||
// Forward Network
|
||||
in_port(forwardToCache_in, RequestMsg, forwardToCache) {
|
||||
if (forwardToCache_in.isReady()) {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
if (in_msg.Requestor == machineID) {
|
||||
trigger(Event:Own_GETX, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Fwd_GETX, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Fwd_GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:Inv, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
|
||||
trigger(Event:Writeback_Ack, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
|
||||
trigger(Event:Writeback_Nack, in_msg.Address);
|
||||
} else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Response Network
|
||||
in_port(responseToCache_in, ResponseMsg, responseToCache) {
|
||||
if (responseToCache_in.isReady()) {
|
||||
peek(responseToCache_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:ACK) {
|
||||
trigger(Event:Ack, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:DATA) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE_CLEAN) {
|
||||
trigger(Event:Exclusive_Data_Clean, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE_DIRTY) {
|
||||
trigger(Event:Exclusive_Data_Dirty, in_msg.Address);
|
||||
} else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing from the unblock network
|
||||
|
||||
// Mandatory Queue
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
// Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
|
||||
|
||||
if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
// ** INSTRUCTION ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, try to write it to the L2
|
||||
if (L2cacheMemory.cacheAvail(in_msg.Address)) {
|
||||
trigger(Event:L1_to_L2, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1
|
||||
if (L2cacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// L2 has it (maybe not with the right permissions)
|
||||
trigger(Event:L2_to_L1I, in_msg.Address);
|
||||
} else {
|
||||
// We have room, the L2 doesn't have it, so the L1 fetches the line
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
// No room in the L1, so we need to make room
|
||||
if (L2cacheMemory.cacheAvail(L1IcacheMemory.cacheProbe(in_msg.Address))) {
|
||||
// The L2 has room, so we move the line from the L1 to the L2
|
||||
trigger(Event:L1_to_L2, L1IcacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
// The L2 does not have room, so we replace a line from the L2
|
||||
trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.Address)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// *** DATA ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, try to write it to the L2
|
||||
if (L2cacheMemory.cacheAvail(in_msg.Address)) {
|
||||
trigger(Event:L1_to_L2, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1
|
||||
if (L2cacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// L2 has it (maybe not with the right permissions)
|
||||
trigger(Event:L2_to_L1D, in_msg.Address);
|
||||
} else {
|
||||
// We have room, the L2 doesn't have it, so the L1 fetches the line
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
// No room in the L1, so we need to make room
|
||||
if (L2cacheMemory.cacheAvail(L1DcacheMemory.cacheProbe(in_msg.Address))) {
|
||||
// The L2 has room, so we move the line from the L1 to the L2
|
||||
trigger(Event:L1_to_L2, L1DcacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
// The L2 does not have room, so we replace a line from the L2
|
||||
trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.Address)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
|
||||
action(a_issueGETS, "a", desc="Issue GETS") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Request_Control;
|
||||
// TBEs[address].NumPendingMsgs := numberOfNodes(); // One from each other processor (n-1) plus the memory (+1)
|
||||
}
|
||||
}
|
||||
|
||||
action(b_issueGETX, "b", desc="Issue GETX") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="(ISSUE_LATENCY-1)") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Request_Control;
|
||||
// TBEs[address].NumPendingMsgs := numberOfNodes(); // One from each other processor (n-1) plus the memory (+1)
|
||||
}
|
||||
}
|
||||
|
||||
action(d_issuePUTX, "d", desc="Issue PUTX") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(dd_issuePUTO, "\d", desc="Issue PUTO") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTO;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(e_sendData, "e", desc="Send data from cache to requestor") {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := getCacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getCacheEntry(address).Dirty;
|
||||
out_msg.Acks := in_msg.Acks;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE_DIRTY;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := getCacheEntry(address).DataBlk;
|
||||
out_msg.Dirty := getCacheEntry(address).Dirty;
|
||||
out_msg.Acks := in_msg.Acks;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_sendAck, "f", desc="Send ack from cache to requestor") {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.Acks := 0 - 1; // -1
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_sendUnblock, "g", desc="Send unblock to memory") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Unblock_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(gg_sendUnblockExclusive, "\g", desc="Send unblock exclusive to memory") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Unblock_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(h_load_hit, "h", desc="Notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(getCacheEntry(address).DataBlk);
|
||||
sequencer.readCallback(address, getCacheEntry(address).DataBlk);
|
||||
}
|
||||
|
||||
action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(getCacheEntry(address).DataBlk);
|
||||
sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
|
||||
getCacheEntry(address).Dirty := true;
|
||||
}
|
||||
|
||||
action(i_allocateTBE, "i", desc="Allocate TBE") {
|
||||
check_allocate(TBEs);
|
||||
TBEs.allocate(address);
|
||||
TBEs[address].DataBlk := getCacheEntry(address).DataBlk; // Data only used for writebacks
|
||||
TBEs[address].Dirty := getCacheEntry(address).Dirty;
|
||||
}
|
||||
|
||||
action(j_popTriggerQueue, "j", desc="Pop trigger queue.") {
|
||||
triggerQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popForwardQueue, "l", desc="Pop forwareded request queue.") {
|
||||
forwardToCache_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") {
|
||||
peek(responseToCache_in, ResponseMsg) {
|
||||
TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks;
|
||||
}
|
||||
}
|
||||
|
||||
action(mm_decrementNumberOfMessages, "\m", desc="Decrement the number of messages for which we're waiting") {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks;
|
||||
}
|
||||
}
|
||||
|
||||
action(n_popResponseQueue, "n", desc="Pop response queue") {
|
||||
responseToCache_in.dequeue();
|
||||
}
|
||||
|
||||
action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
|
||||
if (TBEs[address].NumPendingMsgs == 0) {
|
||||
enqueue(triggerQueue_out, TriggerMsg) {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := TriggerType:ALL_ACKS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") {
|
||||
peek(forwardToCache_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.Dirty := TBEs[address].Dirty;
|
||||
out_msg.Acks := in_msg.Acks;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qq_sendDataFromTBEToMemory, "\q", desc="Send data from TBE to memory") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.Dirty := TBEs[address].Dirty;
|
||||
if (TBEs[address].Dirty) {
|
||||
out_msg.Type := CoherenceResponseType:WRITEBACK_DIRTY;
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Data;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:WRITEBACK_CLEAN;
|
||||
// NOTE: in a real system this would not send data. We send
|
||||
// data here only so we can check it at the memory
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||||
TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(u_writeDataToCache, "u", desc="Write data to cache") {
|
||||
peek(responseToCache_in, ResponseMsg) {
|
||||
getCacheEntry(address).DataBlk := in_msg.DataBlk;
|
||||
getCacheEntry(address).Dirty := in_msg.Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") {
|
||||
peek(responseToCache_in, ResponseMsg) {
|
||||
assert(getCacheEntry(address).DataBlk == in_msg.DataBlk);
|
||||
getCacheEntry(address).DataBlk := in_msg.DataBlk;
|
||||
getCacheEntry(address).Dirty := in_msg.Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
action(kk_deallocateL1CacheBlock, "\k", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L1DcacheMemory.deallocate(address);
|
||||
} else {
|
||||
L1IcacheMemory.deallocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") {
|
||||
if (L1DcacheMemory.isTagPresent(address) == false) {
|
||||
L1DcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") {
|
||||
if (L1IcacheMemory.isTagPresent(address) == false) {
|
||||
L1IcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") {
|
||||
L2cacheMemory.allocate(address);
|
||||
}
|
||||
|
||||
action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
|
||||
L2cacheMemory.deallocate(address);
|
||||
}
|
||||
|
||||
action(ss_copyFromL1toL2, "\s", desc="Copy data block from L1 (I or D) to L2") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L2cacheMemory[address] := L1DcacheMemory[address];
|
||||
} else {
|
||||
L2cacheMemory[address] := L1IcacheMemory[address];
|
||||
}
|
||||
}
|
||||
|
||||
action(tt_copyFromL2toL1, "\t", desc="Copy data block from L2 to L1 (I or D)") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L1DcacheMemory[address] := L2cacheMemory[address];
|
||||
} else {
|
||||
L1IcacheMemory[address] := L2cacheMemory[address];
|
||||
}
|
||||
}
|
||||
|
||||
action(uu_profileMiss, "\u", desc="Profile the demand miss") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
profile_miss(in_msg, id);
|
||||
}
|
||||
}
|
||||
|
||||
action(zz_recycleMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
|
||||
mandatoryQueue_in.recycle();
|
||||
}
|
||||
|
||||
//*****************************************************
|
||||
// TRANSITIONS
|
||||
//*****************************************************
|
||||
|
||||
// Transitions for Load/Store/L2_Replacement from transient states
|
||||
transition({IM, SM, OM, IS, OI, MI, II}, {Store, L2_Replacement}) {
|
||||
zz_recycleMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({IM, IS, OI, MI, II}, {Load, Ifetch}) {
|
||||
zz_recycleMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({IM, SM, OM, IS, OI, MI, II}, L1_to_L2) {
|
||||
zz_recycleMandatoryQueue;
|
||||
}
|
||||
|
||||
// Transitions moving data between the L1 and L2 caches
|
||||
transition({I, S, O, E, M, MM}, L1_to_L2) {
|
||||
vv_allocateL2CacheBlock;
|
||||
ss_copyFromL1toL2; // Not really needed for state I
|
||||
kk_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition({I, S, O, E, M, MM}, L2_to_L1D) {
|
||||
ii_allocateL1DCacheBlock;
|
||||
tt_copyFromL2toL1; // Not really needed for state I
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition({I, S, O, E, M, MM}, L2_to_L1I) {
|
||||
jj_allocateL1ICacheBlock;
|
||||
tt_copyFromL2toL1; // Not really needed for state I
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP, I}, Load, IS) {
|
||||
ii_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
uu_profileMiss;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Ifetch, IS) {
|
||||
jj_allocateL1ICacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
uu_profileMiss;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Store, IM) {
|
||||
ii_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
uu_profileMiss;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(I, L2_Replacement) {
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition({NP, I}, Inv) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition({S, SM}, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Store, SM) {
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
uu_profileMiss;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, L2_Replacement, I) {
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition(S, Inv, I) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition({O, OM}, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(O, Store, OM) {
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
// p_decrementNumberOfMessagesByOne;
|
||||
uu_profileMiss;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(O, L2_Replacement, OI) {
|
||||
i_allocateTBE;
|
||||
dd_issuePUTO;
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition(O, Fwd_GETX, I) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(O, Fwd_GETS) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from MM
|
||||
transition(MM, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(MM, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(MM, L2_Replacement, MI) {
|
||||
i_allocateTBE;
|
||||
d_issuePUTX;
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition(MM, Fwd_GETX, I) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(MM, Fwd_GETS, I) {
|
||||
ee_sendDataExclusive;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from M
|
||||
transition({E, M}, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({E, M}, Store, MM) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({E, M}, L2_Replacement, MI) {
|
||||
i_allocateTBE;
|
||||
d_issuePUTX;
|
||||
rr_deallocateL2CacheBlock;
|
||||
}
|
||||
|
||||
transition({E, M}, Fwd_GETX, I) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition({E, M}, Fwd_GETS, O) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM
|
||||
|
||||
transition(IM, Inv) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(IM, Ack) {
|
||||
m_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data, OM) {
|
||||
u_writeDataToCache;
|
||||
m_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from SM
|
||||
transition(SM, Inv, IM) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(SM, Ack) {
|
||||
m_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(SM, Data, OM) {
|
||||
v_writeDataToCacheVerify;
|
||||
m_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from OM
|
||||
transition(OM, Own_GETX) {
|
||||
mm_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(OM, Fwd_GETX, IM) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(OM, Fwd_GETS, OM) {
|
||||
e_sendData;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(OM, Ack) {
|
||||
m_decrementNumberOfMessages;
|
||||
o_checkForCompletion;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(OM, All_acks, MM) {
|
||||
hh_store_hit;
|
||||
gg_sendUnblockExclusive;
|
||||
s_deallocateTBE;
|
||||
j_popTriggerQueue;
|
||||
}
|
||||
|
||||
// Transitions from IS
|
||||
|
||||
transition(IS, Inv) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data, S) {
|
||||
u_writeDataToCache;
|
||||
m_decrementNumberOfMessages;
|
||||
h_load_hit;
|
||||
g_sendUnblock;
|
||||
s_deallocateTBE;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Data_Clean, E) {
|
||||
u_writeDataToCache;
|
||||
m_decrementNumberOfMessages;
|
||||
h_load_hit;
|
||||
gg_sendUnblockExclusive;
|
||||
s_deallocateTBE;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Data_Dirty, M) {
|
||||
u_writeDataToCache;
|
||||
m_decrementNumberOfMessages;
|
||||
h_load_hit;
|
||||
gg_sendUnblockExclusive;
|
||||
s_deallocateTBE;
|
||||
n_popResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from OI/MI
|
||||
|
||||
transition(MI, Fwd_GETS) {
|
||||
q_sendDataFromTBEToCache;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(MI, Fwd_GETX, II) {
|
||||
q_sendDataFromTBEToCache;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(OI, Fwd_GETS) {
|
||||
q_sendDataFromTBEToCache;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(OI, Fwd_GETX, II) {
|
||||
q_sendDataFromTBEToCache;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition({OI, MI}, Writeback_Ack, I) {
|
||||
qq_sendDataFromTBEToMemory;
|
||||
s_deallocateTBE;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(MI, Writeback_Nack, OI) {
|
||||
// FIXME: This might cause deadlock by re-using the writeback
|
||||
// channel, we should handle this case differently.
|
||||
dd_issuePUTO;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
// Transitions from II
|
||||
transition(II, Writeback_Ack, I) {
|
||||
g_sendUnblock;
|
||||
s_deallocateTBE;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(II, Writeback_Nack, I) {
|
||||
s_deallocateTBE;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
|
||||
transition(II, Inv) {
|
||||
f_sendAck;
|
||||
l_popForwardQueue;
|
||||
}
|
||||
}
|
||||
|
495
src/mem/protocol/MOESI_SMP_directory-dir.sm
Normal file
495
src/mem/protocol/MOESI_SMP_directory-dir.sm
Normal file
|
@ -0,0 +1,495 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
machine(Directory, "Directory protocol") {
|
||||
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false";
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="0", ordered="false";
|
||||
MessageBuffer unblockToDir, network="From", virtual_network="3", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Invalid";
|
||||
S, desc="Shared";
|
||||
O, desc="Owner";
|
||||
M, desc="Modified";
|
||||
|
||||
IS, desc="Blocked, was in idle";
|
||||
SS, desc="Blocked, was in shared";
|
||||
OO, desc="Blocked, was in owned";
|
||||
MO, desc="Blocked, going to owner or maybe modified";
|
||||
MM, desc="Blocked, going to modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
OS, desc="Blocked on a writeback";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
PUTX, desc="A PUTX arrives";
|
||||
PUTO, desc="A PUTO arrives";
|
||||
Unblock, desc="An unblock message arrives";
|
||||
Last_Unblock, desc="An unblock message arrives, we're not waiting for any additional unblocks";
|
||||
Exclusive_Unblock, desc="The processor become the exclusive owner (E or M) of the line";
|
||||
Clean_Writeback, desc="The final message as part of a PutX/PutS, no data";
|
||||
Dirty_Writeback, desc="The final message as part of a PutX/PutS, contains data";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
NetDest Sharers, desc="Sharers for this block";
|
||||
NetDest Owner, desc="Owner of this block";
|
||||
int WaitingUnblocks, desc="Number of acks we're waiting for";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// External function
|
||||
void profile_sharing(Address addr, AccessType type, NodeID requestor, Set sharers, Set owner);
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
||||
if ((state == State:I) || (state == State:IS)) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if ((state == State:S) || (state == State:SS)) {
|
||||
assert(directory[addr].Owner.count() == 0);
|
||||
assert(directory[addr].Sharers.count() != 0);
|
||||
}
|
||||
|
||||
if ((state == State:O) || (state == State:OO)) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.isSuperset(directory[addr].Owner) == false);
|
||||
}
|
||||
|
||||
if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
||||
if ((state != State:SS) && (state != State:OO)) {
|
||||
assert(directory[addr].WaitingUnblocks == 0);
|
||||
}
|
||||
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(unblockNetwork_in, ResponseMsg, unblockToDir) {
|
||||
if (unblockNetwork_in.isReady()) {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
|
||||
if (directory[in_msg.Address].WaitingUnblocks == 1) {
|
||||
trigger(Event:Last_Unblock, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Unblock, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) {
|
||||
trigger(Event:Exclusive_Unblock, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY) {
|
||||
trigger(Event:Dirty_Writeback, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN) {
|
||||
trigger(Event:Clean_Writeback, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
trigger(Event:PUTX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTO) {
|
||||
trigger(Event:PUTO, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_NACK;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_clearOwner, "c", desc="Clear the owner field") {
|
||||
directory[address].Owner.clear();
|
||||
}
|
||||
|
||||
action(cc_clearSharers, "\c", desc="Clear the sharers field") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
|
||||
if (in_msg.Type == CoherenceRequestType:GETS && directory[address].Sharers.count() == 0) {
|
||||
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE_CLEAN;
|
||||
} else {
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
}
|
||||
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false; // By definition, the block is now clean
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(e_ownerIsUnblocker, "e", desc="The owner is now the unblocker") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Owner.clear();
|
||||
directory[address].Owner.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(f_forwardRequest, "f", desc="Forward request to owner") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination := directory[in_msg.Address].Owner;
|
||||
out_msg.Acks := directory[address].Sharers.count();
|
||||
if (directory[address].Sharers.isElement(in_msg.Requestor)) {
|
||||
out_msg.Acks := out_msg.Acks - 1;
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_sendInvalidations, "g", desc="Send invalidations to sharers, not including the requester") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if ((directory[in_msg.Address].Sharers.count() > 1) ||
|
||||
((directory[in_msg.Address].Sharers.count() > 0) && (directory[in_msg.Address].Sharers.isElement(in_msg.Requestor) == false))) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination := directory[in_msg.Address].Sharers;
|
||||
out_msg.Destination.remove(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
|
||||
// Profile the request
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
// profile_sharing(address, AccessType:Write, machineIDToNodeID(in_msg.Requestor), directory[address].Sharers, directory[address].Owner);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
// profile_sharing(address, AccessType:Read, machineIDToNodeID(in_msg.Requestor), directory[address].Sharers, directory[address].Owner);
|
||||
}
|
||||
}
|
||||
|
||||
requestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popIncomingUnblockQueue, "j", desc="Pop incoming unblock queue") {
|
||||
unblockNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(ll_checkDataInMemory, "\l", desc="Check PUTX/PUTO data is same as in the memory") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(m_addUnlockerToSharers, "m", desc="Add the unlocker to the sharer list") {
|
||||
peek(unblockNetwork_in, ResponseMsg) {
|
||||
directory[address].Sharers.add(in_msg.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_incrementOutstanding, "n", desc="Increment outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks + 1;
|
||||
}
|
||||
|
||||
action(o_decrementOutstanding, "o", desc="Decrement outstanding requests") {
|
||||
directory[address].WaitingUnblocks := directory[address].WaitingUnblocks - 1;
|
||||
assert(directory[address].WaitingUnblocks >= 0);
|
||||
}
|
||||
|
||||
// action(z_stall, "z", desc="Cannot be handled right now.") {
|
||||
// Special name recognized as do nothing case
|
||||
// }
|
||||
|
||||
action(zz_recycleRequest, "\z", desc="Recycle the request queue") {
|
||||
requestQueue_in.recycle();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, MM) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX, MM) {
|
||||
d_sendData;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETS, IS) {
|
||||
d_sendData;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETS, SS) {
|
||||
d_sendData;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S, M}, PUTO) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({I, S, O}, PUTX) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
g_sendInvalidations;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({O, OO}, GETS, OO) {
|
||||
f_forwardRequest;
|
||||
n_incrementOutstanding;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX, MM) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETS, MO) {
|
||||
f_forwardRequest;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX, MI) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTO, OS) {
|
||||
a_sendWriteBackAck;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({MM, MO, MI, OS}, {GETS, GETX, PUTO, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition({MM, MO}, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MO, Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition({IS, SS, OO}, {GETX, PUTO, PUTX}) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, GETS) {
|
||||
zz_recycleRequest;
|
||||
}
|
||||
|
||||
transition(IS, Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(IS, Exclusive_Unblock, M) {
|
||||
cc_clearSharers;
|
||||
e_ownerIsUnblocker;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(SS, Last_Unblock, S) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Unblock) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OO, Last_Unblock, O) {
|
||||
m_addUnlockerToSharers;
|
||||
o_decrementOutstanding;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Dirty_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Dirty_Writeback, S) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Clean_Writeback, I) {
|
||||
c_clearOwner;
|
||||
cc_clearSharers;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Clean_Writeback, S) {
|
||||
c_clearOwner;
|
||||
ll_checkDataInMemory;
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(MI, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
transition(OS, Unblock, O) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
}
|
89
src/mem/protocol/MOESI_SMP_directory-msg.sm
Normal file
89
src/mem/protocol/MOESI_SMP_directory-msg.sm
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
PUTX, desc="Put eXclusive";
|
||||
PUTO, desc="Put Owned";
|
||||
WB_ACK, desc="Writeback ack";
|
||||
WB_NACK, desc="Writeback neg. ack";
|
||||
INV, desc="Invalidation";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
ACK, desc="ACKnowledgment, responder doesn't have a copy";
|
||||
DATA, desc="Data";
|
||||
DATA_EXCLUSIVE_CLEAN, desc="Data, no other processor has a copy, data is clean";
|
||||
DATA_EXCLUSIVE_DIRTY, desc="Data, no other processor has a copy, data is dirty";
|
||||
UNBLOCK, desc="Unblock";
|
||||
UNBLOCK_EXCLUSIVE, desc="Unblock, we're in E/M";
|
||||
WRITEBACK_CLEAN, desc="Clean writeback (no data)";
|
||||
WRITEBACK_DIRTY, desc="Dirty writeback (contains data)";
|
||||
}
|
||||
|
||||
// TriggerType
|
||||
enumeration(TriggerType, desc="...") {
|
||||
ALL_ACKS, desc="See corresponding event";
|
||||
}
|
||||
|
||||
// TriggerMsg
|
||||
structure(TriggerMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
TriggerType Type, desc="Type of trigger";
|
||||
}
|
||||
|
||||
// RequestMsg (and also forwarded requests)
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
int Acks, desc="How many acks to expect";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// ResponseMsg (and also unblock requests)
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
int Acks, desc="How many acks to expect";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
4
src/mem/protocol/MOESI_SMP_directory.slicc
Normal file
4
src/mem/protocol/MOESI_SMP_directory.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOESI_SMP_directory-msg.sm
|
||||
MOESI_SMP_directory-cache.sm
|
||||
MOESI_SMP_directory-dir.sm
|
||||
standard_SMP-protocol.sm
|
1734
src/mem/protocol/MOESI_SMP_token-cache.sm
Normal file
1734
src/mem/protocol/MOESI_SMP_token-cache.sm
Normal file
File diff suppressed because it is too large
Load diff
405
src/mem/protocol/MOESI_SMP_token-dir.sm
Normal file
405
src/mem/protocol/MOESI_SMP_token-dir.sm
Normal file
|
@ -0,0 +1,405 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOESI_token-dir.sm 1.5 04/11/17 14:07:50-06:00 mikem@emperor15.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
machine(Directory, "Token protocol") {
|
||||
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="0", ordered="false";
|
||||
|
||||
MessageBuffer responseToDir, network="From", virtual_network="0", ordered="false";
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false";
|
||||
MessageBuffer persistentToDir, network="From", virtual_network="2", ordered="true";
|
||||
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_O") {
|
||||
// Base states
|
||||
O, desc="Owner";
|
||||
NO, desc="Not Owner";
|
||||
L, desc="Locked";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETX, desc="A GETX arrives";
|
||||
GETS, desc="A GETS arrives";
|
||||
Lockdown, desc="A lockdown request arrives";
|
||||
Unlockdown, desc="An un-lockdown request arrives";
|
||||
Data_Owner, desc="Data arrive, includes the owner token";
|
||||
Data_Shared, desc="Data arrive, does not include the owner token";
|
||||
Ack, desc="Tokens arrive";
|
||||
Ack_Owner, desc="Tokens arrive, including the owner token";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
int Tokens, default="max_tokens()", desc="Number of tokens for the line we're holding";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
PersistentTable persistentTable, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
directory[addr].DirectoryState := state;
|
||||
|
||||
if (state == State:L) {
|
||||
assert(directory[addr].Tokens == 0);
|
||||
}
|
||||
|
||||
// Make sure the token count is in range
|
||||
assert(directory[addr].Tokens >= 0);
|
||||
assert(directory[addr].Tokens <= max_tokens());
|
||||
|
||||
if (state == State:O) {
|
||||
assert(directory[addr].Tokens >= 1); // Must have at least one token
|
||||
assert(directory[addr].Tokens >= (max_tokens() / 2)); // Only mostly true; this might not always hold
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(persistentNetwork_in, PersistentMsg, persistentToDir) {
|
||||
if (persistentNetwork_in.isReady()) {
|
||||
peek(persistentNetwork_in, PersistentMsg) {
|
||||
|
||||
// Apply the lockdown or unlockdown message to the table
|
||||
if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) {
|
||||
persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Write);
|
||||
} else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) {
|
||||
persistentTable.persistentRequestLock(in_msg.Address, in_msg.Requestor, AccessType:Read);
|
||||
} else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) {
|
||||
persistentTable.persistentRequestUnlock(in_msg.Address, in_msg.Requestor);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
|
||||
// React to the message based on the current state of the table
|
||||
if (persistentTable.isLocked(in_msg.Address)) {
|
||||
trigger(Event:Lockdown, in_msg.Address); // locked
|
||||
} else {
|
||||
trigger(Event:Unlockdown, in_msg.Address); // unlocked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToDir) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
if (in_msg.Type == CoherenceResponseType:DATA_OWNER) {
|
||||
trigger(Event:Data_Owner, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:ACK) {
|
||||
trigger(Event:Ack, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) {
|
||||
trigger(Event:Data_Shared, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) {
|
||||
trigger(Event:Ack_Owner, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
action(a_sendTokens, "a", desc="Send tokens to requestor") {
|
||||
// Only send a message if we have tokens to send
|
||||
if (directory[address].Tokens > 0) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.Tokens := directory[in_msg.Address].Tokens;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
}
|
||||
|
||||
action(aa_sendTokensToStarver, "\a", desc="Send tokens to starver") {
|
||||
// Only send a message if we have tokens to send
|
||||
if (directory[address].Tokens > 0) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.Tokens := directory[address].Tokens;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Control;
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(d_sendDataWithAllTokens, "d", desc="Send data and tokens to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
assert(directory[address].Tokens > 0);
|
||||
out_msg.Tokens := directory[in_msg.Address].Tokens;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
|
||||
action(dd_sendDataWithAllTokensToStarver, "\d", desc="Send data and tokens to starver") {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
assert(directory[address].Tokens > 0);
|
||||
out_msg.Tokens := directory[address].Tokens;
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
directory[address].Tokens := 0;
|
||||
}
|
||||
|
||||
action(f_incrementTokens, "f", desc="Increment the number of tokens we're tracking") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Tokens >= 1);
|
||||
directory[address].Tokens := directory[address].Tokens + in_msg.Tokens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popIncomingResponseQueue, "k", desc="Pop incoming response queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popIncomingPersistentQueue, "l", desc="Pop incoming persistent queue") {
|
||||
persistentNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_writeDataToMemory, "m", desc="Write dirty writeback to memory") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_checkIncomingMsg, "n", desc="Check incoming token message") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Type == CoherenceResponseType:ACK_OWNER);
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(r_bounceResponse, "r", desc="Bounce response to starving processor") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.Tokens := in_msg.Tokens;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := in_msg.Dirty;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(s_bounceDatalessOwnerToken, "s", desc="Bounce clean owner token to starving processor") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
assert(in_msg.Type == CoherenceResponseType:ACK_OWNER);
|
||||
assert(in_msg.Dirty == false);
|
||||
assert(in_msg.MessageSize == MessageSizeType:Writeback_Control);
|
||||
|
||||
// NOTE: The following check would not be valid in a real
|
||||
// implementation. We include the data in the "dataless"
|
||||
// message so we can assert the clean data matches the datablock
|
||||
// in memory
|
||||
assert(directory[in_msg.Address].DataBlk == in_msg.DataBlk);
|
||||
|
||||
// Bounce the message, but "re-associate" the data and the owner
|
||||
// token. In essence we're converting an ACK_OWNER message to a
|
||||
// DATA_OWNER message, keeping the number of tokens the same.
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA_OWNER;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
out_msg.Destination.add(persistentTable.findSmallest(address));
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.Tokens := in_msg.Tokens;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.Dirty := in_msg.Dirty;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
// Trans. from O
|
||||
transition(O, GETX, NO) {
|
||||
d_sendDataWithAllTokens;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, GETS, NO) {
|
||||
d_sendDataWithAllTokens;
|
||||
// Since we found the owner, no need to forward
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, Lockdown, L) {
|
||||
dd_sendDataWithAllTokensToStarver;
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
transition(O, {Data_Shared, Ack}) {
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Trans. from NO
|
||||
transition(NO, GETX) {
|
||||
a_sendTokens;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(NO, GETS) {
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(NO, Lockdown, L) {
|
||||
aa_sendTokensToStarver;
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
transition(NO, Data_Owner, O) {
|
||||
m_writeDataToMemory;
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(NO, Ack_Owner, O) {
|
||||
n_checkIncomingMsg;
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(NO, {Data_Shared, Ack}) {
|
||||
f_incrementTokens;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Trans. from L
|
||||
transition(L, {GETX, GETS}) {
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(L, Lockdown) {
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
transition(L, {Data_Owner, Data_Shared, Ack}) {
|
||||
r_bounceResponse;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L, Ack_Owner) {
|
||||
s_bounceDatalessOwnerToken;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L, Unlockdown, NO) {
|
||||
l_popIncomingPersistentQueue;
|
||||
}
|
||||
|
||||
}
|
61
src/mem/protocol/MOESI_SMP_token-msg.sm
Normal file
61
src/mem/protocol/MOESI_SMP_token-msg.sm
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* $Id: MOESI_token-msg.sm 1.3 04/06/05 22:43:20-00:00 kmoore@cottons.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
//int max_tokens();
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
}
|
||||
|
||||
// StarvationType
|
||||
enumeration(PersistentRequestType, desc="...") {
|
||||
GETX_PERSISTENT, desc="...";
|
||||
GETS_PERSISTENT, desc="...";
|
||||
DEACTIVATE_PERSISTENT, desc="...";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
DATA_OWNER, desc="Data, with the owner token";
|
||||
DATA_SHARED, desc="Data, without the owner token";
|
||||
ACK, desc="ACKnowledgment";
|
||||
ACK_OWNER, desc="ACKnowledgment, includes the clean owner token";
|
||||
}
|
||||
|
||||
// StarvationMsg
|
||||
structure(PersistentMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
PersistentRequestType Type, desc="Type of starvation request";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Destination set";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
MachineType DestMachine, desc="What component receives the data";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
MachineType SenderMachine, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
MachineType DestMachine, desc="What component receives the data";
|
||||
int Tokens, desc="Number of tokens being transfered for this line";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
bool Dirty, desc="Is the data dirty (different than memory)?";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
4
src/mem/protocol/MOESI_SMP_token.slicc
Normal file
4
src/mem/protocol/MOESI_SMP_token.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOESI_SMP_token-msg.sm
|
||||
MOESI_SMP_token-cache.sm
|
||||
MOESI_SMP_token-dir.sm
|
||||
standard_SMP-protocol.sm
|
1000
src/mem/protocol/MOSI_SMP_bcast-cache.sm
Normal file
1000
src/mem/protocol/MOSI_SMP_bcast-cache.sm
Normal file
File diff suppressed because it is too large
Load diff
267
src/mem/protocol/MOSI_SMP_bcast-dir.sm
Normal file
267
src/mem/protocol/MOSI_SMP_bcast-dir.sm
Normal file
|
@ -0,0 +1,267 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
machine(Directory, "MOSI Broadcast Optimized") {
|
||||
|
||||
|
||||
MessageBuffer addressFromDir, network="To", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataFromDir, network="To", virtual_network="1", ordered="false";
|
||||
|
||||
MessageBuffer addressToDir, network="From", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataToDir, network="From", virtual_network="1", ordered="false";
|
||||
|
||||
|
||||
enumeration(State, desc="Directory states", default="Directory_State_C") {
|
||||
C, desc="Cold - no processor has requested this line";
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
SS, desc="Shared, 2 or more shares";
|
||||
OS, desc="Owned by a cache";
|
||||
OSS, desc="Owned by a cache, present in at least 3 caches";
|
||||
M, desc="Modified", format="!b";
|
||||
}
|
||||
|
||||
// ** EVENTS **
|
||||
|
||||
enumeration(Event, desc="Directory events") {
|
||||
// From Address network
|
||||
OtherAddress, desc="We saw an address msg to someone else";
|
||||
GETS, desc="A GETS arrives";
|
||||
GET_INSTR, desc="A GETInstr arrives";
|
||||
GETX, desc="A GETX arrives", format="!r";
|
||||
PUTX_Owner, desc="A PUTX arrives, requestor is owner";
|
||||
PUTX_NotOwner, desc="A PUTX arrives, requestor is not owner", format="!r";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
bool DirOwner, default="true", desc="Is dir owner?";
|
||||
MachineID ProcOwner, desc="Processor Owner";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
void profile_request(int cache_state, State directory_state, GenericRequestType request_type);
|
||||
|
||||
State getState(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
return State:C;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
|
||||
out_port(dataNetwork_out, DataMsg, dataFromDir);
|
||||
out_port(addressNetwork_out, AddressMsg, addressFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
// Address Network
|
||||
in_port(addressNetwork_in, AddressMsg, addressToDir) {
|
||||
if (addressNetwork_in.isReady()) {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
if(map_Address_to_Directory(in_msg.Address) != machineID) {
|
||||
trigger(Event:OtherAddress, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
trigger(Event:GET_INSTR, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (in_msg.Requestor == directory[in_msg.Address].ProcOwner && directory[in_msg.Address].DirOwner == false) {
|
||||
trigger(Event:PUTX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:PUTX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
error("unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *** ACTIONS ***
|
||||
|
||||
action(d_sendDataMsg, "d", desc="Send data message to requestor") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
enqueue(dataNetwork_out, DataMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := in_msg.Address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
DEBUG_EXPR(in_msg.Requestor);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popAddressQueue, "j", desc="Pop address queue.") {
|
||||
addressNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(p_profile, "p", desc="Profile this transition.") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
profile_request(in_msg.CacheState, getState(address), convertToGenericType(in_msg.Type));
|
||||
}
|
||||
}
|
||||
|
||||
action(m_setOwnerRequestor, "m", desc="Set owner = requestor") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].ProcOwner := in_msg.Requestor;
|
||||
directory[in_msg.Address].DirOwner := false;
|
||||
}
|
||||
}
|
||||
|
||||
action(r_writeDataFromRequest, "r", desc="Write request data to memory") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(x_setOwnerToDirectory, "x", desc="Set owner equal to the directory"){
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].DirOwner := true;
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
// Ignore all address and data messages not bound for us
|
||||
transition(C, OtherAddress) {
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// PUTX_NotOwner Transitions
|
||||
transition({I, S, SS, OS, OSS, M}, PUTX_NotOwner) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({C, I}, {GETS,GET_INSTR}, S) {
|
||||
d_sendDataMsg;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({C, I}, GETX, M) {
|
||||
d_sendDataMsg;
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition({S, SS}, {GETS,GET_INSTR}, SS) {
|
||||
d_sendDataMsg;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETX, M) {
|
||||
d_sendDataMsg;
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition({OS, OSS}, {GETS,GET_INSTR}, OSS) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({OS, OSS}, GETX, M) {
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OS, PUTX_Owner, S) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OSS, PUTX_Owner, SS) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {GETS,GET_INSTR}, OS) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX) {
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_Owner, I) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
}
|
79
src/mem/protocol/MOSI_SMP_bcast-msg.sm
Normal file
79
src/mem/protocol/MOSI_SMP_bcast-msg.sm
Normal file
|
@ -0,0 +1,79 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
GETS, desc="Get Shared";
|
||||
GETX, desc="Get eXclusive";
|
||||
PUTX, desc="Put eXclusive";
|
||||
}
|
||||
|
||||
// AddressMsg
|
||||
structure(AddressMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
int CacheState, default="1000", desc="Hack to transfer the cache's state for profiling"; // The default of 1000 will generate an error if we forget to set this
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
DataBlock DataBlk, desc="data for the cache line"; // This is used for PutX and Downgrades only
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// DataMsg
|
||||
structure(DataMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
// MachineType SenderType, desc="Component who sent data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
MachineType DestMachine, desc="What component receives the data";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
||||
|
4
src/mem/protocol/MOSI_SMP_bcast.slicc
Normal file
4
src/mem/protocol/MOSI_SMP_bcast.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOSI_SMP_bcast-msg.sm
|
||||
MOSI_SMP_bcast-cache.sm
|
||||
MOSI_SMP_bcast-dir.sm
|
||||
standard_SMP-protocol.sm
|
921
src/mem/protocol/MOSI_SMP_bcast_1level-cache.sm
Normal file
921
src/mem/protocol/MOSI_SMP_bcast_1level-cache.sm
Normal file
|
@ -0,0 +1,921 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
machine(L1Cache, "MOSI Broadcast Optimized") {
|
||||
|
||||
MessageBuffer addressFromCache, network="To", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataFromCache, network="To", virtual_network="1", ordered="false";
|
||||
|
||||
MessageBuffer addressToCache, network="From", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataToCache, network="From", virtual_network="1", ordered="false";
|
||||
|
||||
// STATES
|
||||
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||||
NP, desc="Not Present";
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
O, desc="Owned";
|
||||
M, desc="Modified", format="!b";
|
||||
IS_AD, "IS^AD", desc="idle, issued GETS, have not seen GETS or data yet";
|
||||
IM_AD, "IM^AD", desc="idle, issued GETX, have not seen GETX or data yet";
|
||||
SM_AD, "SM^AD",desc="shared, issued GETX, have not seen GETX or data yet";
|
||||
OM_A, "OM^A",desc="owned, issued GETX, have not seen GETX yet", format="!b";
|
||||
|
||||
IS_A, "IS^A",desc="idle, issued GETS, have not seen GETS, have seen data";
|
||||
IM_A, "IM^A",desc="idle, issued GETX, have not seen GETX, have seen data";
|
||||
SM_A, "SM^A",desc="shared, issued GETX, have not seen GETX, have seen data", format="!b";
|
||||
|
||||
MI_A, "MI^A", desc="modified, issued PUTX, have not seen PUTX yet";
|
||||
OI_A, "OI^A", desc="owned, issued PUTX, have not seen PUTX yet";
|
||||
II_A, "II^A", desc="modified, issued PUTX, have not seen PUTX, then saw other GETX", format="!b";
|
||||
|
||||
IS_D, "IS^D", desc="idle, issued GETS, have seen GETS, have not seen data yet";
|
||||
IS_D_I, "IS^D^I", desc="idle, issued GETS, have seen GETS, have not seen data, then saw other GETX";
|
||||
IM_D, "IM^D", desc="idle, issued GETX, have seen GETX, have not seen data yet";
|
||||
IM_D_O, "IM^D^O", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETS";
|
||||
IM_D_I, "IM^D^I", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETX";
|
||||
IM_D_OI, "IM^D^OI", desc="idle, issued GETX, have seen GETX, have not seen data yet, then saw other GETS, then saw other GETX";
|
||||
SM_D, "SM^D", desc="shared, issued GETX, have seen GETX, have not seen data yet";
|
||||
SM_D_O, "SM^D^O", desc="shared, issued GETX, have seen GETX, have not seen data yet, then saw other GETS";
|
||||
}
|
||||
|
||||
// ** EVENTS **
|
||||
|
||||
enumeration(Event, desc="Cache events") {
|
||||
// From processor
|
||||
Load, desc="Load request from the processor";
|
||||
Ifetch, desc="I-fetch request from the processor";
|
||||
Store, desc="Store request from the processor";
|
||||
Replacement, desc="Replacement";
|
||||
Load_prefetch, desc="Read only prefetch";
|
||||
Store_prefetch, desc="Read write prefetch", format="!r";
|
||||
|
||||
// From Address network
|
||||
Own_GETS, desc="Occurs when we observe our own GETS request in the global order";
|
||||
Own_GET_INSTR, desc="Occurs when we observe our own GETInstr request in the global order";
|
||||
Own_GETX, desc="Occurs when we observe our own GETX request in the global order";
|
||||
Own_PUTX, desc="Occurs when we observe our own PUTX request in the global order", format="!r";
|
||||
Other_GETS, desc="Occurs when we observe a GETS request from another processor";
|
||||
Other_GET_INSTR, desc="Occurs when we observe a GETInstr request from another processor";
|
||||
Other_GETX, desc="Occurs when we observe a GETX request from another processor";
|
||||
Other_PUTX, desc="Occurs when we observe a PUTX request from another processor", format="!r";
|
||||
|
||||
// From Data network
|
||||
Data, desc="Data for this block from the data network";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry") {
|
||||
State CacheState, desc="cache state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
Address Address, desc="Physical address for this TBE";
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="Buffer for the data block";
|
||||
NetDest ForwardIDs, desc="IDs of the processors to forward the block";
|
||||
Address ForwardAddress, desc="Address of request for forwarding";
|
||||
bool isPrefetch, desc="Set if this request is a prefetch";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
|
||||
MessageBuffer optionalQueue, ordered="true", abstract_chip_ptr="true";
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
|
||||
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||||
CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_unified"', abstract_chip_ptr="true";
|
||||
|
||||
int cache_state_to_int(State state);
|
||||
|
||||
State getState(Address addr) {
|
||||
if(TBEs.isPresent(addr)) {
|
||||
return TBEs[addr].TBEState;
|
||||
} else if (cacheMemory.isTagPresent(addr)) {
|
||||
return cacheMemory[addr].CacheState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (TBEs.isPresent(addr)) {
|
||||
TBEs[addr].TBEState := state;
|
||||
}
|
||||
if (cacheMemory.isTagPresent(addr)) {
|
||||
cacheMemory[addr].CacheState := state;
|
||||
|
||||
// Set permission
|
||||
if ((state == State:I) || (state == State:MI_A) || (state == State:II_A)) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Invalid);
|
||||
} else if (state == State:S || state == State:O) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Read_Only);
|
||||
} else if (state == State:M) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
|
||||
out_port(dataNetwork_out, DataMsg, dataFromCache);
|
||||
out_port(addressNetwork_out, AddressMsg, addressFromCache);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
// Data Network
|
||||
in_port(dataNetwork_in, DataMsg, dataToCache) {
|
||||
if (dataNetwork_in.isReady()) {
|
||||
peek(dataNetwork_in, DataMsg) {
|
||||
trigger(Event:Data, in_msg.Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Address Network
|
||||
in_port(addressNetwork_in, AddressMsg, addressToCache) {
|
||||
if (addressNetwork_in.isReady()) {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
if (in_msg.Requestor == machineID) {
|
||||
trigger(Event:Own_GETS, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Other_GETS, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
if (in_msg.Requestor == machineID) {
|
||||
trigger(Event:Own_GETX, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Other_GETX, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
if (in_msg.Requestor == machineID) {
|
||||
trigger(Event:Own_GET_INSTR, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Other_GET_INSTR, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (in_msg.Requestor == machineID) {
|
||||
trigger(Event:Own_PUTX, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Other_PUTX, in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
if (in_msg.Type == CacheRequestType:LD) {
|
||||
trigger(Event:Load, in_msg.Address);
|
||||
} else if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
trigger(Event:Ifetch, in_msg.Address);
|
||||
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||||
trigger(Event:Store, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional Queue
|
||||
in_port(optionalQueue_in, CacheMsg, optionalQueue, desc="...") {
|
||||
if (optionalQueue_in.isReady()) {
|
||||
peek(optionalQueue_in, CacheMsg) {
|
||||
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
if ((in_msg.Type == CacheRequestType:LD) || (in_msg.Type == CacheRequestType:IFETCH)) {
|
||||
trigger(Event:Load_prefetch, in_msg.Address);
|
||||
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||||
trigger(Event:Store_prefetch, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
action(a_allocateTBE, "a", desc="Allocate TBE with Address=B, ForwardID=null, RetryCount=zero, ForwardIDRetryCount=zero, ForwardProgressBit=unset.") {
|
||||
check_allocate(TBEs);
|
||||
TBEs.allocate(address);
|
||||
TBEs[address].isPrefetch := false;
|
||||
TBEs[address].ForwardIDs.clear();
|
||||
|
||||
// Keep the TBE state consistent with the cache state
|
||||
if (cacheMemory.isTagPresent(address)) {
|
||||
TBEs[address].TBEState := cacheMemory[address].CacheState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(b_setPrefetchBit, "b", desc="Set prefetch bit in TBE.") {
|
||||
TBEs[address].isPrefetch := true;
|
||||
}
|
||||
|
||||
action(c_allocateCacheBlock, "c", desc="Set cache tag equal to tag of block B.") {
|
||||
if (cacheMemory.isTagPresent(address) == false) {
|
||||
cacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(d_deallocateTBE, "d", desc="Deallocate TBE.") {
|
||||
TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(e_recordForwardingInfo, "e", desc="Record ID of other processor in ForwardID.") {
|
||||
peek(addressNetwork_in, AddressMsg){
|
||||
TBEs[address].ForwardIDs.add(in_msg.Requestor);
|
||||
TBEs[address].ForwardAddress := in_msg.Address;
|
||||
}
|
||||
}
|
||||
|
||||
action(f_issueGETS, "f", desc="Issue GETS.") {
|
||||
enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.CacheState := cache_state_to_int(getState(address));
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.broadcast(MachineType:L1Cache);
|
||||
out_msg.Destination.add(map_Address_to_Directory(address)); // To memory
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(g_issueGETX, "g", desc="Issue GETX.") {
|
||||
enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.CacheState := cache_state_to_int(getState(address));
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.broadcast(MachineType:L1Cache);
|
||||
out_msg.Destination.add(map_Address_to_Directory(address)); // To memory
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||||
// Non-prefetch
|
||||
sequencer.readCallback(address, cacheMemory[address].DataBlk);
|
||||
} else {
|
||||
// Prefetch - don't call back
|
||||
}
|
||||
}
|
||||
|
||||
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||||
// Non-prefetch
|
||||
sequencer.writeCallback(address, cacheMemory[address].DataBlk);
|
||||
} else {
|
||||
// Prefetch - don't call back
|
||||
}
|
||||
}
|
||||
|
||||
action(i_popAddressQueue, "i", desc="Pop incoming address queue.") {
|
||||
addressNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(j_popDataQueue, "j", desc="Pop incoming data queue.") {
|
||||
dataNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popOptionalQueue, "l", desc="Pop optional queue.") {
|
||||
optionalQueue_in.dequeue();
|
||||
}
|
||||
|
||||
|
||||
action(o_cacheToForward, "o", desc="Send data from the cache to the processor indicated by ForwardIDs.") {
|
||||
peek(dataNetwork_in, DataMsg){
|
||||
// This has a CACHE_RESPONSE_LATENCY latency because we want to avoid the
|
||||
// timing strangeness that can occur if requests that source the
|
||||
// data from the TBE are faster than data sourced from the cache
|
||||
enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY"){
|
||||
out_msg.Address := TBEs[address].ForwardAddress;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.Destination := TBEs[address].ForwardIDs;
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(p_issuePUTX, "p", desc="Issue PUTX.") {
|
||||
enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.CacheState := cache_state_to_int(getState(address));
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address)); // To memory
|
||||
out_msg.Destination.add(machineID); // Back to us
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(q_writeDataFromCacheToTBE, "q", desc="Write data from the cache into the TBE.") {
|
||||
TBEs[address].DataBlk := cacheMemory[address].DataBlk;
|
||||
DEBUG_EXPR(TBEs[address].DataBlk);
|
||||
}
|
||||
|
||||
action(r_cacheToRequestor, "r", desc="Send data from the cache to the requestor") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action(s_saveDataInTBE, "s", desc="Save data in data field of TBE.") {
|
||||
peek(dataNetwork_in, DataMsg) {
|
||||
TBEs[address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(TBEs[address].DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(t_issueGET_INSTR, "t", desc="Issue GETInstr.") {
|
||||
enqueue(addressNetwork_out, AddressMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GET_INSTR;
|
||||
out_msg.CacheState := cache_state_to_int(getState(address));
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.broadcast(MachineType:L1Cache);
|
||||
out_msg.Destination.add(map_Address_to_Directory(address)); // To memory
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(w_writeDataFromTBEToCache, "w", desc="Write data from the TBE into the cache.") {
|
||||
cacheMemory[address].DataBlk := TBEs[address].DataBlk;
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
}
|
||||
|
||||
action(y_tbeToReq, "y", desc="Send data from the TBE to the requestor.") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
enqueue(dataNetwork_out, DataMsg, latency="CACHE_RESPONSE_LATENCY") { // Either this or the PutX should have a real latency
|
||||
out_msg.Address := address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(ff_deallocateCacheBlock, "\f", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
|
||||
cacheMemory.deallocate(address);
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="Cannot be handled right now.") {
|
||||
// Special name recognized as do nothing case
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP, I}, Load, IS_AD) {
|
||||
f_issueGETS;
|
||||
c_allocateCacheBlock;
|
||||
a_allocateTBE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Ifetch, IS_AD) {
|
||||
t_issueGET_INSTR;
|
||||
c_allocateCacheBlock;
|
||||
a_allocateTBE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Load_prefetch, IS_AD) {
|
||||
f_issueGETS;
|
||||
c_allocateCacheBlock;
|
||||
a_allocateTBE;
|
||||
b_setPrefetchBit;
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Store, IM_AD) {
|
||||
g_issueGETX;
|
||||
c_allocateCacheBlock;
|
||||
a_allocateTBE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP, I}, Store_prefetch, IM_AD) {
|
||||
g_issueGETX;
|
||||
c_allocateCacheBlock;
|
||||
a_allocateTBE;
|
||||
b_setPrefetchBit;
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(I, Replacement) {
|
||||
ff_deallocateCacheBlock; // the cache line is now in NotPresent
|
||||
}
|
||||
|
||||
transition({NP, I}, { Other_GETS, Other_GET_INSTR, Other_GETX } ) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition(S, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Load_prefetch) {
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(S, Store, SM_AD) {
|
||||
g_issueGETX;
|
||||
a_allocateTBE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Store_prefetch, IM_AD) {
|
||||
g_issueGETX;
|
||||
a_allocateTBE;
|
||||
b_setPrefetchBit; // Must be after allocate TBE
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(S, Replacement, I) {
|
||||
ff_deallocateCacheBlock; // the cache line is now in NotPresent
|
||||
}
|
||||
|
||||
transition(S, {Other_GETS, Other_GET_INSTR}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(S, Other_GETX, I) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition(O, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(O, Store, OM_A){
|
||||
g_issueGETX;
|
||||
a_allocateTBE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(O, Load_prefetch) {
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(O, Store_prefetch, OM_A) {
|
||||
g_issueGETX;
|
||||
a_allocateTBE;
|
||||
b_setPrefetchBit;
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(O, Replacement, OI_A) {
|
||||
p_issuePUTX;
|
||||
a_allocateTBE;
|
||||
q_writeDataFromCacheToTBE;// the cache line is now empty
|
||||
ff_deallocateCacheBlock; // the cache line is now in NotPresent
|
||||
}
|
||||
|
||||
transition(O, {Other_GETS,Other_GET_INSTR}) {
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(O, Other_GETX, I) {
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, {Load_prefetch,Store_prefetch}) {
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(M, Replacement, MI_A) {
|
||||
p_issuePUTX;
|
||||
a_allocateTBE;
|
||||
q_writeDataFromCacheToTBE;// the cache line is now empty
|
||||
ff_deallocateCacheBlock; // the cache line is now in NotPresent
|
||||
}
|
||||
|
||||
transition(M, {Other_GETS,Other_GET_INSTR}, O) {
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(M, Other_GETX, I) {
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions for Load/Store/Replacement from transient states
|
||||
|
||||
transition({IS_AD, IM_AD, IS_A, IM_A, SM_AD, OM_A, SM_A, IS_D, IS_D_I, IM_D, IM_D_O, IM_D_I, IM_D_OI, SM_D, SM_D_O}, {Load, Ifetch, Store, Replacement}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition({IS_AD, IM_AD, IS_A, IM_A, SM_AD, OM_A, SM_A, IS_D, IM_D, IM_D_O, SM_D, SM_D_O}, Load_prefetch) {
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition({IS_D_I, IM_D_I, IM_D_OI}, Load_prefetch) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition({IM_AD, SM_AD, OM_A, IM_A, SM_A, IM_D, SM_D}, Store_prefetch) {
|
||||
l_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition({IS_AD, IS_A, IS_D, IS_D_I, IM_D_O, IM_D_I, IM_D_OI, SM_D_O}, Store_prefetch) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition({MI_A, OI_A, II_A}, {Load, Ifetch, Store, Load_prefetch, Store_prefetch, Replacement}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
// Always ignore PUTXs which we are not the owner of
|
||||
transition({NP, I, S, O, M, IS_AD, IM_AD, SM_AD, OM_A, IS_A, IM_A, SM_A, MI_A, OI_A, II_A, IS_D, IS_D_I, IM_D, IM_D_O, IM_D_I, IM_D_OI, SM_D, SM_D_O }, Other_PUTX) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// transitions from IS_AD
|
||||
|
||||
transition(IS_AD, {Own_GETS,Own_GET_INSTR}, IS_D) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_AD, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_AD, Data, IS_A) {
|
||||
s_saveDataInTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from IM_AD
|
||||
|
||||
transition(IM_AD, Own_GETX, IM_D) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IM_AD, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IM_AD, Data, IM_A) {
|
||||
s_saveDataInTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
// Transitions from OM_A
|
||||
|
||||
transition(OM_A, Own_GETX, M){
|
||||
hh_store_hit;
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OM_A, {Other_GETS, Other_GET_INSTR}){
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OM_A, Other_GETX, IM_AD){
|
||||
r_cacheToRequestor;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OM_A, Data, IM_A) { // if we get data, we know we're going to lose block before we see own GETX
|
||||
s_saveDataInTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
// Transitions from SM_AD
|
||||
|
||||
transition(SM_AD, Own_GETX, SM_D) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(SM_AD, {Other_GETS,Other_GET_INSTR}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(SM_AD, Other_GETX, IM_AD) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(SM_AD, Data, SM_A) {
|
||||
s_saveDataInTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from IS_A
|
||||
|
||||
transition(IS_A, {Own_GETS,Own_GET_INSTR}, S) {
|
||||
w_writeDataFromTBEToCache;
|
||||
h_load_hit;
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM_A
|
||||
|
||||
transition(IM_A, Own_GETX, M) {
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IM_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from SM_A
|
||||
|
||||
transition(SM_A, Own_GETX, M) {
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(SM_A, {Other_GETS,Other_GET_INSTR}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(SM_A, Other_GETX, IM_A) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from MI_A
|
||||
|
||||
transition(MI_A, Own_PUTX, I) {
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(MI_A, {Other_GETS, Other_GET_INSTR}) {
|
||||
y_tbeToReq;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(MI_A, Other_GETX, II_A) {
|
||||
y_tbeToReq;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from OI_A
|
||||
|
||||
transition(OI_A, Own_PUTX, I) {
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OI_A, {Other_GETS, Other_GET_INSTR}) {
|
||||
y_tbeToReq;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OI_A, Other_GETX, II_A) {
|
||||
y_tbeToReq;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from II_A
|
||||
|
||||
transition(II_A, Own_PUTX, I) {
|
||||
d_deallocateTBE;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(II_A, {Other_GETS, Other_GET_INSTR, Other_GETX}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from IS_D, IS_D_I
|
||||
|
||||
transition({IS_D, IS_D_I}, {Other_GETS,Other_GET_INSTR}) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_D, Other_GETX, IS_D_I) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_D_I, Other_GETX) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
transition(IS_D, Data, S) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
h_load_hit;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
transition(IS_D_I, Data, I) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
h_load_hit;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM_D, IM_D_O, IM_D_I, IM_D_OI
|
||||
|
||||
transition( IM_D, {Other_GETS,Other_GET_INSTR}, IM_D_O ) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition( IM_D, Other_GETX, IM_D_I ) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(IM_D_O, {Other_GETS,Other_GET_INSTR} ) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(IM_D_O, Other_GETX, IM_D_OI) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition( {IM_D_I, IM_D_OI}, {Other_GETS, Other_GET_INSTR, Other_GETX} ) {
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(IM_D, Data, M) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
transition(IM_D_O, Data, O) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
o_cacheToForward;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
transition(IM_D_I, Data, I) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
o_cacheToForward;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
transition(IM_D_OI, Data, I) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
o_cacheToForward;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
// Transitions for SM_D, SM_D_O
|
||||
|
||||
transition(SM_D, {Other_GETS,Other_GET_INSTR}, SM_D_O) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(SM_D, Other_GETX, IM_D_I) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(SM_D_O, {Other_GETS,Other_GET_INSTR}) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(SM_D_O, Other_GETX, IM_D_OI) {
|
||||
e_recordForwardingInfo;
|
||||
i_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(SM_D, Data, M) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
transition(SM_D_O, Data, O) {
|
||||
s_saveDataInTBE;
|
||||
w_writeDataFromTBEToCache;
|
||||
hh_store_hit;
|
||||
o_cacheToForward;
|
||||
d_deallocateTBE;
|
||||
j_popDataQueue;
|
||||
}
|
||||
|
||||
}
|
4
src/mem/protocol/MOSI_SMP_bcast_1level.slicc
Normal file
4
src/mem/protocol/MOSI_SMP_bcast_1level.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOSI_SMP_bcast-msg.sm
|
||||
MOSI_SMP_bcast_1level-cache.sm
|
||||
MOSI_SMP_bcast-dir.sm
|
||||
standard_1level_SMP-protocol.sm
|
345
src/mem/protocol/MOSI_SMP_bcast_m-dir.sm
Normal file
345
src/mem/protocol/MOSI_SMP_bcast_m-dir.sm
Normal file
|
@ -0,0 +1,345 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
machine(Directory, "MOSI Broadcast Optimized") {
|
||||
|
||||
|
||||
MessageBuffer addressFromDir, network="To", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataFromDir, network="To", virtual_network="1", ordered="false";
|
||||
|
||||
MessageBuffer addressToDir, network="From", virtual_network="0", ordered="true";
|
||||
MessageBuffer dataToDir, network="From", virtual_network="1", ordered="false";
|
||||
|
||||
|
||||
enumeration(State, desc="Directory states", default="Directory_State_C") {
|
||||
C, desc="Cold - no processor has requested this line";
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
SS, desc="Shared, 2 or more shares";
|
||||
OS, desc="Owned by a cache";
|
||||
OSS, desc="Owned by a cache, present in at least 3 caches";
|
||||
M, desc="Modified", format="!b";
|
||||
}
|
||||
|
||||
// ** EVENTS **
|
||||
|
||||
enumeration(Event, desc="Directory events") {
|
||||
// From Address network
|
||||
OtherAddress, desc="We saw an address msg to someone else";
|
||||
GETS, desc="A GETS arrives";
|
||||
GET_INSTR, desc="A GETInstr arrives";
|
||||
GETX, desc="A GETX arrives", format="!r";
|
||||
PUTX_Owner, desc="A PUTX arrives, requestor is owner";
|
||||
PUTX_NotOwner, desc="A PUTX arrives, requestor is not owner", format="!r";
|
||||
Memory_Data, desc="Fetched data from memory arrives";
|
||||
Memory_Ack, desc="Writeback Ack from memory arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
bool DirOwner, default="true", desc="Is dir owner?";
|
||||
MachineID ProcOwner, desc="Processor Owner";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// to simulate detailed DRAM
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
MemoryControl memBuffer, constructor_hack="i";
|
||||
|
||||
void profile_request(int cache_state, State directory_state, GenericRequestType request_type);
|
||||
|
||||
State getState(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
return State:C;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
|
||||
out_port(dataNetwork_out, DataMsg, dataFromDir);
|
||||
out_port(addressNetwork_out, AddressMsg, addressFromDir);
|
||||
out_port(memQueue_out, MemoryMsg, memBuffer);
|
||||
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
// Address Network
|
||||
in_port(addressNetwork_in, AddressMsg, addressToDir) {
|
||||
if (addressNetwork_in.isReady()) {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
if(map_Address_to_Directory(in_msg.Address) != machineID) {
|
||||
trigger(Event:OtherAddress, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
trigger(Event:GET_INSTR, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (in_msg.Requestor == directory[in_msg.Address].ProcOwner && directory[in_msg.Address].DirOwner == false) {
|
||||
trigger(Event:PUTX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:PUTX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
error("unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// off-chip memory request/response is done
|
||||
in_port(memQueue_in, MemoryMsg, memBuffer) {
|
||||
if (memQueue_in.isReady()) {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
|
||||
trigger(Event:Memory_Data, in_msg.Address);
|
||||
} else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
|
||||
trigger(Event:Memory_Ack, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *** ACTIONS ***
|
||||
|
||||
action(d_sendDataMsg, "d", desc="Send data message to requestor") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(dataNetwork_out, DataMsg, latency="1") {
|
||||
out_msg.Address := in_msg.Address;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
//out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
DEBUG_EXPR(in_msg.OriginalRequestorMachId);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(j_popAddressQueue, "j", desc="Pop address queue.") {
|
||||
addressNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
|
||||
memQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(p_profile, "p", desc="Profile this transition.") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
profile_request(in_msg.CacheState, getState(address), convertToGenericType(in_msg.Type));
|
||||
}
|
||||
}
|
||||
|
||||
action(m_setOwnerRequestor, "m", desc="Set owner = requestor") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].ProcOwner := in_msg.Requestor;
|
||||
directory[in_msg.Address].DirOwner := false;
|
||||
}
|
||||
}
|
||||
|
||||
action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="1") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(r_writeDataFromRequest, "r", desc="Write request data to memory") {
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(x_setOwnerToDirectory, "x", desc="Set owner equal to the directory"){
|
||||
peek(addressNetwork_in, AddressMsg) {
|
||||
directory[in_msg.Address].DirOwner := true;
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
// Ignore all address and data messages not bound for us
|
||||
transition(C, OtherAddress) {
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// PUTX_NotOwner Transitions
|
||||
transition({I, S, SS, OS, OSS, M}, PUTX_NotOwner) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({C, I}, {GETS,GET_INSTR}, S) {
|
||||
//d_sendDataMsg;
|
||||
qf_queueMemoryFetchRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({C, I}, GETX, M) {
|
||||
//d_sendDataMsg;
|
||||
qf_queueMemoryFetchRequest;
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition({S, SS}, {GETS,GET_INSTR}, SS) {
|
||||
//d_sendDataMsg;
|
||||
qf_queueMemoryFetchRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({S, SS}, GETX, M) {
|
||||
//d_sendDataMsg;
|
||||
qf_queueMemoryFetchRequest;
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition({OS, OSS}, {GETS,GET_INSTR}, OSS) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({OS, OSS}, GETX, M) {
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OS, PUTX_Owner, S) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
qw_queueMemoryWBRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(OSS, PUTX_Owner, SS) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
qw_queueMemoryWBRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {GETS,GET_INSTR}, OS) {
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX) {
|
||||
m_setOwnerRequestor;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_Owner, I) {
|
||||
x_setOwnerToDirectory;
|
||||
r_writeDataFromRequest;
|
||||
qw_queueMemoryWBRequest;
|
||||
p_profile;
|
||||
j_popAddressQueue;
|
||||
}
|
||||
|
||||
transition({C, I, S, SS, OS, OSS, M}, Memory_Data) {
|
||||
d_sendDataMsg;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition({C, I, S, SS, OS, OSS, M}, Memory_Ack) {
|
||||
//a_sendAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
}
|
4
src/mem/protocol/MOSI_SMP_bcast_m.slicc
Normal file
4
src/mem/protocol/MOSI_SMP_bcast_m.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOSI_SMP_bcast-msg.sm
|
||||
MOSI_SMP_bcast-cache.sm
|
||||
MOSI_SMP_bcast_m-dir.sm
|
||||
standard_SMP-protocol.sm
|
838
src/mem/protocol/MOSI_SMP_directory_1level-cache.sm
Normal file
838
src/mem/protocol/MOSI_SMP_directory_1level-cache.sm
Normal file
|
@ -0,0 +1,838 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOSI_directory_1level-cache.sm 1.18 04/09/07 13:52:52-05:00 mikem@maya.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
machine(L1Cache, "MOSI Directory Optimized") {
|
||||
|
||||
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="false";
|
||||
MessageBuffer responseFromCache, network="To", virtual_network="2", ordered="false";
|
||||
|
||||
MessageBuffer forwardedRequestToCache, network="From", virtual_network="1", ordered="true";
|
||||
MessageBuffer responseToCache, network="From", virtual_network="2", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_I") {
|
||||
// Base states
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
O, desc="Owned";
|
||||
M, desc="Modified", format="!b";
|
||||
|
||||
// Transient States
|
||||
MI, desc="modified, issued PUTX, have not seen response yet";
|
||||
OI, desc="owned, issued PUTX, have not seen response yet";
|
||||
|
||||
IS, desc="idle, issued GETS, have not seen response yet";
|
||||
ISI, desc="idle, issued GETS, saw INV, have not seen data for GETS yet", format="!b";
|
||||
|
||||
IM, desc="idle, issued GETX, have not seen response yet";
|
||||
IMI, desc="idle, issued GETX, saw forwarded GETX";
|
||||
IMO, desc="idle, issued GETX, saw forwarded GETS";
|
||||
IMOI, desc="idle, issued GETX, saw forwarded GETS, saw forwarded GETX";
|
||||
|
||||
// Note: OM is a strange state, because it is waiting for the line
|
||||
// to be stolen away, or look like it has been stolen away. The
|
||||
// common case is that we see a forward from the directory that is
|
||||
// really from us, we forwarded the data to our dataqueue, and
|
||||
// everythings works fine.
|
||||
|
||||
OM, desc="owned, issued GETX, have not seen response yet";
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
Load, desc="Load request from the processor";
|
||||
Load_prefetch, desc="Load prefetch request from the processor";
|
||||
Ifetch, desc="I-fetch request from the processor";
|
||||
Store_prefetch, desc="Store prefetch request from the processor";
|
||||
Store, desc="Store request from the processor";
|
||||
Replacement, desc="Replacement", format="!r";
|
||||
|
||||
Forwarded_GETS, "Forwarded GETS", desc="Directory forwards GETS to us";
|
||||
Forwarded_GETX, "Forwarded GETX", desc="Directory forwards GETX to us";
|
||||
INV, "INV", desc="Invalidation", format="!r";
|
||||
|
||||
Proc_ack, "Proc ack", desc="Ack from proc";
|
||||
Proc_last_ack, "Proc last ack", desc="Last ack", format="!r";
|
||||
|
||||
Data_ack_0, "Data ack 0", desc="Data with ack count = 0";
|
||||
Data_ack_not_0, "Data ack not 0", desc="Data with ack count != 0 (but haven't seen all acks first";
|
||||
Data_ack_not_0_last, "Data ack not 0 last", desc="Data with ack count != 0 after having received all acks";
|
||||
|
||||
Dir_WB_ack, "WB ack", desc="Writeback ack from dir";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry") {
|
||||
State CacheState, desc="cache state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
Address Address, desc="Physical address for this TBE";
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="Buffer for the data block";
|
||||
int NumPendingAcks, desc="Number of acks that this processor is waiting for";
|
||||
NetDest ForwardGetS_IDs, desc="Set of the processors to forward the block";
|
||||
MachineID ForwardGetX_ID, desc="ID of the processor to forward the block";
|
||||
int ForwardGetX_AckCount, desc="Number of acks the GetX we are forwarded needs";
|
||||
bool isPrefetch, desc="Set if this was caused by a prefetch";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
|
||||
MessageBuffer optionalQueue, ordered="false", abstract_chip_ptr="true";
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
StoreBuffer storeBuffer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||||
CacheMemory cacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_unified L1"', abstract_chip_ptr="true";
|
||||
|
||||
State getState(Address addr) {
|
||||
if(TBEs.isPresent(addr)) {
|
||||
return TBEs[addr].TBEState;
|
||||
} else if (cacheMemory.isTagPresent(addr)) {
|
||||
return cacheMemory[addr].CacheState;
|
||||
}
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (TBEs.isPresent(addr)) {
|
||||
TBEs[addr].TBEState := state;
|
||||
}
|
||||
if (cacheMemory.isTagPresent(addr)) {
|
||||
cacheMemory[addr].CacheState := state;
|
||||
|
||||
// Set permission
|
||||
if ((state == State:I) || (state == State:MI) || (state == State:OI)) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Invalid);
|
||||
} else if (state == State:S || state == State:O) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Read_Only);
|
||||
} else if (state == State:M) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
|
||||
out_port(requestNetwork_out, RequestMsg, requestFromCache);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromCache);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
// Response Network
|
||||
in_port(responseNetwork_in, ResponseMsg, responseToCache) {
|
||||
if (responseNetwork_in.isReady()) {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
if(in_msg.Type == CoherenceResponseType:DATA) {
|
||||
if(in_msg.NumPendingAcks == 0) {
|
||||
trigger(Event:Data_ack_0, in_msg.Address);
|
||||
} else {
|
||||
if(in_msg.NumPendingAcks + TBEs[in_msg.Address].NumPendingAcks != 0) {
|
||||
trigger(Event:Data_ack_not_0, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Data_ack_not_0_last, in_msg.Address);
|
||||
}
|
||||
}
|
||||
} else if(in_msg.Type == CoherenceResponseType:ACK) {
|
||||
if(TBEs[in_msg.Address].NumPendingAcks != 1){
|
||||
trigger(Event:Proc_ack, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:Proc_last_ack, in_msg.Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Forwarded Request network
|
||||
in_port(forwardedRequestNetwork_in, RequestMsg, forwardedRequestToCache) {
|
||||
if(forwardedRequestNetwork_in.isReady()) {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
if(in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:Forwarded_GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
trigger(Event:Forwarded_GETX, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:INV, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
|
||||
trigger(Event:Dir_WB_ack, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid forwarded request type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
if (in_msg.Type == CacheRequestType:LD) {
|
||||
trigger(Event:Load, in_msg.Address);
|
||||
} else if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
trigger(Event:Ifetch, in_msg.Address);
|
||||
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||||
trigger(Event:Store, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional Queue
|
||||
in_port(optionalQueue_in, CacheMsg, optionalQueue, desc="...") {
|
||||
if (optionalQueue_in.isReady()) {
|
||||
peek(optionalQueue_in, CacheMsg) {
|
||||
if (cacheMemory.cacheAvail(in_msg.Address) == false) {
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
} else {
|
||||
if (in_msg.Type == CacheRequestType:LD) {
|
||||
trigger(Event:Load_prefetch, in_msg.Address);
|
||||
} else if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
trigger(Event:Load_prefetch, in_msg.Address);
|
||||
} else if ((in_msg.Type == CacheRequestType:ST) || (in_msg.Type == CacheRequestType:ATOMIC)) {
|
||||
trigger(Event:Store_prefetch, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
|
||||
action(a_issueGETS, "a", desc="Issue GETS") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(b_issueGETX, "b", desc="Issue GETX") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(d_issuePUTX, "d", desc="Issue PUTX") {
|
||||
enqueue(requestNetwork_out, RequestMsg, latency="ISSUE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(e_dataFromCacheToRequestor, "e", desc="Send data from cache to requestor") {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="CACHE_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:L1Cache;
|
||||
out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state O and we see a GetX
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(g_allocateCacheBlock, "g", desc="Allocate cache block") {
|
||||
if (cacheMemory.isTagPresent(address) == false) {
|
||||
cacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||||
// Non-prefetch
|
||||
sequencer.readCallback(address, cacheMemory[address].DataBlk);
|
||||
} else {
|
||||
// Prefetch - don't call back
|
||||
}
|
||||
}
|
||||
|
||||
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(cacheMemory[address].DataBlk);
|
||||
if((TBEs.isPresent(address) == false) || (TBEs[address].isPrefetch == false)) {
|
||||
// Non-prefetch
|
||||
sequencer.writeCallback(address, cacheMemory[address].DataBlk);
|
||||
} else {
|
||||
// Prefetch - don't call back
|
||||
}
|
||||
}
|
||||
|
||||
action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
|
||||
check_allocate(TBEs);
|
||||
TBEs.allocate(address);
|
||||
TBEs[address].NumPendingAcks := 0; // default value
|
||||
TBEs[address].isPrefetch := false;
|
||||
TBEs[address].ForwardGetS_IDs.clear();
|
||||
}
|
||||
|
||||
action(j_setPrefetchBit, "j", desc="Set prefetch bit") {
|
||||
TBEs[address].isPrefetch := true;
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popForwardedRequestQueue, "l", desc="Pop incoming forwarded request queue") {
|
||||
forwardedRequestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(m_popOptionalQueue, "m", desc="Pop optional queue") {
|
||||
optionalQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(p_addNumberOfPendingAcks, "p", desc="Add number of pending acks to TBE") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||||
TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks + in_msg.NumPendingAcks;
|
||||
DEBUG_EXPR(in_msg.NumPendingAcks);
|
||||
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||||
}
|
||||
}
|
||||
|
||||
action(q_decrementNumberOfPendingAcks, "q", desc="Decrement number of pending invalidations by one") {
|
||||
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||||
TBEs[address].NumPendingAcks := TBEs[address].NumPendingAcks - 1;
|
||||
DEBUG_EXPR(TBEs[address].NumPendingAcks);
|
||||
}
|
||||
|
||||
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||||
TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(t_sendAckToInvalidator, "t", desc="Send ack to invalidator") {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:L1Cache;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.NumPendingAcks := 0;
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(u_writeDataToCache, "u", desc="Write data to cache") {
|
||||
peek(responseNetwork_in, ResponseMsg) {
|
||||
cacheMemory[address].DataBlk := in_msg.DataBlk;
|
||||
}
|
||||
}
|
||||
|
||||
action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") {
|
||||
TBEs[address].DataBlk := cacheMemory[address].DataBlk;
|
||||
}
|
||||
|
||||
action(y_dataFromTBEToRequestor, "y", desc="Send data from TBE to requestor") {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:L1Cache;
|
||||
out_msg.NumPendingAcks := in_msg.NumPendingAcks; // Needed when in state MS and we see a GetX
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.DataBlk := TBEs[address].DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="Stall") {
|
||||
}
|
||||
|
||||
action(dd_recordGetSForwardID, "\d", desc="Record forwarded GetS for future forwarding") {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
TBEs[address].ForwardGetS_IDs.add(in_msg.Requestor);
|
||||
}
|
||||
}
|
||||
|
||||
action(ee_dataFromCacheToGetSForwardIDs, "\e", desc="Send data from cache to GetS ForwardIDs") {
|
||||
// FIXME - In some cases this should be from the TBE, not the cache.
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:L1Cache;
|
||||
out_msg.Destination := TBEs[address].ForwardGetS_IDs;
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.NumPendingAcks := 0;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(ff_deallocateCacheBlock, "\f", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") {
|
||||
cacheMemory.deallocate(address);
|
||||
}
|
||||
|
||||
action(gg_dataFromCacheToGetXForwardID, "\g", desc="Send data from cache to GetX ForwardID") {
|
||||
// FIXME - In some cases this should be from the TBE, not the cache.
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="NULL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:L1Cache;
|
||||
out_msg.Destination.add(TBEs[address].ForwardGetX_ID);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.DataBlk := cacheMemory[address].DataBlk;
|
||||
out_msg.NumPendingAcks := TBEs[address].ForwardGetX_AckCount;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(ii_recordGetXForwardID, "\i", desc="Record forwarded GetX and ack count for future forwarding") {
|
||||
peek(forwardedRequestNetwork_in, RequestMsg) {
|
||||
TBEs[address].ForwardGetX_ID := in_msg.Requestor;
|
||||
TBEs[address].ForwardGetX_AckCount := in_msg.NumPendingAcks;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************
|
||||
// TRANSITIONS
|
||||
//*****************************************************
|
||||
|
||||
// Transitions for Load/Store/Prefetch/Replacement from transient states
|
||||
transition({OM, OI, IS, ISI, IM, IMO, IMOI, IMI, MI}, {Load, Load_prefetch, Ifetch, Store, Store_prefetch, Replacement}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition(I, {Load,Ifetch}, IS) {
|
||||
g_allocateCacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(I, {Load_prefetch}, IS) {
|
||||
g_allocateCacheBlock;
|
||||
i_allocateTBE;
|
||||
j_setPrefetchBit;
|
||||
a_issueGETS;
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(I, Store, IM) {
|
||||
g_allocateCacheBlock;
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(I, Store_prefetch, IM) {
|
||||
g_allocateCacheBlock;
|
||||
i_allocateTBE;
|
||||
j_setPrefetchBit;
|
||||
b_issueGETX;
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(I, Replacement) {
|
||||
ff_deallocateCacheBlock;
|
||||
}
|
||||
|
||||
transition(I, INV) {
|
||||
t_sendAckToInvalidator;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition({S, O}, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({S, O, M}, Load_prefetch) {
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(S, Store, IM) {
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(S, Store_prefetch, IM) {
|
||||
i_allocateTBE;
|
||||
j_setPrefetchBit;
|
||||
b_issueGETX;
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(S, Replacement, I) {
|
||||
ff_deallocateCacheBlock;
|
||||
}
|
||||
|
||||
transition(S, INV, I) {
|
||||
t_sendAckToInvalidator;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(M, Store_prefetch) {
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(M, Replacement, MI) {
|
||||
i_allocateTBE;
|
||||
d_issuePUTX;
|
||||
x_copyDataFromCacheToTBE;
|
||||
ff_deallocateCacheBlock;
|
||||
}
|
||||
|
||||
transition(M, Forwarded_GETS, O) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, Forwarded_GETX, I) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from O
|
||||
transition(O, Store, OM) {
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(O, Store_prefetch, OM) {
|
||||
i_allocateTBE;
|
||||
j_setPrefetchBit;
|
||||
b_issueGETX;
|
||||
m_popOptionalQueue;
|
||||
}
|
||||
|
||||
transition(O, Replacement, OI){
|
||||
i_allocateTBE;
|
||||
d_issuePUTX;
|
||||
x_copyDataFromCacheToTBE;
|
||||
ff_deallocateCacheBlock;
|
||||
}
|
||||
|
||||
transition(O, Forwarded_GETS) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, Forwarded_GETX, I) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// transitions from OI
|
||||
|
||||
transition(OI, Forwarded_GETS) {
|
||||
y_dataFromTBEToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(OI, Forwarded_GETX) {
|
||||
y_dataFromTBEToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(OI, Dir_WB_ack, I) {
|
||||
s_deallocateTBE;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from IS
|
||||
|
||||
transition(IS, INV, ISI) {
|
||||
t_sendAckToInvalidator;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(IS, Data_ack_0, S) {
|
||||
u_writeDataToCache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from ISI
|
||||
|
||||
// in ISI, could get data from the Proc whose GETX caused INV to go from IS to ISI
|
||||
// or, could get data from Dir if Dir's data lost race to Dir's INV
|
||||
// or, could get data from Dir, if my GETS took forever to get to Dir, and the GETX
|
||||
// processor already wrote it back
|
||||
|
||||
transition(ISI, Data_ack_0, I) {
|
||||
u_writeDataToCache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(ISI, INV) {
|
||||
t_sendAckToInvalidator;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from IM
|
||||
|
||||
transition(IM, INV) { // do not need to go to IMI, since INV is for earlier epoch
|
||||
t_sendAckToInvalidator;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition({IM, IMO}, Forwarded_GETS, IMO) {
|
||||
dd_recordGetSForwardID;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(IM, Forwarded_GETX, IMI) {
|
||||
ii_recordGetXForwardID;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(IM, {Data_ack_0, Data_ack_not_0_last}, M) {
|
||||
u_writeDataToCache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Data_ack_not_0) {
|
||||
u_writeDataToCache;
|
||||
p_addNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Proc_ack) {
|
||||
q_decrementNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IM, Proc_last_ack, M) {
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from IMO
|
||||
|
||||
transition(IMO, Forwarded_GETX, IMOI) {
|
||||
ii_recordGetXForwardID;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(IMO, {Data_ack_0, Data_ack_not_0_last}, O) {
|
||||
u_writeDataToCache;
|
||||
hh_store_hit;
|
||||
ee_dataFromCacheToGetSForwardIDs;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMO, Data_ack_not_0) {
|
||||
u_writeDataToCache;
|
||||
p_addNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMO, Proc_ack) {
|
||||
q_decrementNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMO, Proc_last_ack, O) {
|
||||
hh_store_hit;
|
||||
ee_dataFromCacheToGetSForwardIDs;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from IMI
|
||||
|
||||
transition(IMI, {Data_ack_0, Data_ack_not_0_last}, I) {
|
||||
u_writeDataToCache;
|
||||
hh_store_hit;
|
||||
gg_dataFromCacheToGetXForwardID;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMI, Data_ack_not_0) {
|
||||
u_writeDataToCache;
|
||||
p_addNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMI, Proc_ack) {
|
||||
q_decrementNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMI, Proc_last_ack, I) {
|
||||
hh_store_hit;
|
||||
gg_dataFromCacheToGetXForwardID;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// transitions from IMOI
|
||||
|
||||
transition(IMOI, {Data_ack_0, Data_ack_not_0_last}, I) {
|
||||
u_writeDataToCache;
|
||||
hh_store_hit;
|
||||
ee_dataFromCacheToGetSForwardIDs;
|
||||
gg_dataFromCacheToGetXForwardID;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMOI, Data_ack_not_0) {
|
||||
u_writeDataToCache;
|
||||
p_addNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMOI, Proc_ack) {
|
||||
q_decrementNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(IMOI, Proc_last_ack, I) {
|
||||
hh_store_hit;
|
||||
ee_dataFromCacheToGetSForwardIDs;
|
||||
gg_dataFromCacheToGetXForwardID;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from OM
|
||||
transition(OM, Proc_ack) {
|
||||
q_decrementNumberOfPendingAcks;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(OM, Forwarded_GETS) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(OM, Forwarded_GETX, IM) {
|
||||
e_dataFromCacheToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from MI
|
||||
|
||||
transition(MI, Forwarded_GETS) {
|
||||
y_dataFromTBEToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(MI, Forwarded_GETX) {
|
||||
y_dataFromTBEToRequestor;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(MI, Dir_WB_ack, I) {
|
||||
s_deallocateTBE;
|
||||
l_popForwardedRequestQueue;
|
||||
}
|
||||
}
|
333
src/mem/protocol/MOSI_SMP_directory_1level-dir.sm
Normal file
333
src/mem/protocol/MOSI_SMP_directory_1level-dir.sm
Normal file
|
@ -0,0 +1,333 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOSI_directory-dir.sm 1.14 04/09/07 13:52:52-05:00 mikem@maya.cs.wisc.edu $
|
||||
*/
|
||||
|
||||
machine(Directory, "MOSI Directory Optimized") {
|
||||
|
||||
|
||||
MessageBuffer forwardedRequestFromDir, network="To", virtual_network="1", ordered="true";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="2", ordered="false";
|
||||
MessageBuffer requestToDir, network="From", virtual_network="0", ordered="false";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
O, desc="Owned";
|
||||
M, desc="Modified", format="!b";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETS, desc="A GETS arrives";
|
||||
GETX_Owner, desc="A GETX arrives, requestor is owner";
|
||||
GETX_NotOwner, desc="A GETX arrives, requestor is not owner";
|
||||
PUTX_Owner, "PUTX (requestor is owner)", desc="A PUTX arrives, requestor is owner";
|
||||
PUTX_NotOwner, "PUTX (requestor not owner)",desc="A PUTX arrives, requestor is not owner";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
NetDest Sharers, desc="Set of sharers";
|
||||
bool DirOwner, default="true", desc="Is dir owner?";
|
||||
MachineID ProcOwner, desc="Processor owner";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
return State:I;
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
directory[addr].DirectoryState := state;
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardedRequestNetwork_out, RequestMsg, forwardedRequestFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
if(directory[in_msg.Address].DirOwner == false && in_msg.Requestor == directory[in_msg.Address].ProcOwner) {
|
||||
trigger(Event:GETX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:GETX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (directory[in_msg.Address].DirOwner == false && in_msg.Requestor == directory[in_msg.Address].ProcOwner) {
|
||||
trigger(Event:PUTX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:PUTX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
// a_addRequestorToSharers
|
||||
|
||||
action(a_addRequestorToSharers, "a", desc="Add requestor to list of sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[address].Sharers.add(in_msg.Requestor);
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
}
|
||||
|
||||
// b_dataToRequestor
|
||||
|
||||
action(b_dataToRequestor, "b", desc="Send data to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.SenderMachine := MachineType:Directory;
|
||||
if(in_msg.Type == CoherenceRequestType:GETX) {
|
||||
out_msg.NumPendingAcks := directory[address].Sharers.count();
|
||||
} else {
|
||||
out_msg.NumPendingAcks := 0; // don't need to send pending ack count to GETS requestor
|
||||
}
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.DestMachine := MachineType:L1Cache;
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
DEBUG_EXPR(out_msg.NumPendingAcks);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// d_forwardRequestToOwner
|
||||
|
||||
action(d_forwardRequestToOwner, "d", desc="Forward request to owner") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination.add(directory[address].ProcOwner);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
|
||||
if(in_msg.Type == CoherenceRequestType:GETX) {
|
||||
out_msg.NumPendingAcks := directory[address].Sharers.count();
|
||||
} else {
|
||||
out_msg.NumPendingAcks := 0; // don't need to send pending ack count to GETS requestor
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_setOwnerToRequestor, "f", desc="Set owner equal to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[address].ProcOwner := in_msg.Requestor;
|
||||
directory[address].DirOwner := false;
|
||||
}
|
||||
DEBUG_EXPR(directory[address].ProcOwner);
|
||||
}
|
||||
|
||||
action(g_clearSharers, "g", desc="Clear list of sharers") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
// currently done via multicast message
|
||||
|
||||
action(h_invToSharers, "h", desc="Send INVs to all sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
if(directory[address].Sharers.count() != 0){
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := in_msg.Requestor;
|
||||
out_msg.Destination := directory[address].Sharers;
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeRequestDataToMemory, "l", desc="Write PUTX/DWN data to memory") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_writebackAckToRequestor, "n", desc="Send WB_ack to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
// This needs to be DIRECTORY_LATENCY to keep the queue fifo
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination.add(in_msg.Requestor);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(p_clearOwner, "p", desc="Clear owner") {
|
||||
directory[address].DirOwner := true; // set owner equal to dir
|
||||
}
|
||||
|
||||
action(r_addOwnerToSharers, "r", desc="Add owner to list of sharers") {
|
||||
directory[address].Sharers.add(directory[address].ProcOwner);
|
||||
}
|
||||
|
||||
action(t_removeOwnerFromSharers, "t", desc="Remove owner from list of sharers") {
|
||||
directory[address].Sharers.remove(directory[address].ProcOwner);
|
||||
}
|
||||
|
||||
action(u_removeRequestorFromSharers, "u", desc="Remove requestor from list of sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[address].Sharers.remove(in_msg.Requestor);
|
||||
}
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition({I, S, M, O}, PUTX_NotOwner) {
|
||||
n_writebackAckToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition(I, GETS, S) {
|
||||
a_addRequestorToSharers;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETX_NotOwner, M) {
|
||||
f_setOwnerToRequestor;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition(S, GETS) {
|
||||
a_addRequestorToSharers;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX_NotOwner, M) {
|
||||
u_removeRequestorFromSharers;
|
||||
b_dataToRequestor;
|
||||
f_setOwnerToRequestor;
|
||||
h_invToSharers;
|
||||
g_clearSharers;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition(O, GETS) {
|
||||
a_addRequestorToSharers;
|
||||
d_forwardRequestToOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, {GETX_NotOwner, GETX_Owner}, M) {
|
||||
u_removeRequestorFromSharers;
|
||||
t_removeOwnerFromSharers;
|
||||
d_forwardRequestToOwner;
|
||||
f_setOwnerToRequestor;
|
||||
h_invToSharers;
|
||||
g_clearSharers;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTX_Owner, S) {
|
||||
u_removeRequestorFromSharers;
|
||||
l_writeRequestDataToMemory;
|
||||
n_writebackAckToRequestor;
|
||||
p_clearOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, GETS, O) {
|
||||
a_addRequestorToSharers;
|
||||
r_addOwnerToSharers;
|
||||
d_forwardRequestToOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX_NotOwner) {
|
||||
d_forwardRequestToOwner;
|
||||
f_setOwnerToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_Owner, I) {
|
||||
l_writeRequestDataToMemory;
|
||||
n_writebackAckToRequestor;
|
||||
p_clearOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
}
|
74
src/mem/protocol/MOSI_SMP_directory_1level-msg.sm
Normal file
74
src/mem/protocol/MOSI_SMP_directory_1level-msg.sm
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: MOSI_directory-msg.sm 1.9 04/08/09 16:11:38-05:00 mikem@maya.cs.wisc.edu $
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
PUTX, desc="Put eXclusive";
|
||||
INV, desc="INValidate";
|
||||
WB_ACK, desc="Write Back ACKnowledgment";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
ACK, desc="ACKnowledgment";
|
||||
NACK, desc="Negative ACKnowledgment";
|
||||
DATA, desc="Data";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
MachineID Requestor, desc="Node who initiated the request";
|
||||
NetDest Destination, desc="Multicast destination mask";
|
||||
DataBlock DataBlk, desc="Data for the cache line (if PUTX)";
|
||||
int NumPendingAcks, desc="Number of acks to wait for"; // Needed for forwarded responses only
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID Sender, desc="Node who sent the data";
|
||||
MachineType SenderMachine, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
MachineType DestMachine, desc="What component receives the data";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
int NumPendingAcks, desc="Number of acks to wait for";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
4
src/mem/protocol/MOSI_SMP_directory_1level.slicc
Normal file
4
src/mem/protocol/MOSI_SMP_directory_1level.slicc
Normal file
|
@ -0,0 +1,4 @@
|
|||
MOSI_SMP_directory_1level-msg.sm
|
||||
MOSI_SMP_directory_1level-cache.sm
|
||||
MOSI_SMP_directory_1level-dir.sm
|
||||
standard_1level_SMP-protocol.sm
|
799
src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm
Normal file
799
src/mem/protocol/MSI_MOSI_CMP_directory-L1cache.sm
Normal file
|
@ -0,0 +1,799 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
||||
|
||||
// NODE L1 CACHE
|
||||
// From this node's L1 cache TO the network
|
||||
// a local L1 -> this L2 bank, currently ordered with directory forwarded requests
|
||||
MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="true";
|
||||
MessageBuffer dummyFrom1, network="To", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer dummyFrom2, network="To", virtual_network="2", ordered="false"; // dummy buffer that shouldn't be used
|
||||
// a local L1 -> this L2 bank
|
||||
MessageBuffer responseFromL1Cache, network="To", virtual_network="3", ordered="false";
|
||||
MessageBuffer dummyFrom4, network="To", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used
|
||||
|
||||
|
||||
// To this node's L1 cache FROM the network
|
||||
MessageBuffer dummyTo0, network="From", virtual_network="0", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer dummyTo1, network="From", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer requestToL1Cache, network="From", virtual_network="2", ordered="true";
|
||||
// a L2 bank -> this L1
|
||||
MessageBuffer responseToL1Cache, network="From", virtual_network="3", ordered="false";
|
||||
MessageBuffer dummyTo4, network="From", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Cache states", default="L1Cache_State_L1_I") {
|
||||
// Base states
|
||||
NP, desc="Not present in either cache";
|
||||
L1_I, desc="a L1 cache entry Idle";
|
||||
L1_S, desc="a L1 cache entry Shared";
|
||||
L1_M, desc="a L1 cache entry Modified", format="!b";
|
||||
|
||||
// Transient States
|
||||
L1_IS, desc="L1 idle, issued GETS, have not seen response yet";
|
||||
L1_ISI, desc="L1 idle, issued GETS, saw INV, still waiting for data";
|
||||
L1_IM, desc="L1 idle, issued GETX, have not seen response yet";
|
||||
L1_IMI, desc="L1 idle, issued GETX, saw INV, still waiting for data";
|
||||
L1_IMS, desc="L1 idle, issued GETX, saw DownGrade, still waiting for data";
|
||||
L1_IMSI, desc="L1 idle, issued GETX, saw DownGrade, saw INV, still waiting for data";
|
||||
|
||||
L1_SI, desc="issued PUTS, waiting for response";
|
||||
L1_MI, desc="issued PUTX, waiting for response";
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
enumeration(Event, desc="Cache events") {
|
||||
// L1 events
|
||||
Load, desc="Load request from the home processor";
|
||||
Ifetch, desc="I-fetch request from the home processor";
|
||||
Store, desc="Store request from the home processor";
|
||||
|
||||
// L1 is required to send response to the L2 immediately
|
||||
L1_INV, "INV", desc="L1 Invalidation of M data", format="!r";
|
||||
L1_INV_S, "INV", desc="L1 Invalidation of S data", format="!r";
|
||||
L1_DownGrade, "Force DownGrade", desc="L2 cache forces an L1 cache in M to downgrade to S and writeback result";
|
||||
|
||||
// receiving of data
|
||||
L1_Data, "Data", desc="Data in response to an L1 request, transistion to M or S depending on request";
|
||||
L1_Data_S, "Data S", desc="Data in response to an L1 request, write data then transistion to S";
|
||||
L1_Data_I, "Data I", desc="Data in response to an L1 request, write data then transistion to I";
|
||||
|
||||
// receiving of acks
|
||||
L1_PutAck, "Put Ack", desc="PutS or PutX ack from L2";
|
||||
|
||||
// internal generated request
|
||||
// L1 request to replace block, results in either a PUTS or PUTX request
|
||||
L1_Replacement, desc="L1 Replacement", format="!r";
|
||||
// Currently same as replacement, request initiated when block is in the wrong L1 cache
|
||||
L1_WriteBack, desc="on-chip L1 cache must write back to shared L2";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// CacheEntry
|
||||
structure(Entry, desc="...", interface="AbstractCacheEntry" ) {
|
||||
State CacheState, desc="cache state";
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
// TBE fields
|
||||
structure(TBE, desc="...") {
|
||||
Address Address, desc="Physical address for this TBE";
|
||||
State TBEState, desc="Transient state";
|
||||
DataBlock DataBlk, desc="Buffer for the data block";
|
||||
bool isPrefetch, desc="Set if this was caused by a prefetch";
|
||||
}
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
bool isTagPresent(Address);
|
||||
}
|
||||
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
TBETable L1_TBEs, template_hack="<L1Cache_TBE>";
|
||||
|
||||
CacheMemory L1IcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1I"', abstract_chip_ptr="true";
|
||||
CacheMemory L1DcacheMemory, template_hack="<L1Cache_Entry>", constructor_hack='L1_CACHE_NUM_SETS_BITS,L1_CACHE_ASSOC,MachineType_L1Cache,int_to_string(i)+"_L1D"', abstract_chip_ptr="true";
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
|
||||
// the optionalQueue doesn't have to be ordered for correctness
|
||||
// however inforcing order ensures the prefetches reach the L2 in order
|
||||
MessageBuffer optionalQueue, ordered="true", rank="101", abstract_chip_ptr="true";
|
||||
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
int cache_state_to_int(State state);
|
||||
|
||||
// inclusive cache returns L1 entries only
|
||||
Entry getL1CacheEntry(Address addr), return_by_ref="yes" {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory[addr];
|
||||
} else {
|
||||
return L1IcacheMemory[addr];
|
||||
}
|
||||
}
|
||||
|
||||
void changeL1Permission(Address addr, AccessPermission permission) {
|
||||
if (L1DcacheMemory.isTagPresent(addr)) {
|
||||
return L1DcacheMemory.changePermission(addr, permission);
|
||||
} else if(L1IcacheMemory.isTagPresent(addr)) {
|
||||
return L1IcacheMemory.changePermission(addr, permission);
|
||||
} else {
|
||||
error("cannot change permission, L1 block not present");
|
||||
}
|
||||
}
|
||||
|
||||
bool isL1CacheTagPresent(Address addr) {
|
||||
return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr));
|
||||
}
|
||||
|
||||
State getState(Address addr) {
|
||||
if((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == true){
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(addr);
|
||||
}
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
return L1_TBEs[addr].TBEState;
|
||||
} else if (isL1CacheTagPresent(addr)) {
|
||||
return getL1CacheEntry(addr).CacheState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
string getStateStr(Address addr) {
|
||||
return L1Cache_State_to_string(getState(addr));
|
||||
}
|
||||
|
||||
// when is this called?
|
||||
void setState(Address addr, State state) {
|
||||
assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false);
|
||||
|
||||
// MUST CHANGE
|
||||
if(L1_TBEs.isPresent(addr)) {
|
||||
L1_TBEs[addr].TBEState := state;
|
||||
}
|
||||
|
||||
if (isL1CacheTagPresent(addr)) {
|
||||
getL1CacheEntry(addr).CacheState := state;
|
||||
|
||||
// Set permission
|
||||
if (state == State:L1_I || state == State:L1_SI || state == State:L1_MI) {
|
||||
changeL1Permission(addr, AccessPermission:Invalid);
|
||||
} else if (state == State:L1_S) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Only);
|
||||
} else if (state == State:L1_M) {
|
||||
changeL1Permission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
changeL1Permission(addr, AccessPermission:Busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event mandatory_request_type_to_event(CacheRequestType type) {
|
||||
if (type == CacheRequestType:LD) {
|
||||
return Event:Load;
|
||||
} else if (type == CacheRequestType:IFETCH) {
|
||||
return Event:Ifetch;
|
||||
} else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
|
||||
return Event:Store;
|
||||
} else {
|
||||
error("Invalid CacheRequestType");
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
// All ports are to the same CMP network, queue id numbers determine IntraChip Switch location
|
||||
|
||||
out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache);
|
||||
out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache);
|
||||
|
||||
// ** IN_PORTS **
|
||||
in_port(dummyTo0_in, RequestMsg, dummyTo0) {
|
||||
if (dummyTo0_in.isReady()) {
|
||||
peek(dummyTo0_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(machineID);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
}
|
||||
error("dummyTo0 port should not be used");
|
||||
}
|
||||
}
|
||||
|
||||
in_port(dummyTo1_in, RequestMsg, dummyTo1) {
|
||||
if (dummyTo1_in.isReady()) {
|
||||
peek(dummyTo1_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(machineID);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
}
|
||||
error("dummyTo1 port should not be used");
|
||||
}
|
||||
}
|
||||
|
||||
in_port(dummyTo4_in, ResponseMsg, dummyTo4) {
|
||||
if (dummyTo4_in.isReady()) {
|
||||
peek(dummyTo4_in, ResponseMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(machineID);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.SenderMachId);
|
||||
}
|
||||
error("dummyTo4 port should not be used");
|
||||
}
|
||||
}
|
||||
|
||||
// Response IntraChip L1 Network - response msg to this L1 cache
|
||||
in_port(responseIntraChipL1Network_in, ResponseMsg, responseToL1Cache) {
|
||||
if (responseIntraChipL1Network_in.isReady()) {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.Destination);
|
||||
DEBUG_EXPR(in_msg.SenderMachId);
|
||||
DEBUG_EXPR(machineID);
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if(machineIDToMachineType(in_msg.SenderMachId) == MachineType:L2Cache) {
|
||||
if(in_msg.Type == CoherenceResponseType:DATA) {
|
||||
trigger(Event:L1_Data, in_msg.Address); // L1 now has data in its desired state
|
||||
} else if(in_msg.Type == CoherenceResponseType:DATA_S) {
|
||||
trigger(Event:L1_Data_S, in_msg.Address); // L1 now has data but must imediately move to S state
|
||||
} else if(in_msg.Type == CoherenceResponseType:DATA_I) {
|
||||
trigger(Event:L1_Data_I, in_msg.Address); // L1 now has data but must imediately move to INV state
|
||||
} else if(in_msg.Type == CoherenceResponseType:ACK) {
|
||||
trigger(Event:L1_PutAck, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid L1 response type");
|
||||
}
|
||||
} else {
|
||||
error("A non-L2 cache sent a response to a L1 cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request InterChip network - request from this L1 cache to the shared L2
|
||||
in_port(requestIntraChipL1Network_in, RequestMsg, requestToL1Cache) {
|
||||
if(requestIntraChipL1Network_in.isReady()) {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if(machineIDToMachineType(in_msg.RequestorMachId) == MachineType:L2Cache) {
|
||||
if(in_msg.Type == CoherenceRequestType:L1_DG) {
|
||||
trigger(Event:L1_DownGrade, in_msg.Address); // Force L1 to downgrade to S state
|
||||
} else if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:L1_INV, in_msg.Address); // L1 must invalidate it's modified version
|
||||
} else if (in_msg.Type == CoherenceRequestType:INV_S) {
|
||||
trigger(Event:L1_INV_S, in_msg.Address); // L1 must invalidate it's shared version
|
||||
} else {
|
||||
error("Invalid forwarded request type");
|
||||
}
|
||||
} else {
|
||||
error("A non-L2 cache sent a request to a L1 cache");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory Queue betweens Node's CPU and it's L1 caches
|
||||
in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
|
||||
if (mandatoryQueue_in.isReady()) {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
// Check for data access to blocks in I-cache and ifetchs to blocks in D-cache
|
||||
|
||||
if (in_msg.Type == CacheRequestType:IFETCH) {
|
||||
// ** INSTRUCTION ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_WriteBack, in_msg.Address);
|
||||
}
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 asks the L2 for it.
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// *** DATA ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_WriteBack, in_msg.Address);
|
||||
}
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
// The tag matches for the L1, so the L1 ask the L2 for it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
// L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIONS
|
||||
action(a_issueGETS, "a", desc="Issue GETS") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETS;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(b_issueGETX, "b", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GETX;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
DEBUG_EXPR(machineID);
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(c_issueUPGRADE, "c", desc="Issue GETX") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:UPGRADE;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_issueGETINSTR, "g", desc="Issue GETINSTR") {
|
||||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:GET_INSTR;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
out_msg.Prefetch := in_msg.Prefetch;
|
||||
out_msg.AccessMode := in_msg.AccessMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(d_issuePUTX, "d", desc="Issue PUTX") {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTX;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(q_issuePUTS, "q", desc="Issue PUTS") {
|
||||
enqueue(requestIntraChipL1Network_out, RequestMsg, latency="L1_REQUEST_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:PUTS;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
out_msg.L1CacheStateStr := getStateStr(address);
|
||||
}
|
||||
}
|
||||
|
||||
// L1 responding to a L2 request with data
|
||||
action(e_dataFromL1CacheToL2Cache, "e", desc="Send data from L1 cache to L2 Cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.SenderMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
|
||||
action(f_dataFromTBEToL2Cache, "f", desc="Send data from L1_TBE to L2 Cache") {
|
||||
peek(requestIntraChipL1Network_in, RequestMsg) {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.SenderMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
out_msg.DataBlk := L1_TBEs[in_msg.Address].DataBlk;
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// L1 responding to a L2 request with an invadiation ack
|
||||
action(t_sendInvAckToL2Cache, "t", desc="Send Invadiation ack to L2 Cache") {
|
||||
enqueue(responseIntraChipL1Network_out, ResponseMsg, latency="L1_RESPONSE_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:INV_ACK;
|
||||
out_msg.SenderMachId := machineID;
|
||||
out_msg.Destination.add(map_L1CacheMachId_to_L2Cache(address, machineID));
|
||||
DEBUG_EXPR(address);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") {
|
||||
DEBUG_EXPR(getL1CacheEntry(address).DataBlk);
|
||||
sequencer.readCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
}
|
||||
|
||||
action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") {
|
||||
DEBUG_EXPR(getL1CacheEntry(address).DataBlk);
|
||||
sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk);
|
||||
}
|
||||
|
||||
action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") {
|
||||
check_allocate(L1_TBEs);
|
||||
L1_TBEs.allocate(address);
|
||||
L1_TBEs[address].isPrefetch := false;
|
||||
}
|
||||
|
||||
action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") {
|
||||
mandatoryQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_popRequestQueue, "l", desc="Pop incoming request queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(2, requestIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue and profile the delay within this virtual network") {
|
||||
profileMsgDelay(3, responseIntraChipL1Network_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(s_deallocateTBE, "s", desc="Deallocate TBE") {
|
||||
L1_TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(u_writeDataToL1Cache, "u", desc="Write data to cache") {
|
||||
peek(responseIntraChipL1Network_in, ResponseMsg) {
|
||||
getL1CacheEntry(address).DataBlk := in_msg.DataBlk;
|
||||
}
|
||||
}
|
||||
|
||||
action(x_copyDataFromL1CacheToTBE, "x", desc="Copy data from cache to TBE") {
|
||||
L1_TBEs[address].DataBlk := getL1CacheEntry(address).DataBlk;
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="Stall") {
|
||||
}
|
||||
|
||||
action(ff_deallocateL1CacheBlock, "\f", desc="Deallocate L1 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
|
||||
if (L1DcacheMemory.isTagPresent(address)) {
|
||||
L1DcacheMemory.deallocate(address);
|
||||
} else {
|
||||
L1IcacheMemory.deallocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") {
|
||||
if (L1DcacheMemory.isTagPresent(address) == false) {
|
||||
L1DcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") {
|
||||
if (L1IcacheMemory.isTagPresent(address) == false) {
|
||||
L1IcacheMemory.allocate(address);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************
|
||||
// TRANSITIONS
|
||||
//*****************************************************
|
||||
|
||||
// Transitions for Load/Store/Replacement/WriteBack from transient states
|
||||
transition({L1_IS, L1_IM, L1_ISI, L1_IMI, L1_IMS, L1_IMSI, L1_SI, L1_MI}, {Load, Ifetch, Store, L1_Replacement, L1_WriteBack}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP,L1_I}, {L1_Replacement, L1_WriteBack}) {
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition({NP,L1_I}, Load, L1_IS) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
a_issueGETS;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,L1_I}, Ifetch, L1_IS) {
|
||||
pp_allocateL1ICacheBlock;
|
||||
i_allocateTBE;
|
||||
f_issueGETINSTR;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition({NP,L1_I}, Store, L1_IM) {
|
||||
oo_allocateL1DCacheBlock;
|
||||
i_allocateTBE;
|
||||
b_issueGETX;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition({L1_S}, {Load,Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(L1_S, Store, L1_IM) {
|
||||
i_allocateTBE;
|
||||
c_issueUPGRADE;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(L1_S, {L1_Replacement,L1_WriteBack}, L1_SI) {
|
||||
i_allocateTBE;
|
||||
q_issuePUTS;
|
||||
x_copyDataFromL1CacheToTBE;
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(L1_S, L1_INV_S, L1_I) {
|
||||
t_sendInvAckToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Modified
|
||||
transition(L1_M, {Load, Ifetch}) {
|
||||
h_load_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(L1_M, Store) {
|
||||
hh_store_hit;
|
||||
k_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(L1_M, {L1_Replacement, L1_WriteBack}, L1_MI) {
|
||||
i_allocateTBE;
|
||||
d_issuePUTX;
|
||||
x_copyDataFromL1CacheToTBE;
|
||||
ff_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(L1_M, L1_INV, L1_I) {
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_M, L1_DownGrade, L1_S) {
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_IS
|
||||
transition(L1_IS, L1_INV_S, L1_ISI) {
|
||||
t_sendInvAckToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_IS, L1_Data, L1_S) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L1_IS, L1_Data_I, L1_I) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_ISI
|
||||
transition(L1_ISI, L1_Data, L1_I) {
|
||||
u_writeDataToL1Cache;
|
||||
h_load_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_IM
|
||||
transition(L1_IM, L1_INV, L1_IMI) { // we don't have to respond immediately because we know the data is coming
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_IM, L1_INV_S) {
|
||||
t_sendInvAckToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_IM, L1_DownGrade, L1_IMS) {
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_IM, L1_Data, L1_M) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L1_IM, L1_Data_S, L1_S) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L1_IM, L1_Data_I, L1_I) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_IMI - data should arrive and no request are possilbe
|
||||
transition(L1_IMI, L1_Data, L1_I) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_IMS
|
||||
transition(L1_IMS, L1_Data, L1_S) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(L1_IMS, L1_INV_S, L1_IMSI) {
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_IMSI
|
||||
transition(L1_IMSI, L1_Data, L1_I) {
|
||||
u_writeDataToL1Cache;
|
||||
hh_store_hit;
|
||||
s_deallocateTBE;
|
||||
e_dataFromL1CacheToL2Cache;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_SI
|
||||
transition(L1_SI, L1_INV_S) {
|
||||
t_sendInvAckToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_SI, L1_PutAck, L1_I) {
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
// Transitions from L1_MI
|
||||
transition(L1_MI, L1_INV) {
|
||||
f_dataFromTBEToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_MI, L1_DownGrade, L1_SI) {
|
||||
f_dataFromTBEToL2Cache;
|
||||
l_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(L1_MI, L1_PutAck, L1_I) {
|
||||
s_deallocateTBE;
|
||||
o_popIncomingResponseQueue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
2191
src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm
Normal file
2191
src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm
Normal file
File diff suppressed because it is too large
Load diff
497
src/mem/protocol/MSI_MOSI_CMP_directory-dir.sm
Normal file
497
src/mem/protocol/MSI_MOSI_CMP_directory-dir.sm
Normal file
|
@ -0,0 +1,497 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
machine(Directory, "MOSI Directory Optimized") {
|
||||
|
||||
// ** OUT QUEUES **
|
||||
MessageBuffer dummyFrom0, network="To", virtual_network="0", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer dummyFrom1, network="To", virtual_network="1", ordered="false"; // dummy buffer that shouldn't be used
|
||||
// Dir -> mod-L2 bank - Must be true for the 'opt' and 'GS' protocols BE CAREFUL HERE!!!
|
||||
MessageBuffer forwardedRequestFromDir, network="To", virtual_network="2", ordered="true";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="3", ordered="false"; // Dir -> mod-L2 bank
|
||||
MessageBuffer dummyFrom4, network="To", virtual_network="4", ordered="false"; // dummy buffer that shouldn't be used
|
||||
|
||||
// ** IN QUEUES **
|
||||
MessageBuffer dummyTo0, network="From", virtual_network="0", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer requestToDir, network="From", virtual_network="1", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
MessageBuffer dummyTo2, network="From", virtual_network="2", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer dummyTo3, network="From", virtual_network="3", ordered="false"; // dummy buffer that shouldn't be used
|
||||
MessageBuffer finalAckToDir, network="From", virtual_network="4", ordered="false"; // a mod-L2 bank -> this Dir
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_NP") {
|
||||
// Base states
|
||||
NP, desc="Not present";
|
||||
I, desc="Idle";
|
||||
S, desc="Shared";
|
||||
O, desc="Owned";
|
||||
M, desc="Modified", format="!b";
|
||||
OO, desc="transient state of O->GetS/GetInstr->O";
|
||||
OM, desc="transient state of O->GetX->M";
|
||||
MO, desc="transient state of M->GetS/GetInstr->O";
|
||||
MM, desc="transient state of M->GetX->M";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
GETS, desc="A GETS arrives";
|
||||
GET_INSTR, desc="";
|
||||
GETX_Owner, desc="A GETX arrives, requestor is owner";
|
||||
GETX_NotOwner, desc="A GETX arrives, requestor is not owner";
|
||||
PUTX_Owner, "PUTX (requestor is owner)", desc="A PUTX arrives, requestor is owner";
|
||||
PUTX_NotOwner, "PUTX (requestor not owner)",desc="A PUTX arrives, requestor is not owner";
|
||||
FinalAck, desc="";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
||||
// DirectoryEntry
|
||||
structure(Entry, desc="...") {
|
||||
State DirectoryState, desc="Directory state";
|
||||
Set Sharers, desc="Set of sharers - must be L2 caches"; // Note this is a Set and not a NetDest for space concerns
|
||||
bool DirOwner, default="true", desc="Is dir owner?";
|
||||
NodeID ProcOwner, default="0", desc="Processor owner"; // Note this is an int for space concerns
|
||||
DataBlock DataBlk, desc="data for the block";
|
||||
}
|
||||
|
||||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
|
||||
State getState(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
return directory[addr].DirectoryState;
|
||||
}
|
||||
return State:NP;
|
||||
}
|
||||
|
||||
string getDirStateStr(Address addr) {
|
||||
return Directory_State_to_string(getState(addr));
|
||||
}
|
||||
|
||||
string getRequestTypeStr(CoherenceRequestType type) {
|
||||
return CoherenceRequestType_to_string(type);
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
if (directory.isPresent(addr)) {
|
||||
DEBUG_EXPR(addr);
|
||||
DEBUG_EXPR(directory[addr].DirectoryState);
|
||||
directory[addr].DirectoryState := state;
|
||||
DEBUG_EXPR(directory[addr].DirectoryState);
|
||||
DEBUG_EXPR(state);
|
||||
}
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardedRequestNetwork_out, RequestMsg, forwardedRequestFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(ownRequestQueue_out, RequestMsg, requestToDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
in_port(dummyTo0_in, RequestMsg, dummyTo0) {
|
||||
if (dummyTo0_in.isReady()) {
|
||||
peek(dummyTo0_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
}
|
||||
error("dummyTo0 port should not be used");
|
||||
}
|
||||
}
|
||||
in_port(dummyTo2_in, RequestMsg, dummyTo2) {
|
||||
if (dummyTo2_in.isReady()) {
|
||||
peek(dummyTo2_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
}
|
||||
error("dummyTo2 port should not be used");
|
||||
}
|
||||
}
|
||||
|
||||
in_port(dummyTo3_in, RequestMsg, dummyTo3) {
|
||||
if (dummyTo3_in.isReady()) {
|
||||
peek(dummyTo3_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(id);
|
||||
DEBUG_EXPR(in_msg.Type);
|
||||
DEBUG_EXPR(getState(in_msg.Address));
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
}
|
||||
error("dummyTo3 port should not be used");
|
||||
}
|
||||
}
|
||||
|
||||
in_port(finalAckNetwork_in, ResponseMsg, finalAckToDir){
|
||||
if(finalAckNetwork_in.isReady()){
|
||||
peek(finalAckNetwork_in, ResponseMsg){
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if(in_msg.Type == CoherenceResponseType:FINALACK){
|
||||
trigger(Event:FinalAck, in_msg.Address);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestNetwork_in, RequestMsg, requestToDir) {
|
||||
if (requestNetwork_in.isReady()) {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
assert(in_msg.Destination.isElement(machineID));
|
||||
if (in_msg.Type == CoherenceRequestType:GETS) {
|
||||
trigger(Event:GETS, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GET_INSTR) {
|
||||
trigger(Event:GET_INSTR, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
if(directory[in_msg.Address].DirOwner == false &&
|
||||
L2CacheMachIDToChipID(in_msg.RequestorMachId) == directory[in_msg.Address].ProcOwner) {
|
||||
trigger(Event:GETX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:GETX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else if (in_msg.Type == CoherenceRequestType:PUTX) {
|
||||
if (directory[in_msg.Address].DirOwner == false &&
|
||||
L2CacheMachIDToChipID(in_msg.RequestorMachId) == directory[in_msg.Address].ProcOwner) {
|
||||
trigger(Event:PUTX_Owner, in_msg.Address);
|
||||
} else {
|
||||
trigger(Event:PUTX_NotOwner, in_msg.Address);
|
||||
}
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
// a_addRequestorToSharers
|
||||
|
||||
action(a_addRequestorToSharers, "a", desc="Add requestor to list of sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[address].Sharers.add(L2CacheMachIDToChipID(in_msg.RequestorMachId));
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
}
|
||||
|
||||
// b_dataToRequestor
|
||||
|
||||
action(b_dataToRequestor, "b", desc="Send data to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:DATA;
|
||||
out_msg.SenderMachId := machineID;
|
||||
if(in_msg.Type == CoherenceRequestType:GETX) {
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
DEBUG_EXPR(directory[address].Sharers.count());
|
||||
out_msg.NumPendingExtAcks := directory[address].Sharers.count();
|
||||
} else {
|
||||
out_msg.NumPendingExtAcks := 0; // don't need to send pending ack count to GETS requestor
|
||||
}
|
||||
out_msg.Destination.add(in_msg.RequestorMachId);
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
DEBUG_EXPR(out_msg.Address);
|
||||
DEBUG_EXPR(out_msg.DataBlk);
|
||||
DEBUG_EXPR(out_msg.NumPendingExtAcks);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
out_msg.MessageSize := MessageSizeType:Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// d_forwardRequestToOwner
|
||||
|
||||
action(d_forwardRequestToOwner, "d", desc="Forward request to owner") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := in_msg.Type;
|
||||
out_msg.RequestorMachId := in_msg.RequestorMachId;
|
||||
out_msg.Destination.add(map_L2ChipId_to_L2Cache(out_msg.Address, directory[address].ProcOwner));
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
|
||||
if(in_msg.Type == CoherenceRequestType:GETX) {
|
||||
out_msg.NumPendingExtAcks := directory[address].Sharers.count();
|
||||
} else {
|
||||
out_msg.NumPendingExtAcks := 0; // don't need to send pending ack count to GETS requestor
|
||||
}
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
DEBUG_EXPR(out_msg.Address);
|
||||
DEBUG_EXPR(out_msg.NumPendingExtAcks);
|
||||
DEBUG_EXPR(out_msg.Destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(f_setOwnerToRequestor, "f", desc="Set owner equal to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[address].ProcOwner := L2CacheMachIDToChipID(in_msg.RequestorMachId);
|
||||
directory[address].DirOwner := false;
|
||||
}
|
||||
DEBUG_EXPR(directory[address].ProcOwner);
|
||||
}
|
||||
|
||||
action(g_clearSharers, "g", desc="Clear list of sharers") {
|
||||
directory[address].Sharers.clear();
|
||||
}
|
||||
|
||||
// currently done via multicast message
|
||||
|
||||
action(h_invToSharers, "h", desc="Send INVs to all sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
DEBUG_EXPR(directory[address].Sharers.count());
|
||||
if(directory[address].Sharers.count() != 0){
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.RequestorMachId := in_msg.RequestorMachId;
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
out_msg.Destination := getMultiStaticL2BankNetDest(address, directory[address].Sharers);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
|
||||
action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
|
||||
profileMsgDelay(1, requestNetwork_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(l_writeRequestDataToMemory, "l", desc="Write PUTX/DWN data to memory") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
directory[in_msg.Address].DataBlk := in_msg.DataBlk;
|
||||
DEBUG_EXPR(in_msg.Address);
|
||||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(n_writebackAckToRequestor, "n", desc="Send WB_ack to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
// This needs to be DIRECTORY_LATENCY to keep the queue fifo
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(in_msg.RequestorMachId);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(m_forwardExclusiveRequestToOwner, "m", desc="Send EXE_ack to requestor") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
// This needs to be DIRECTORY_LATENCY to keep the queue fifo
|
||||
enqueue(forwardedRequestNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:EXE_ACK;
|
||||
out_msg.RequestorMachId := machineID;
|
||||
out_msg.Destination.add(in_msg.RequestorMachId);
|
||||
out_msg.MessageSize := MessageSizeType:Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(uu_profile, "u/", desc="Profile this transition.") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
profile_request(in_msg.L1CacheStateStr, in_msg.L2CacheStateStr, getDirStateStr(address), getRequestTypeStr(in_msg.Type));
|
||||
}
|
||||
}
|
||||
|
||||
action(p_clearOwner, "p", desc="Clear owner") {
|
||||
directory[address].DirOwner := true; // set owner equal to dir
|
||||
}
|
||||
|
||||
action(r_addOwnerToSharers, "r", desc="Add owner to list of sharers") {
|
||||
DEBUG_EXPR(directory[address].ProcOwner);
|
||||
directory[address].Sharers.add(directory[address].ProcOwner);
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
|
||||
action(t_removeOwnerFromSharers, "t", desc="Remove owner from list of sharers") {
|
||||
DEBUG_EXPR(directory[address].ProcOwner);
|
||||
directory[address].Sharers.remove(directory[address].ProcOwner);
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
|
||||
action(u_removeRequestorFromSharers, "u", desc="Remove requestor from list of sharers") {
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
DEBUG_EXPR(in_msg.RequestorMachId);
|
||||
directory[address].Sharers.remove(L2CacheMachIDToChipID(in_msg.RequestorMachId));
|
||||
DEBUG_EXPR(directory[address].Sharers);
|
||||
}
|
||||
}
|
||||
|
||||
action(x_recycleRequest, "x", desc=""){
|
||||
peek(requestNetwork_in, RequestMsg) {
|
||||
enqueue(ownRequestQueue_out, RequestMsg, latency="RECYCLE_LATENCY"){
|
||||
out_msg := in_msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(hh_popFinalAckQueue, "\h", desc=""){
|
||||
profileMsgDelay(4, finalAckNetwork_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
//action(z_stall, "z", desc=""){
|
||||
//}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition({OM,MM}, FinalAck, M){
|
||||
hh_popFinalAckQueue;
|
||||
}
|
||||
transition({OO,MO}, FinalAck, O){
|
||||
hh_popFinalAckQueue;
|
||||
}
|
||||
|
||||
transition({OO, OM, MO, MM}, {GETS, GET_INSTR, GETX_Owner, GETX_NotOwner, PUTX_Owner}){
|
||||
x_recycleRequest;
|
||||
j_popIncomingRequestQueue;
|
||||
// z_stall;
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
|
||||
transition({NP, I, S, M, O, OO, OM, MO, MM}, PUTX_NotOwner) {
|
||||
uu_profile;
|
||||
n_writebackAckToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Idle
|
||||
transition({NP,I}, {GETS,GET_INSTR}, S) {
|
||||
uu_profile;
|
||||
a_addRequestorToSharers;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition({NP,I}, GETX_NotOwner, M) {
|
||||
uu_profile;
|
||||
f_setOwnerToRequestor;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Shared
|
||||
transition(S, {GETS,GET_INSTR}) {
|
||||
uu_profile;
|
||||
a_addRequestorToSharers;
|
||||
b_dataToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(S, GETX_NotOwner, M) {
|
||||
uu_profile;
|
||||
u_removeRequestorFromSharers;
|
||||
b_dataToRequestor;
|
||||
f_setOwnerToRequestor;
|
||||
h_invToSharers;
|
||||
g_clearSharers;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// Transitions from Owned
|
||||
transition(O, {GETS,GET_INSTR}, OO) {
|
||||
uu_profile;
|
||||
a_addRequestorToSharers;
|
||||
d_forwardRequestToOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, {GETX_NotOwner, GETX_Owner}, OM) {
|
||||
uu_profile;
|
||||
u_removeRequestorFromSharers;
|
||||
t_removeOwnerFromSharers;
|
||||
d_forwardRequestToOwner;
|
||||
f_setOwnerToRequestor;
|
||||
h_invToSharers;
|
||||
g_clearSharers;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(O, PUTX_Owner, S) {
|
||||
uu_profile;
|
||||
u_removeRequestorFromSharers;
|
||||
l_writeRequestDataToMemory;
|
||||
n_writebackAckToRequestor;
|
||||
p_clearOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
// Transitions from Modified
|
||||
transition(M, {GETS,GET_INSTR}, MO) {
|
||||
uu_profile;
|
||||
a_addRequestorToSharers;
|
||||
r_addOwnerToSharers;
|
||||
d_forwardRequestToOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX_NotOwner, MM) {
|
||||
uu_profile;
|
||||
d_forwardRequestToOwner;
|
||||
f_setOwnerToRequestor;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, GETX_Owner) {
|
||||
uu_profile;
|
||||
m_forwardExclusiveRequestToOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_Owner, I) {
|
||||
uu_profile;
|
||||
l_writeRequestDataToMemory;
|
||||
n_writebackAckToRequestor;
|
||||
p_clearOwner;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
}
|
115
src/mem/protocol/MSI_MOSI_CMP_directory-msg.sm
Normal file
115
src/mem/protocol/MSI_MOSI_CMP_directory-msg.sm
Normal file
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// CoherenceRequestType
|
||||
enumeration(CoherenceRequestType, desc="...") {
|
||||
GETX, desc="Get eXclusive";
|
||||
UPGRADE, desc="UPGRADE to exclusive";
|
||||
GETS, desc="Get Shared";
|
||||
GET_INSTR, desc="Get Instruction";
|
||||
PUTX, desc="Put eXclusive";
|
||||
PUTS, desc="Put Shared";
|
||||
INV, desc="INValidate";
|
||||
INV_S, desc="INValidate the shared version";
|
||||
L1_DG, desc="L1 cache DownGrade";
|
||||
WB_ACK, desc="Write Back ACKnowledgment";
|
||||
EXE_ACK, desc="EXclusivE ACKnowledgment";
|
||||
}
|
||||
|
||||
// CoherenceResponseType
|
||||
enumeration(CoherenceResponseType, desc="...") {
|
||||
ACK, desc="ACKnowledgment";
|
||||
INV_ACK, desc="INValidation ACKnowledgment";
|
||||
DG_ACK, desc="DownGrade ACKnowledgment";
|
||||
NACK, desc="Negative ACKnowledgment";
|
||||
DATA, desc="Data";
|
||||
DATA_S, desc="Data to L1 cache, then imediately go to shared state";
|
||||
DATA_I, desc="Data to L1 cache, then imediately go to inv state";
|
||||
FINALACK, desc="";
|
||||
}
|
||||
|
||||
// RequestMsg
|
||||
structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceRequestType Type, desc="Type of request (GetS, GetX, PutX, etc)";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
MachineID RequestorMachId, desc="What component request";
|
||||
NetDest Destination, desc="What components receive the request, includes MachineType and num";
|
||||
DataBlock DataBlk, desc="Data for the cache line (if PUTX)";
|
||||
int NumPendingExtAcks, desc="Number of acks to wait for"; // Needed for forwarded responses only
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
string L1CacheStateStr, desc="describes L1 cache block state";
|
||||
string L2CacheStateStr, desc="describes L2 cache block state";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
}
|
||||
|
||||
// ResponseMsg
|
||||
structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
CoherenceResponseType Type, desc="Type of response (Ack, Data, etc)";
|
||||
MachineID SenderMachId, desc="What component sent the data";
|
||||
NetDest Destination, desc="Node to whom the data is sent";
|
||||
DataBlock DataBlk, desc="data for the cache line";
|
||||
int NumPendingExtAcks, desc="Number of acks to wait for";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
return GenericRequestType:PUTX;
|
||||
} else if(type == CoherenceRequestType:GETS) {
|
||||
return GenericRequestType:GETS;
|
||||
} else if(type == CoherenceRequestType:GET_INSTR) {
|
||||
return GenericRequestType:GET_INSTR;
|
||||
} else if(type == CoherenceRequestType:GETX) {
|
||||
return GenericRequestType:GETX;
|
||||
} else if(type == CoherenceRequestType:UPGRADE) {
|
||||
return GenericRequestType:UPGRADE;
|
||||
} else if(type == CoherenceRequestType:PUTS) {
|
||||
return GenericRequestType:PUTS;
|
||||
} else if(type == CoherenceRequestType:INV) {
|
||||
return GenericRequestType:INV;
|
||||
} else if(type == CoherenceRequestType:INV_S) {
|
||||
return GenericRequestType:INV_S;
|
||||
} else if(type == CoherenceRequestType:L1_DG) {
|
||||
return GenericRequestType:DOWNGRADE;
|
||||
} else if(type == CoherenceRequestType:WB_ACK) {
|
||||
return GenericRequestType:WB_ACK;
|
||||
} else if(type == CoherenceRequestType:EXE_ACK) {
|
||||
return GenericRequestType:EXE_ACK;
|
||||
} else {
|
||||
DEBUG_EXPR(type);
|
||||
error("invalid CoherenceRequestType");
|
||||
}
|
||||
}
|
8
src/mem/protocol/MSI_MOSI_CMP_directory.slicc
Normal file
8
src/mem/protocol/MSI_MOSI_CMP_directory.slicc
Normal file
|
@ -0,0 +1,8 @@
|
|||
# protocol briefly described in
|
||||
# doc/MSI_MOSI_CMP_directory_2level-protocol-description.txt
|
||||
|
||||
MSI_MOSI_CMP_directory-msg.sm
|
||||
MSI_MOSI_CMP_directory-L1cache.sm
|
||||
MSI_MOSI_CMP_directory-L2cache.sm
|
||||
MSI_MOSI_CMP_directory-dir.sm
|
||||
standard_CMP-protocol.sm
|
62
src/mem/protocol/RubySlicc_ComponentMapping.sm
Normal file
62
src/mem/protocol/RubySlicc_ComponentMapping.sm
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Mapping functions
|
||||
|
||||
// NodeID map_address_to_node(Address addr);
|
||||
MachineID map_Address_to_Directory(Address addr);
|
||||
NodeID map_Address_to_DirectoryNode(Address addr);
|
||||
MachineID map_Address_to_CentralArbiterNode(Address addr);
|
||||
NodeID oldmap_L1RubyNode_to_L2Cache(Address addr, NodeID L1RubyNode);
|
||||
MachineID map_L1CacheMachId_to_L2Cache(Address addr, MachineID L1CacheMachId);
|
||||
MachineID map_L2ChipId_to_L2Cache(Address addr, NodeID L2ChipId);
|
||||
// MachineID map_L1RubyNode_to_Arb(NodeID L1RubyNode);
|
||||
|
||||
MachineID getL1MachineID(NodeID L1RubyNode);
|
||||
NodeID getChipID(MachineID L2machID);
|
||||
MachineID getCollectorDest(MachineID L1machID);
|
||||
MachineID getCollectorL1Cache(MachineID colID);
|
||||
NetDest getMultiStaticL2BankNetDest(Address addr, Set sharers);
|
||||
bool isL1OnChip(MachineID L1machID, NodeID L2NodeID);
|
||||
bool isL2OnChip(MachineID L2machID, NodeID L2NodeID);
|
||||
|
||||
int getNumBanksInBankSet();
|
||||
NodeID machineIDToNodeID(MachineID machID);
|
||||
NodeID machineIDToVersion(MachineID machID);
|
||||
MachineType machineIDToMachineType(MachineID machID);
|
||||
NodeID L1CacheMachIDToProcessorNum(MachineID machID);
|
||||
NodeID L2CacheMachIDToChipID(MachineID machID);
|
||||
Set getOtherLocalL1IDs(MachineID L1);
|
||||
Set getLocalL1IDs(MachineID L1);
|
||||
Set getExternalL1IDs(MachineID L1);
|
||||
NetDest getAllPertinentL2Banks(Address addr);
|
||||
bool isLocalProcessor(MachineID thisId, MachineID tarId);
|
||||
|
||||
GenericMachineType ConvertMachToGenericMach(MachineType machType);
|
||||
|
34
src/mem/protocol/RubySlicc_Defines.sm
Normal file
34
src/mem/protocol/RubySlicc_Defines.sm
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Hack, no node object since base class has them
|
||||
NodeID id, no_chip_object="yes", no_vector="yes", abstract_chip_ptr="true";
|
||||
NodeID version, no_chip_object="yes", no_vector="yes", abstract_chip_ptr="true";
|
||||
MachineID machineID, no_chip_object="yes", no_vector="yes", abstract_chip_ptr="true";
|
||||
|
339
src/mem/protocol/RubySlicc_Exports.sm
Normal file
339
src/mem/protocol/RubySlicc_Exports.sm
Normal file
|
@ -0,0 +1,339 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// defines
|
||||
external_type(int, primitive="yes", default="0");
|
||||
external_type(bool, primitive="yes", default="false");
|
||||
external_type(string, primitive="yes");
|
||||
external_type(uint64, primitive="yes");
|
||||
external_type(Time, primitive="yes", default="0");
|
||||
external_type(Address);
|
||||
|
||||
|
||||
// Declarations of external types that are common to all protocols
|
||||
|
||||
// AccessPermission
|
||||
enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent") {
|
||||
Busy, desc="No Read or Write";
|
||||
Read_Only, desc="Read Only";
|
||||
Read_Write, desc="Read/Write";
|
||||
Invalid, desc="Invalid";
|
||||
NotPresent, desc="NotPresent";
|
||||
OnHold, desc="Holding a place in dnuca cache";
|
||||
ReadUpgradingToWrite, desc="Read only, but trying to get Read/Write";
|
||||
Stale, desc="local L1 has a modified copy, assume L2 copy is stale data";
|
||||
}
|
||||
|
||||
// TesterStatus
|
||||
enumeration(TesterStatus, desc="...") {
|
||||
Idle, desc="Idle";
|
||||
Action_Pending, desc="Action Pending";
|
||||
Ready, desc="Ready";
|
||||
Check_Pending, desc="Check Pending";
|
||||
}
|
||||
|
||||
// SpecifiedGeneratorTypes
|
||||
enumeration(SpecifiedGeneratorType, desc="...") {
|
||||
DetermGETXGenerator, desc="deterministic GETX Tester";
|
||||
DetermInvGenerator, desc="deterministic all shared then invalidate Tester";
|
||||
DetermSeriesGETSGenerator, desc="deterministic Series of GETSs Tester for prefetcher tuning";
|
||||
}
|
||||
|
||||
// RequestGeneratorStatus
|
||||
enumeration(RequestGeneratorStatus, desc="...") {
|
||||
Thinking, desc="Doing work between release and next acquire";
|
||||
Test_Pending, desc="Test pending";
|
||||
Before_Swap, desc="We're about to perform the swap";
|
||||
Swap_Pending, desc="The swap used for test-and-send is pending";
|
||||
Holding, desc="We are holding the lock performing the critical section";
|
||||
Release_Pending, desc="The write for the release is pending";
|
||||
Done, desc="Done, waiting for end of run";
|
||||
}
|
||||
|
||||
// DetermGETXGeneratorStatus
|
||||
enumeration(DetermGETXGeneratorStatus, desc="...") {
|
||||
Thinking, desc="Doing work before next action";
|
||||
Store_Pending, desc="Store pending";
|
||||
Done, desc="Done, waiting for end of run";
|
||||
}
|
||||
|
||||
// DetermGETXGeneratorStatus
|
||||
enumeration(DetermInvGeneratorStatus, desc="...") {
|
||||
Thinking, desc="Doing work before next action";
|
||||
Store_Pending, desc="Store pending";
|
||||
Load_Complete, desc="Load complete";
|
||||
Load_Pending, desc="Load pending";
|
||||
Done, desc="Done, waiting for end of run";
|
||||
}
|
||||
|
||||
// DetermSeriesGETSGeneratorStatus
|
||||
enumeration(DetermSeriesGETSGeneratorStatus, desc="...") {
|
||||
Thinking, desc="Doing work before next action";
|
||||
Load_Pending, desc="Load pending";
|
||||
Done, desc="Done, waiting for end of run";
|
||||
}
|
||||
|
||||
// LockStatus
|
||||
enumeration(LockStatus, desc="...") {
|
||||
Unlocked, desc="Lock is not held";
|
||||
Locked, desc="Lock is held";
|
||||
}
|
||||
|
||||
// SequencerStatus
|
||||
enumeration(SequencerStatus, desc="...") {
|
||||
Idle, desc="Idle";
|
||||
Pending, desc="Pending";
|
||||
}
|
||||
|
||||
enumeration(TransitionResult, desc="...") {
|
||||
Valid, desc="Valid transition";
|
||||
ResourceStall, desc="Stalled due to insufficient resources";
|
||||
ProtocolStall, desc="Protocol specified stall";
|
||||
}
|
||||
|
||||
// CacheRequestType
|
||||
enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
|
||||
LD, desc="Load";
|
||||
ST, desc="Store";
|
||||
ATOMIC, desc="Atomic Load/Store";
|
||||
IFETCH, desc="Instruction fetch";
|
||||
IO, desc="I/O";
|
||||
REPLACEMENT, desc="Replacement";
|
||||
COMMIT, desc="Commit version";
|
||||
LD_XACT, desc="Transactional Load";
|
||||
LDX_XACT, desc="Transactional Load-Intend-To-Modify";
|
||||
ST_XACT, desc="Transactional Store";
|
||||
BEGIN_XACT, desc="Begin Transaction";
|
||||
COMMIT_XACT, desc="Commit Transaction";
|
||||
ABORT_XACT, desc="Abort Transaction";
|
||||
NULL, desc="Invalid request type";
|
||||
}
|
||||
|
||||
enumeration(GenericRequestType, desc="...", default="GenericRequestType_NULL") {
|
||||
GETS, desc="gets request";
|
||||
GET_INSTR, desc="get instr request";
|
||||
GETX, desc="getx request";
|
||||
UPGRADE, desc="upgrade request";
|
||||
DOWNGRADE, desc="downgrade request";
|
||||
INV, desc="invalidate request";
|
||||
INV_S, desc="invalidate shared copy request";
|
||||
PUTS, desc="puts request";
|
||||
PUTO, desc="puto request";
|
||||
PUTX, desc="putx request";
|
||||
L2_PF, desc="L2 prefetch";
|
||||
LD, desc="Load";
|
||||
ST, desc="Store";
|
||||
ATOMIC, desc="Atomic Load/Store";
|
||||
IFETCH, desc="Instruction fetch";
|
||||
IO, desc="I/O";
|
||||
NACK, desc="Nack";
|
||||
REPLACEMENT, desc="Replacement";
|
||||
WB_ACK, desc="WriteBack ack";
|
||||
EXE_ACK, desc="Execlusive ack";
|
||||
COMMIT, desc="Commit version";
|
||||
LD_XACT, desc="Transactional Load";
|
||||
LDX_XACT, desc="Transactional Load-Intend-Modify";
|
||||
ST_XACT, desc="Transactional Store";
|
||||
BEGIN_XACT, desc="Begin Transaction";
|
||||
COMMIT_XACT, desc="Commit Transaction";
|
||||
ABORT_XACT, desc="Abort Transaction";
|
||||
NULL, desc="null request type";
|
||||
}
|
||||
|
||||
enumeration(GenericMachineType, desc="...", default="GenericMachineType_NULL") {
|
||||
L1Cache, desc="L1 Cache Mach";
|
||||
L2Cache, desc="L2 Cache Mach";
|
||||
L3Cache, desc="L3 Cache Mach";
|
||||
Directory, desc="Directory Mach";
|
||||
Collector, desc="Collector Mach";
|
||||
L1Cache_wCC, desc="L1 Cache Mach with Cache Coherence (used for miss latency profile)";
|
||||
L2Cache_wCC, desc="L1 Cache Mach with Cache Coherence (used for miss latency profile)";
|
||||
NULL, desc="null mach type";
|
||||
}
|
||||
|
||||
// MessageSizeType
|
||||
enumeration(MessageSizeType, default="MessageSizeType_Undefined", desc="...") {
|
||||
Undefined, desc="Undefined";
|
||||
Control, desc="Control Message";
|
||||
Data, desc="Data Message";
|
||||
Request_Control, desc="Request";
|
||||
Reissue_Control, desc="Reissued request";
|
||||
Response_Data, desc="data response";
|
||||
ResponseL2hit_Data, desc="data response";
|
||||
ResponseLocal_Data, desc="data response";
|
||||
Response_Control, desc="non-data response";
|
||||
Writeback_Data, desc="Writeback data";
|
||||
Writeback_Control, desc="Writeback control";
|
||||
Forwarded_Control, desc="Forwarded control";
|
||||
Invalidate_Control, desc="Invalidate control";
|
||||
Unblock_Control, desc="Unblock control";
|
||||
Persistent_Control, desc="Persistent request activation messages";
|
||||
Completion_Control, desc="Completion messages";
|
||||
}
|
||||
|
||||
// AccessType
|
||||
enumeration(AccessType, desc="...") {
|
||||
Read, desc="Reading from cache";
|
||||
Write, desc="Writing to cache";
|
||||
}
|
||||
|
||||
// AccessModeType
|
||||
enumeration(AccessModeType, default="AccessModeType_UserMode", desc="...") {
|
||||
SupervisorMode, desc="Supervisor mode";
|
||||
UserMode, desc="User mode";
|
||||
}
|
||||
|
||||
enumeration(PrefetchBit, default="PrefetchBit_No", desc="...") {
|
||||
No, desc="No, not a prefetch";
|
||||
Yes, desc="Yes, a prefetch";
|
||||
L1_HW, desc="This is a L1 hardware prefetch";
|
||||
L2_HW, desc="This is a L2 hardware prefetch";
|
||||
}
|
||||
|
||||
// CacheMsg
|
||||
structure(CacheMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Line address for this request";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
CacheRequestType Type, desc="Type of request (LD, ST, etc)";
|
||||
Address ProgramCounter, desc="Program counter of the instruction that caused the miss";
|
||||
AccessModeType AccessMode, desc="user/supervisor access type";
|
||||
int Size, desc="size in bytes of access";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
// following field only used for MVC
|
||||
int Version, desc="Version associated with this request";
|
||||
// trans mem fields
|
||||
//bool Aborted, desc="This flag is set if the request is from an aborted xact.";
|
||||
Address LogicalAddress, desc="Virtual address for this request";
|
||||
//int TransactionLevel, desc="Transaction Level of this request";
|
||||
//uint64 SequenceNumber, desc="Sequence number of this request";
|
||||
int ThreadID, desc="The SMT thread that initiated this request";
|
||||
uint64 Timestamp, desc="The transaction timestamp of this request. Last commit time if request is non-transactional";
|
||||
bool ExposedAction, desc="Is this request part of an exposed action";
|
||||
//uint64 RequestTime, desc="The cycle in which this request was issued";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MaskPredictorType
|
||||
enumeration(MaskPredictorType, "MaskPredictorType_Undefined", desc="...") {
|
||||
Undefined, desc="Undefined";
|
||||
AlwaysUnicast, desc="AlwaysUnicast";
|
||||
TokenD, desc="TokenD";
|
||||
AlwaysBroadcast, desc="AlwaysBroadcast";
|
||||
TokenB, desc="TokenB";
|
||||
TokenNull, desc="TokenNull";
|
||||
Random, desc="Random";
|
||||
Pairwise, desc="Pairwise";
|
||||
Owner, desc="Owner";
|
||||
BroadcastIfShared, desc="Broadcast-If-Shared";
|
||||
BroadcastCounter, desc="Broadcast Counter";
|
||||
Group, desc="Group";
|
||||
Counter, desc="Counter";
|
||||
StickySpatial, desc="StickySpatial";
|
||||
OwnerBroadcast, desc="Owner/Broadcast Hybrid";
|
||||
OwnerGroup, desc="Owner/Group Hybrid";
|
||||
OwnerBroadcastMod, desc="Owner/Broadcast Hybrid-Mod";
|
||||
OwnerGroupMod, desc="Owner/Group Hybrid-Mod";
|
||||
LastNMasks, desc="Last N Masks";
|
||||
BandwidthAdaptive, desc="Bandwidth Adaptive";
|
||||
}
|
||||
|
||||
// MaskPredictorIndex
|
||||
enumeration(MaskPredictorIndex, "MaskPredictorIndex_Undefined", desc="...") {
|
||||
Undefined, desc="Undefined";
|
||||
DataBlock, desc="Data Block";
|
||||
PC, desc="Program Counter";
|
||||
}
|
||||
|
||||
// MaskPredictorTraining
|
||||
enumeration(MaskPredictorTraining, "MaskPredictorTraining_Undefined", desc="...") {
|
||||
Undefined, desc="Undefined";
|
||||
None, desc="None";
|
||||
Implicit, desc="Implicit";
|
||||
Explicit, desc="Explicit";
|
||||
Both, desc="Both";
|
||||
}
|
||||
|
||||
// Network Topologies
|
||||
enumeration(TopologyType, desc="...") {
|
||||
CROSSBAR, desc="One node per chip, single switch crossbar";
|
||||
HIERARCHICAL_SWITCH, desc="One node per chip, totally ordered hierarchical tree switched network";
|
||||
TORUS_2D, desc="One node per chip, 2D torus";
|
||||
PT_TO_PT, desc="One node per chip, Point to Point Network";
|
||||
FILE_SPECIFIED, desc="described by the file NETWORK_FILE";
|
||||
}
|
||||
|
||||
// DNUCA AllocationStrategy
|
||||
enumeration(AllocationStrategy, desc="...") {
|
||||
InMiddle, desc="";
|
||||
InInvCorners, desc="";
|
||||
InSharedSides, desc="";
|
||||
StaticDist, desc="";
|
||||
RandomBank, desc="";
|
||||
FrequencyBank, desc="";
|
||||
FrequencyBlock, desc="";
|
||||
LRUBlock, desc="";
|
||||
}
|
||||
|
||||
// DNUCA SearchMechanism
|
||||
enumeration(SearchMechanism, desc="...") {
|
||||
Perfect, desc="";
|
||||
PartialTag, desc="";
|
||||
BloomFilter, desc="";
|
||||
Random, desc="";
|
||||
None, desc="";
|
||||
}
|
||||
|
||||
// DNUCA link type
|
||||
enumeration(LinkType, desc="...") {
|
||||
RC_1500UM, desc="";
|
||||
RC_2500UM, desc="";
|
||||
TL_9000UM, desc="";
|
||||
TL_11000UM, desc="";
|
||||
TL_13000UM, desc="";
|
||||
NO_ENERGY, desc="";
|
||||
NULL, desc="";
|
||||
}
|
||||
|
||||
// transient request type
|
||||
enumeration(TransientRequestType, desc="...", default="TransientRequestType_Undefined") {
|
||||
Undefined, desc="";
|
||||
OffChip, desc="";
|
||||
OnChip, desc="";
|
||||
LocalTransient, desc="";
|
||||
}
|
||||
|
||||
|
||||
|
67
src/mem/protocol/RubySlicc_MemControl.sm
Normal file
67
src/mem/protocol/RubySlicc_MemControl.sm
Normal file
|
@ -0,0 +1,67 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
// MemoryRequestType used in MemoryMsg
|
||||
|
||||
enumeration(MemoryRequestType, desc="...") {
|
||||
|
||||
// Southbound request: from directory to memory cache
|
||||
// or directory to memory or memory cache to memory
|
||||
MEMORY_READ, desc="Read request to memory";
|
||||
MEMORY_WB, desc="Write back data to memory";
|
||||
|
||||
// response from memory to directory
|
||||
// (These are currently unused!)
|
||||
MEMORY_DATA, desc="Data read from memory";
|
||||
MEMORY_ACK, desc="Write to memory acknowledgement";
|
||||
}
|
||||
|
||||
|
||||
// Message to and from Memory Control
|
||||
|
||||
structure(MemoryMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Physical address for this request";
|
||||
MemoryRequestType Type, desc="Type of memory request (MEMORY_READ or MEMORY_WB)";
|
||||
MachineID Sender, desc="What component sent the data";
|
||||
MachineID OriginalRequestorMachId, desc="What component originally requested";
|
||||
DataBlock DataBlk, desc="Data to writeback";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
// Not all fields used by all protocols:
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
bool ReadX, desc="Exclusive";
|
||||
int Acks, desc="How many acks to expect";
|
||||
|
||||
|
||||
}
|
||||
|
64
src/mem/protocol/RubySlicc_Profiler.sm
Normal file
64
src/mem/protocol/RubySlicc_Profiler.sm
Normal file
|
@ -0,0 +1,64 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Profiler function
|
||||
|
||||
void profileStore(NodeID node, bool needCLB);
|
||||
void profileCacheCLBsize(int size, int numStaleI);
|
||||
void profileMemoryCLBsize(int size, int numStaleI);
|
||||
|
||||
// used by 2level exclusive cache protocols
|
||||
void profile_miss(CacheMsg msg, NodeID id);
|
||||
|
||||
// used by non-fast path protocols
|
||||
void profile_L1Cache_miss(CacheMsg msg, NodeID l1cacheID);
|
||||
|
||||
// used by CMP protocols
|
||||
void profile_L2Cache_miss(GenericRequestType requestType, AccessModeType type, int msgSize, PrefetchBit pfBit, NodeID l2cacheID);
|
||||
void profile_request(string L1CacheStateStr, string L2CacheStateStr, string directoryStateStr, string requestTypeStr);
|
||||
void profileMessageReordering(bool wasReordered);
|
||||
void profileMessageReorderingByNetwork(int vnet, bool wasReordered);
|
||||
void profile_token_retry(Address addr, AccessType type, int count);
|
||||
void profile_persistent_prediction(Address addr, AccessType type);
|
||||
void profile_filter_action(int act);
|
||||
void profile_multicast_retry(Address addr, int count);
|
||||
void profile_outstanding_request(int outstanding);
|
||||
void profile_outstanding_persistent_request(int outstanding);
|
||||
// void profile_overlapping_persistent_request(int overlapping);
|
||||
void profile_average_latency_estimate(int latency);
|
||||
|
||||
// profile the total message delay of a message across a virtual network
|
||||
void profileMsgDelay(int virtualNetwork, int delayCycles);
|
||||
|
||||
// used by transactional-memory protocols
|
||||
void profile_transaction(int numStores);
|
||||
void profile_trans_wb();
|
||||
void profileOverflow(Address addr, MachineID mach);
|
||||
|
||||
|
168
src/mem/protocol/RubySlicc_Types.sm
Normal file
168
src/mem/protocol/RubySlicc_Types.sm
Normal file
|
@ -0,0 +1,168 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// External Types
|
||||
|
||||
external_type(DataBlock, desc="..."){
|
||||
void clear();
|
||||
}
|
||||
|
||||
external_type(MessageBuffer, buffer="yes", inport="yes", outport="yes");
|
||||
|
||||
external_type(OutPort, primitive="yes");
|
||||
|
||||
external_type(InPort, primitive="yes") {
|
||||
bool isReady();
|
||||
void dequeue();
|
||||
int dequeue_getDelayCycles();
|
||||
void recycle();
|
||||
bool isEmpty();
|
||||
}
|
||||
|
||||
external_type(NodeID, default="0");
|
||||
external_type(MachineID);
|
||||
|
||||
external_type(StoreBuffer);
|
||||
|
||||
|
||||
external_type(Set, non_obj="yes") {
|
||||
void setSize(int);
|
||||
void add(NodeID);
|
||||
void addSet(Set);
|
||||
void remove(NodeID);
|
||||
void removeSet(Set);
|
||||
void broadcast();
|
||||
void addRandom();
|
||||
void clear();
|
||||
int count();
|
||||
bool isElement(NodeID);
|
||||
bool isEqual(Set);
|
||||
bool isSuperset(Set);
|
||||
bool intersectionIsEmpty(Set);
|
||||
NodeID smallestElement();
|
||||
}
|
||||
|
||||
external_type(NetDest, non_obj="yes") {
|
||||
void setSize(int);
|
||||
void setSize(int, int);
|
||||
void add(NodeID);
|
||||
void add(MachineID);
|
||||
void addSet(Set);
|
||||
void addNetDest(NetDest);
|
||||
void setNetDest(MachineType, Set);
|
||||
void remove(NodeID);
|
||||
void remove(MachineID);
|
||||
void removeSet(Set);
|
||||
void removeNetDest(NetDest);
|
||||
void broadcast();
|
||||
void broadcast(MachineType);
|
||||
void addRandom();
|
||||
void clear();
|
||||
Set toSet();
|
||||
int count();
|
||||
bool isElement(NodeID);
|
||||
bool isElement(MachineID);
|
||||
bool isSuperset(Set);
|
||||
bool isSuperset(NetDest);
|
||||
bool isEmpty();
|
||||
bool intersectionIsEmpty(Set);
|
||||
bool intersectionIsEmpty(NetDest);
|
||||
MachineID smallestElement(MachineType);
|
||||
}
|
||||
|
||||
external_type(PersistentTable) {
|
||||
void persistentRequestLock(Address, MachineID, AccessType);
|
||||
void persistentRequestUnlock(Address, MachineID);
|
||||
bool okToIssueStarving(Address);
|
||||
MachineID findSmallest(Address);
|
||||
AccessType typeOfSmallest(Address);
|
||||
void markEntries(Address);
|
||||
bool isLocked(Address);
|
||||
int countStarvingForAddress(Address);
|
||||
int countReadStarvingForAddress(Address);
|
||||
}
|
||||
|
||||
external_type(NodePersistentTable) {
|
||||
void persistentRequestLock(Address, NodeID, AccessType);
|
||||
void persistentRequestUnlock(Address, NodeID);
|
||||
bool okToIssueStarving(Address);
|
||||
NodeID findSmallest(Address);
|
||||
AccessType typeOfSmallest(Address);
|
||||
void markEntries(Address);
|
||||
bool isLocked(Address);
|
||||
int countStarvingForAddress(Address);
|
||||
int countReadStarvingForAddress(Address);
|
||||
}
|
||||
|
||||
external_type(Sequencer) {
|
||||
void readCallback(Address, DataBlock, GenericMachineType, PrefetchBit, int);
|
||||
void writeCallback(Address, DataBlock, GenericMachineType, PrefetchBit, int);
|
||||
void readCallback(Address, DataBlock, GenericMachineType, PrefetchBit);
|
||||
void writeCallback(Address, DataBlock, GenericMachineType, PrefetchBit);
|
||||
void readCallback(Address, DataBlock);
|
||||
void writeCallback(Address, DataBlock);
|
||||
void readCallback(Address);
|
||||
void writeCallback(Address);
|
||||
void readCallbackAbort(Address, int);
|
||||
void writeCallbackAbort(Address, int);
|
||||
void readConflictCallback(Address);
|
||||
void writeConflictCallback(Address);
|
||||
void xactCallback(Address);
|
||||
void updateCurrentVersion();
|
||||
void updateLastCommittedVersion();
|
||||
void systemRecovery();
|
||||
void systemRestart();
|
||||
void checkCoherence(Address);
|
||||
void profileNack(Address, int, int, uint64);
|
||||
void resetRequestTime(Address, int);
|
||||
bool isReadAborted(Address, int);
|
||||
bool isWriteAborted(Address, int);
|
||||
}
|
||||
|
||||
external_type(TimerTable, inport="yes") {
|
||||
bool isReady();
|
||||
Address readyAddress();
|
||||
void set(Address, int);
|
||||
void unset(Address);
|
||||
bool isSet(Address);
|
||||
}
|
||||
|
||||
external_type(GenericBloomFilter) {
|
||||
|
||||
void clear(int);
|
||||
void increment(Address, int);
|
||||
void decrement(Address, int);
|
||||
void set(Address, int);
|
||||
void unset(Address, int);
|
||||
|
||||
bool isSet(Address, int);
|
||||
int getCount(Address, int);
|
||||
}
|
||||
|
||||
|
61
src/mem/protocol/RubySlicc_Util.sm
Normal file
61
src/mem/protocol/RubySlicc_Util.sm
Normal file
|
@ -0,0 +1,61 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Miscallaneous Functions
|
||||
|
||||
void error(string msg);
|
||||
void assert(bool condition);
|
||||
int random(int number);
|
||||
Time get_time();
|
||||
Time zero_time();
|
||||
NodeID intToID(int nodenum);
|
||||
int IDToInt(NodeID id);
|
||||
int addressToInt(Address addr);
|
||||
int MessageSizeTypeToInt(MessageSizeType size_type);
|
||||
bool multicast_retry();
|
||||
int numberOfNodes();
|
||||
int numberOfL1CachePerChip();
|
||||
int getAddThenMod(int addend1, int addend2, int modulus);
|
||||
int time_to_int(Time time);
|
||||
Time getTimeModInt(Time time, int modulus);
|
||||
Time getTimePlusInt(Time addend1, int addend2);
|
||||
Time getTimeMinusTime(Time t1, Time t2);
|
||||
Time getPreviousDelayedCycles(Time t1, Time t2);
|
||||
void WARN_ERROR_TIME(Time time);
|
||||
void procProfileCoherenceRequest(NodeID node, bool needCLB);
|
||||
void dirProfileCoherenceRequest(NodeID node, bool needCLB);
|
||||
bool isPerfectProtocol();
|
||||
bool L1trainsPrefetcher();
|
||||
int max_tokens();
|
||||
int N_tokens();
|
||||
bool distributedPersistentEnabled();
|
||||
Address setOffset(Address addr, int offset);
|
||||
Address makeLineAddress(Address addr);
|
||||
|
||||
|
7
src/mem/protocol/RubySlicc_interfaces.slicc
Normal file
7
src/mem/protocol/RubySlicc_interfaces.slicc
Normal file
|
@ -0,0 +1,7 @@
|
|||
RubySlicc_Exports.sm
|
||||
RubySlicc_Types.sm
|
||||
RubySlicc_Util.sm
|
||||
RubySlicc_ComponentMapping.sm
|
||||
RubySlicc_Profiler.sm
|
||||
RubySlicc_Defines.sm
|
||||
RubySlicc_MemControl.sm
|
|
@ -0,0 +1,49 @@
|
|||
MSI_dir_L1_MOSI_dir_L2_SNUCA_CMP
|
||||
---------------------------------------
|
||||
|
||||
|
||||
CMP System structure:
|
||||
|
||||
A CMP (Chip MultiProcessor) System is composed of one or more CMP chips. A CMP chip consists of some number of processors, each with private L1 I+D caches and one shared L2 cache. The shared L2 cache can be sub-divided into banks where each bank as a separate cache controller. One global interconnect is defined that connects all the components in the system including the L1 caches, the L2 cache banks, and the memories/directories.
|
||||
|
||||
High-level Protocol Description:
|
||||
|
||||
- The L1 has 3 stable states: M, S, I
|
||||
|
||||
- L2 maintains strict inclusion and has full knowledge of on-chip L1 sharers via individual bits in the cache tag. The stable
|
||||
states are below:
|
||||
|
||||
M,O,S,I : normal meanings
|
||||
SS : L2 entry shared, also present in one or more L1s or ext L2s
|
||||
SO : L2 entry owned, also present in one or more L1s or ext L2s
|
||||
MT : L2 entry modified in a local L1. L2 copy is stale
|
||||
|
||||
- The protocol has a strict on-chip hierarchy where the L1 caches only communicate with their on-chip L2 cache, while off-chip the L2 cache communicates with the directory as well as directly responding to the other L2 caches.
|
||||
|
||||
High Level Event Description:
|
||||
|
||||
On a L1 GETS miss -
|
||||
> The L2 controller will satisfy the miss immediately if in M, S, SS, or OS.
|
||||
> If the L2 controller is in MT, the L2 controller will issue a down-grade request to the on-chip L1 sharer. The L1 sharer will then downgrade to S and copy it's dirty block to the L2. The L2 will then forward that copy to the L1 GETS requestor.
|
||||
> If not present, the L2 will issue a GETS to the directory. The directory will either forward the request, or respond with data. If forwarded to another L2 controller, the L2 owner will respond with data directly to the L2 requestor which would then respond to the original L1 requestor.
|
||||
|
||||
On a L1 GETX miss -
|
||||
> The L2 controller will satisfy the miss immediately if in M
|
||||
> If the L2 controller is in MT, the L2 controller will issue an invalidate request to the on-chip L1 sharer. The L1 sharer will then invalidate the block and writeback it's dirty block to the L2. The L2 will then forward that copy to the L1 GETX requestor.
|
||||
> If the L2 controller is in O, S, or I, the L2 controller will issue a GETX request to the directory. The L2 will wait to receive the data and the necessary number of acks before responding to the L1 GETX requestor with the data and exclusive permission.
|
||||
> If the L2 controller is in SS or SO, the L2 controller will issue a GETX request to the directory as well as invalidate requests to the on-chip L1 copies. The L2 will wait to receive the data and the necessary number of acks (both on and off chip) before responding to the L1 GETX requestor with the data and exclusive permission.
|
||||
|
||||
Other minute details:
|
||||
|
||||
The L2 acknowledges all L1 replacements
|
||||
The L1 acknowledges L2 invalidation requests
|
||||
The L2 sends an ack to the directory on a 3-hop transfer
|
||||
The forward request network (Dir -> L2 -> L1) is assumed to be pt-to-pt ordered
|
||||
The L1 request network (L1 -> L2) is assumed to be pt-to-pt ordered
|
||||
All other networks are unordered
|
||||
|
||||
Ruby Implementation Details:
|
||||
|
||||
- The new component network must be used with this protocol
|
||||
- Each ruby node contains a L1 cache controller, 0 or more L2 cache controllers, and 0 or more directories. There must be at least one directory in the system and at least one L2 cache controller per chip. The directories are statically partitioned by address across the entire system (SMP), while the L2Cache banks are statically partitioned by address across a single chip. There must be some power of 2 for each machine type.
|
||||
- BUG ALERT: There is a single pool of TBE Entries for the L2 Controller. Therefore it is possible to encounter a resource deadlock for these entries between satisfying L1 requests and directory requests.
|
|
@ -0,0 +1,49 @@
|
|||
MSI_dir_L1_MOSI_dir_L2_SNUCA_CMP
|
||||
---------------------------------------
|
||||
|
||||
|
||||
CMP System structure:
|
||||
|
||||
A CMP (Chip MultiProcessor) System is composed of one or more CMP chips. A CMP chip consists of some number of processors, each with private L1 I+D caches and one shared L2 cache. The shared L2 cache can be sub-divided into banks where each bank as a separate cache controller. One global interconnect is defined that connects all the components in the system including the L1 caches, the L2 cache banks, and the memories/directories.
|
||||
|
||||
High-level Protocol Description:
|
||||
|
||||
- The L1 has 3 stable states: M, S, I
|
||||
|
||||
- L2 maintains strict inclusion and has full knowledge of on-chip L1 sharers via individual bits in the cache tag. The stable
|
||||
states are below:
|
||||
|
||||
M,O,S,I : normal meanings
|
||||
SS : L2 entry shared, also present in one or more L1s or ext L2s
|
||||
SO : L2 entry owned, also present in one or more L1s or ext L2s
|
||||
MT : L2 entry modified in a local L1. L2 copy is stale
|
||||
|
||||
- The protocol has a strict on-chip hierarchy where the L1 caches only communicate with their on-chip L2 cache, while off-chip the L2 cache communicates with the directory as well as directly responding to the other L2 caches.
|
||||
|
||||
High Level Event Description:
|
||||
|
||||
On a L1 GETS miss -
|
||||
> The L2 controller will satisfy the miss immediately if in M, S, SS, or OS.
|
||||
> If the L2 controller is in MT, the L2 controller will issue a down-grade request to the on-chip L1 sharer. The L1 sharer will then downgrade to S and copy it's dirty block to the L2. The L2 will then forward that copy to the L1 GETS requestor.
|
||||
> If not present, the L2 will issue a GETS to the directory. The directory will either forward the request, or respond with data. If forwarded to another L2 controller, the L2 owner will respond with data directly to the L2 requestor which would then respond to the original L1 requestor.
|
||||
|
||||
On a L1 GETX miss -
|
||||
> The L2 controller will satisfy the miss immediately if in M
|
||||
> If the L2 controller is in MT, the L2 controller will issue an invalidate request to the on-chip L1 sharer. The L1 sharer will then invalidate the block and writeback it's dirty block to the L2. The L2 will then forward that copy to the L1 GETX requestor.
|
||||
> If the L2 controller is in O, S, or I, the L2 controller will issue a GETX request to the directory. The L2 will wait to receive the data and the necessary number of acks before responding to the L1 GETX requestor with the data and exclusive permission.
|
||||
> If the L2 controller is in SS or SO, the L2 controller will issue a GETX request to the directory as well as invalidate requests to the on-chip L1 copies. The L2 will wait to receive the data and the necessary number of acks (both on and off chip) before responding to the L1 GETX requestor with the data and exclusive permission.
|
||||
|
||||
Other minute details:
|
||||
|
||||
The L2 acknowledges all L1 replacements
|
||||
The L1 acknowledges L2 invalidation requests
|
||||
The L2 sends an ack to the directory on a 3-hop transfer
|
||||
The forward request network (Dir -> L2 -> L1) is assumed to be pt-to-pt ordered
|
||||
The L1 request network (L1 -> L2) is assumed to be pt-to-pt ordered
|
||||
All other networks are unordered
|
||||
|
||||
Ruby Implementation Details:
|
||||
|
||||
- The new component network must be used with this protocol
|
||||
- Each ruby node contains a L1 cache controller, 0 or more L2 cache controllers, and 0 or more directories. There must be at least one directory in the system and at least one L2 cache controller per chip. The directories are statically partitioned by address across the entire system (SMP), while the L2Cache banks are statically partitioned by address across a single chip. There must be some power of 2 for each machine type.
|
||||
- BUG ALERT: There is a single pool of TBE Entries for the L2 Controller. Therefore it is possible to encounter a resource deadlock for these entries between satisfying L1 requests and directory requests.
|
39
src/mem/protocol/standard_1level_SMP-protocol.sm
Normal file
39
src/mem/protocol/standard_1level_SMP-protocol.sm
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
// global protocol features
|
||||
global(Protocol, desc="Global properties of this protocol",
|
||||
interface = "AbstractProtocol") {
|
||||
bool TwoLevelCache := false;
|
||||
}
|
||||
|
36
src/mem/protocol/standard_CMP-protocol.sm
Normal file
36
src/mem/protocol/standard_CMP-protocol.sm
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// global protocol features
|
||||
global(Protocol, desc="Global properties of this protocol",
|
||||
interface = "AbstractProtocol") {
|
||||
bool TwoLevelCache := true;
|
||||
bool CMP := true;
|
||||
}
|
||||
|
39
src/mem/protocol/standard_SMP-protocol.sm
Normal file
39
src/mem/protocol/standard_SMP-protocol.sm
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
// global protocol features
|
||||
global(Protocol, desc="Global properties of this protocol",
|
||||
interface = "AbstractProtocol") {
|
||||
bool TwoLevelCache := true;
|
||||
}
|
||||
|
10
src/mem/ruby/Decomissioning_note
Normal file
10
src/mem/ruby/Decomissioning_note
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
1. While decomissioning log_tm
|
||||
|
||||
a. I left lots of transaction related stuff ( Xact.... ) in commands.C
|
||||
Made the minimal changes to compile it properly
|
||||
|
||||
|
||||
make[1]: *** No rule to make target `amd64-linux/generated/MI_example/obj/PartialAddressFilter.o', needed by `amd64-linux/generated/MI_example/bin/libruby.so
|
||||
|
||||
|
63
src/mem/ruby/FakeSimicsDataTypes.hh
Normal file
63
src/mem/ruby/FakeSimicsDataTypes.hh
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef FAKE_SIMICS_DATA_TYPES_H
|
||||
#define FAKE_SIMICS_DATA_TYPES_H
|
||||
|
||||
typedef struct attr_value attr_value_t;
|
||||
|
||||
typedef enum {
|
||||
Sim_Val_Invalid = 0,
|
||||
Sim_Val_String = 1,
|
||||
Sim_Val_Integer = 2,
|
||||
Sim_Val_Floating = 3,
|
||||
Sim_Val_List = 4,
|
||||
Sim_Val_Data = 5,
|
||||
Sim_Val_Nil = 6,
|
||||
Sim_Val_Object = 7
|
||||
} attr_kind_t;
|
||||
|
||||
typedef struct attr_list attr_list_t;
|
||||
|
||||
struct attr_list {
|
||||
int size;
|
||||
struct attr_value *vector;
|
||||
};
|
||||
|
||||
struct attr_value {
|
||||
attr_kind_t kind;
|
||||
union {
|
||||
const char *string; /* Sim_Val_String */
|
||||
unsigned long long integer; /* Sim_Val_Integer */
|
||||
double floating; /* Sim_Val_Floating */
|
||||
void *object; /* Sim_Val_Object */
|
||||
attr_list_t list; /* Sim_Val_List */
|
||||
} u;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
Sim_Set_Ok,
|
||||
Sim_Set_Need_Integer,
|
||||
Sim_Set_Need_Floating,
|
||||
Sim_Set_Need_String,
|
||||
Sim_Set_Need_List,
|
||||
Sim_Set_Need_Data,
|
||||
Sim_Set_Need_Object,
|
||||
Sim_Set_Object_Not_Found,
|
||||
Sim_Set_Interface_Not_Found,
|
||||
Sim_Set_Illegal_Value,
|
||||
Sim_Set_Illegal_Type,
|
||||
Sim_Set_Illegal_Index,
|
||||
Sim_Set_Attribute_Not_Found,
|
||||
Sim_Set_Not_Writable,
|
||||
Sim_Set_Ignored
|
||||
} set_error_t;
|
||||
|
||||
|
||||
typedef attr_value_t (*get_attr_t)(void *ptr,
|
||||
void *obj,
|
||||
attr_value_t *idx);
|
||||
|
||||
typedef set_error_t (*set_attr_t)(void *ptr,
|
||||
void *obj,
|
||||
attr_value_t *val,
|
||||
attr_value_t *idx);
|
||||
|
||||
#endif // #ifndef FAKE_SIMICS_DATA_TYPES_H
|
104
src/mem/ruby/README.debugging
Normal file
104
src/mem/ruby/README.debugging
Normal file
|
@ -0,0 +1,104 @@
|
|||
# ------ Debugging the Ruby Tester ------
|
||||
|
||||
You can compile Ruby with debugging turned on.
|
||||
|
||||
cd ruby
|
||||
[vim or emacs] Makefile
|
||||
|
||||
Change OPT_FLAGS to "-g -O0" (the first OPT_FLAGS line). Make
|
||||
sure all the other OPT_FLAGS lines are commented out.
|
||||
|
||||
Change DEBUG_FLAGS to "-DRUBY_DEBUG=true". (Just uncomment the
|
||||
first DEBUG_FLAGS line, and comment out the second DEBUG_FLAGS
|
||||
line.)
|
||||
|
||||
You can choose which component or components to debug, and the
|
||||
level of verbosity. For example,
|
||||
|
||||
"x86-linux/generated/MOSI_SMP_bcast/bin/tester.exec -l 100000 -v med -c n"
|
||||
|
||||
gives you debugging information about the network component at
|
||||
the medium verbosity level. -v selects the verbosity, which may
|
||||
be low, med, high, or none. -c selects the component or
|
||||
components.
|
||||
|
||||
"x86-linux/generated/MOSI_SMP_bcast/bin/tester.exec -l 100000 -v med -c nSt"
|
||||
|
||||
debugs the network, the sequencer, and the tester.
|
||||
|
||||
For a list of the components you can debug, just run the tester with
|
||||
no arguments, and it will display a list of valid components. The
|
||||
components are defined in ruby/common/Debug.def.
|
||||
|
||||
The protocol debug trace is especially useful for debugging cache coherence protocols. This must be enabled at compile-time by ensuring that PROTOCOL_DEBUG_TRACE is set to true for rubyconfig.defaults (if running in Simics) or tester.defaults. You must specify the time to start tracing. The following starts the protocol trace immediately (at time 1)
|
||||
|
||||
"x86-linux/generated/MOSI_SMP_bcast/bin/tester.exec -l 100000 -s 1"
|
||||
|
||||
Also, if something seems to be wrong and you're not sure where to
|
||||
start looking, it may help to run the tester for a longer time,
|
||||
e.g.
|
||||
|
||||
"x86-linux/generated/MOSI_SMP_bcast/bin/tester.exec -l 500000"
|
||||
|
||||
This may help because some problems eventually show up as
|
||||
deadlock, but the tester has to run for a long time before a
|
||||
deadlock is detected.
|
||||
|
||||
Once your simulator has succeeded on the tester for a certain
|
||||
number of cycles, say 1000000, you may want to set the
|
||||
RANDOMIZATION variable in ruby/config/tester.defaults to "true"
|
||||
for more thorough testing. However, RANDOMIZATION may not work in
|
||||
all situations because it overrides some of the ordering in the
|
||||
network and may break your simulator in ways you don't like. For
|
||||
example, messages are added to MessageBuffers with random
|
||||
latency.
|
||||
|
||||
By default the tester driver is a generator that issues random store
|
||||
and load requests. This driver does a good job of stressing the
|
||||
cache coherency protocol by issuing racy store requests from multiple
|
||||
processors to a cache line then checks the stores with a single load.
|
||||
|
||||
Other tester drivers are available. By setting the g_SYNTHETIC_DRIVER
|
||||
to true in ruby/config/tester.defaults, you enable a tester that generates
|
||||
racy lock requests for a number of locks indicated by g_synthetic_locks.
|
||||
|
||||
Another tester driver is a series of non-racy deterministic testers. By
|
||||
setting the g_DETERMINISTIC_DRIVER in ruby/config/tester.defaults to true,
|
||||
you enable the deterministic tester. The deterministic tester can do
|
||||
different types of deterministic tests as specified by g_SpecifiedGenerator
|
||||
string. The deterministic tester works best when RANDOMIZATION is set to
|
||||
false. To easily track the queues being used with the deterministic tester,
|
||||
use the following debug flags "-v low -c nq".
|
||||
|
||||
# ------ Debugging Ruby in Simics ------
|
||||
|
||||
When you're running Simics, the debugging components and
|
||||
verbosity levels are the same. However, the way you communicate
|
||||
with Ruby changes.
|
||||
|
||||
See the README.quickstart for information on compiling the Ruby
|
||||
module and loading it into Simics. Once you've got Simics
|
||||
running, with the Ruby module loaded, you can set up Ruby
|
||||
debugging.
|
||||
|
||||
To set the debugging verbosity level, run:
|
||||
|
||||
simics> ruby0.debug-verb med
|
||||
|
||||
To set the debugging components, run: (see common/Debug.def for complete list
|
||||
of component shortcuts)
|
||||
|
||||
simics> ruby0.debug-filter n
|
||||
|
||||
(NOTE: sometimes simics will interpret a single letter as a
|
||||
command; e.g. expanding "p" into "print". If simics gives you an
|
||||
error when setting the debug filter, try setting it like so:
|
||||
simics> ruby0.debug-filter "n")
|
||||
|
||||
This gives the same kind of debugging information as running the
|
||||
tester with "-v med -c n".
|
||||
|
||||
You can also send the debugging output to a file (may be a good
|
||||
idea, since there's a lot of it). To do this, run:
|
||||
|
||||
simics> ruby0.debug-output-file <filename>
|
363
src/mem/ruby/buffers/MessageBuffer.cc
Normal file
363
src/mem/ruby/buffers/MessageBuffer.cc
Normal file
|
@ -0,0 +1,363 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "MessageBuffer.hh"
|
||||
#include "RubyConfig.hh"
|
||||
|
||||
MessageBuffer::MessageBuffer()
|
||||
{
|
||||
m_msg_counter = 0;
|
||||
m_consumer_ptr = NULL;
|
||||
m_ordering_set = false;
|
||||
m_strict_fifo = true;
|
||||
m_size = 0;
|
||||
m_max_size = -1;
|
||||
m_last_arrival_time = 0;
|
||||
m_randomization = true;
|
||||
m_size_last_time_size_checked = 0;
|
||||
m_time_last_time_size_checked = 0;
|
||||
m_time_last_time_enqueue = 0;
|
||||
m_time_last_time_pop = 0;
|
||||
m_size_at_cycle_start = 0;
|
||||
m_msgs_this_cycle = 0;
|
||||
m_not_avail_count = 0;
|
||||
m_priority_rank = 0;
|
||||
}
|
||||
|
||||
MessageBuffer::MessageBuffer(const Chip* chip_ptr) // The chip_ptr is ignored, but could be used for extra debugging
|
||||
{
|
||||
m_msg_counter = 0;
|
||||
m_consumer_ptr = NULL;
|
||||
m_ordering_set = false;
|
||||
m_strict_fifo = true;
|
||||
m_size = 0;
|
||||
m_max_size = -1;
|
||||
m_last_arrival_time = 0;
|
||||
m_randomization = true;
|
||||
m_size_last_time_size_checked = 0;
|
||||
m_time_last_time_size_checked = 0;
|
||||
m_time_last_time_enqueue = 0;
|
||||
m_time_last_time_pop = 0;
|
||||
m_size_at_cycle_start = 0;
|
||||
m_msgs_this_cycle = 0;
|
||||
m_not_avail_count = 0;
|
||||
m_priority_rank = 0;
|
||||
}
|
||||
|
||||
int MessageBuffer::getSize()
|
||||
{
|
||||
if(m_time_last_time_size_checked == g_eventQueue_ptr->getTime()){
|
||||
return m_size_last_time_size_checked;
|
||||
} else {
|
||||
m_time_last_time_size_checked = g_eventQueue_ptr->getTime();
|
||||
m_size_last_time_size_checked = m_size;
|
||||
return m_size;
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageBuffer::areNSlotsAvailable(int n)
|
||||
{
|
||||
|
||||
// fast path when message buffers have infinite size
|
||||
if(m_max_size == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// determine my correct size for the current cycle
|
||||
// pop operations shouldn't effect the network's visible size until next cycle,
|
||||
// but enqueue operations effect the visible size immediately
|
||||
int current_size = max(m_size_at_cycle_start, m_size);
|
||||
if (m_time_last_time_pop < g_eventQueue_ptr->getTime()) { // no pops this cycle - m_size is correct
|
||||
current_size = m_size;
|
||||
} else {
|
||||
if (m_time_last_time_enqueue < g_eventQueue_ptr->getTime()) { // no enqueues this cycle - m_size_at_cycle_start is correct
|
||||
current_size = m_size_at_cycle_start;
|
||||
} else { // both pops and enqueues occured this cycle - add new enqueued msgs to m_size_at_cycle_start
|
||||
current_size = m_size_at_cycle_start+m_msgs_this_cycle;
|
||||
}
|
||||
}
|
||||
|
||||
// now compare the new size with our max size
|
||||
if(current_size+n <= m_max_size){
|
||||
return true;
|
||||
} else {
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,n);
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,current_size);
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,m_size);
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,m_max_size);
|
||||
m_not_avail_count++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const MsgPtr MessageBuffer::getMsgPtrCopy() const
|
||||
{
|
||||
assert(isReady());
|
||||
|
||||
MsgPtr temp_msg;
|
||||
temp_msg = *(m_prio_heap.peekMin().m_msgptr.ref());
|
||||
assert(temp_msg.ref() != NULL);
|
||||
return temp_msg;
|
||||
}
|
||||
|
||||
const Message* MessageBuffer::peekAtHeadOfQueue() const
|
||||
{
|
||||
const Message* msg_ptr;
|
||||
DEBUG_NEWLINE(QUEUE_COMP,MedPrio);
|
||||
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,"Peeking at head of queue " + m_name + " time: "
|
||||
+ int_to_string(g_eventQueue_ptr->getTime()) + ".");
|
||||
assert(isReady());
|
||||
|
||||
msg_ptr = m_prio_heap.peekMin().m_msgptr.ref();
|
||||
assert(msg_ptr != NULL);
|
||||
|
||||
DEBUG_EXPR(QUEUE_COMP,MedPrio,*msg_ptr);
|
||||
DEBUG_NEWLINE(QUEUE_COMP,MedPrio);
|
||||
return msg_ptr;
|
||||
}
|
||||
|
||||
// FIXME - move me somewhere else
|
||||
int random_time()
|
||||
{
|
||||
int time = 1;
|
||||
time += random() & 0x3; // [0...3]
|
||||
if ((random() & 0x7) == 0) { // 1 in 8 chance
|
||||
time += 100 + (random() % 0xf); // 100 + [1...15]
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
void MessageBuffer::enqueue(const MsgPtr& message, Time delta)
|
||||
{
|
||||
DEBUG_NEWLINE(QUEUE_COMP,HighPrio);
|
||||
DEBUG_MSG(QUEUE_COMP,HighPrio,"enqueue " + m_name + " time: "
|
||||
+ int_to_string(g_eventQueue_ptr->getTime()) + ".");
|
||||
DEBUG_EXPR(QUEUE_COMP,MedPrio,message);
|
||||
DEBUG_NEWLINE(QUEUE_COMP,HighPrio);
|
||||
|
||||
m_msg_counter++;
|
||||
m_size++;
|
||||
|
||||
// record current time incase we have a pop that also adjusts my size
|
||||
if (m_time_last_time_enqueue < g_eventQueue_ptr->getTime()) {
|
||||
m_msgs_this_cycle = 0; // first msg this cycle
|
||||
m_time_last_time_enqueue = g_eventQueue_ptr->getTime();
|
||||
}
|
||||
m_msgs_this_cycle++;
|
||||
|
||||
// ASSERT(m_max_size == -1 || m_size <= m_max_size + 1);
|
||||
// the plus one is a kluge because of a SLICC issue
|
||||
|
||||
if (!m_ordering_set) {
|
||||
WARN_EXPR(*this);
|
||||
WARN_EXPR(m_name);
|
||||
ERROR_MSG("Ordering property of this queue has not been set");
|
||||
}
|
||||
|
||||
// Calculate the arrival time of the message, that is, the first
|
||||
// cycle the message can be dequeued.
|
||||
assert(delta>0);
|
||||
Time current_time = g_eventQueue_ptr->getTime();
|
||||
Time arrival_time = 0;
|
||||
if (!RANDOMIZATION || (m_randomization == false)) {
|
||||
// No randomization
|
||||
arrival_time = current_time + delta;
|
||||
|
||||
} else {
|
||||
// Randomization - ignore delta
|
||||
if (m_strict_fifo) {
|
||||
if (m_last_arrival_time < current_time) {
|
||||
m_last_arrival_time = current_time;
|
||||
}
|
||||
arrival_time = m_last_arrival_time + random_time();
|
||||
} else {
|
||||
arrival_time = current_time + random_time();
|
||||
}
|
||||
}
|
||||
|
||||
// Check the arrival time
|
||||
assert(arrival_time > current_time);
|
||||
if (m_strict_fifo) {
|
||||
if (arrival_time >= m_last_arrival_time) {
|
||||
|
||||
} else {
|
||||
WARN_EXPR(*this);
|
||||
WARN_EXPR(m_name);
|
||||
WARN_EXPR(current_time);
|
||||
WARN_EXPR(delta);
|
||||
WARN_EXPR(arrival_time);
|
||||
WARN_EXPR(m_last_arrival_time);
|
||||
ERROR_MSG("FIFO ordering violated");
|
||||
}
|
||||
}
|
||||
m_last_arrival_time = arrival_time;
|
||||
|
||||
// compute the delay cycles and set enqueue time
|
||||
Message* msg_ptr = NULL;
|
||||
msg_ptr = message.mod_ref();
|
||||
assert(msg_ptr != NULL);
|
||||
assert(g_eventQueue_ptr->getTime() >= msg_ptr->getLastEnqueueTime()); // ensure we aren't dequeued early
|
||||
msg_ptr->setDelayedCycles((g_eventQueue_ptr->getTime() - msg_ptr->getLastEnqueueTime())+msg_ptr->getDelayedCycles());
|
||||
msg_ptr->setLastEnqueueTime(arrival_time);
|
||||
|
||||
// Insert the message into the priority heap
|
||||
MessageBufferNode thisNode(arrival_time, m_msg_counter, message);
|
||||
m_prio_heap.insert(thisNode);
|
||||
|
||||
DEBUG_NEWLINE(QUEUE_COMP,HighPrio);
|
||||
DEBUG_MSG(QUEUE_COMP,HighPrio,"enqueue " + m_name
|
||||
+ " with arrival_time " + int_to_string(arrival_time)
|
||||
+ " cur_time: " + int_to_string(g_eventQueue_ptr->getTime()) + ".");
|
||||
DEBUG_EXPR(QUEUE_COMP,MedPrio,message);
|
||||
DEBUG_NEWLINE(QUEUE_COMP,HighPrio);
|
||||
|
||||
// Schedule the wakeup
|
||||
if (m_consumer_ptr != NULL) {
|
||||
g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, arrival_time);
|
||||
} else {
|
||||
WARN_EXPR(*this);
|
||||
WARN_EXPR(m_name);
|
||||
ERROR_MSG("No consumer");
|
||||
}
|
||||
}
|
||||
|
||||
int MessageBuffer::dequeue_getDelayCycles(MsgPtr& message)
|
||||
{
|
||||
int delay_cycles = -1; // null value
|
||||
|
||||
dequeue(message);
|
||||
|
||||
// get the delay cycles
|
||||
delay_cycles = setAndReturnDelayCycles(message);
|
||||
|
||||
assert(delay_cycles >= 0);
|
||||
return delay_cycles;
|
||||
}
|
||||
|
||||
void MessageBuffer::dequeue(MsgPtr& message)
|
||||
{
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,"dequeue from " + m_name);
|
||||
message = m_prio_heap.peekMin().m_msgptr;
|
||||
|
||||
pop();
|
||||
DEBUG_EXPR(QUEUE_COMP,MedPrio,message);
|
||||
}
|
||||
|
||||
int MessageBuffer::dequeue_getDelayCycles()
|
||||
{
|
||||
int delay_cycles = -1; // null value
|
||||
|
||||
// get MsgPtr of the message about to be dequeued
|
||||
MsgPtr message = m_prio_heap.peekMin().m_msgptr;
|
||||
|
||||
// get the delay cycles
|
||||
delay_cycles = setAndReturnDelayCycles(message);
|
||||
|
||||
dequeue();
|
||||
|
||||
assert(delay_cycles >= 0);
|
||||
return delay_cycles;
|
||||
}
|
||||
|
||||
void MessageBuffer::pop()
|
||||
{
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,"pop from " + m_name);
|
||||
assert(isReady());
|
||||
Time ready_time = m_prio_heap.extractMin().m_time;
|
||||
// record previous size and time so the current buffer size isn't adjusted until next cycle
|
||||
if (m_time_last_time_pop < g_eventQueue_ptr->getTime()) {
|
||||
m_size_at_cycle_start = m_size;
|
||||
m_time_last_time_pop = g_eventQueue_ptr->getTime();
|
||||
}
|
||||
m_size--;
|
||||
}
|
||||
|
||||
void MessageBuffer::clear()
|
||||
{
|
||||
while(m_prio_heap.size() > 0){
|
||||
m_prio_heap.extractMin();
|
||||
}
|
||||
|
||||
ASSERT(m_prio_heap.size() == 0);
|
||||
|
||||
m_msg_counter = 0;
|
||||
m_size = 0;
|
||||
m_time_last_time_enqueue = 0;
|
||||
m_time_last_time_pop = 0;
|
||||
m_size_at_cycle_start = 0;
|
||||
m_msgs_this_cycle = 0;
|
||||
}
|
||||
|
||||
void MessageBuffer::recycle()
|
||||
{
|
||||
// const int RECYCLE_LATENCY = 3;
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,"recycling " + m_name);
|
||||
assert(isReady());
|
||||
MessageBufferNode node = m_prio_heap.extractMin();
|
||||
node.m_time = g_eventQueue_ptr->getTime() + RECYCLE_LATENCY;
|
||||
m_prio_heap.insert(node);
|
||||
g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, g_eventQueue_ptr->getTime() + RECYCLE_LATENCY);
|
||||
}
|
||||
|
||||
int MessageBuffer::setAndReturnDelayCycles(MsgPtr& message)
|
||||
{
|
||||
int delay_cycles = -1; // null value
|
||||
|
||||
// get the delay cycles of the message at the top of the queue
|
||||
Message* msg_ptr = message.ref();
|
||||
|
||||
// this function should only be called on dequeue
|
||||
// ensure the msg hasn't been enqueued
|
||||
assert(msg_ptr->getLastEnqueueTime() <= g_eventQueue_ptr->getTime());
|
||||
msg_ptr->setDelayedCycles((g_eventQueue_ptr->getTime() - msg_ptr->getLastEnqueueTime())+msg_ptr->getDelayedCycles());
|
||||
delay_cycles = msg_ptr->getDelayedCycles();
|
||||
|
||||
assert(delay_cycles >= 0);
|
||||
return delay_cycles;
|
||||
}
|
||||
|
||||
void MessageBuffer::print(ostream& out) const
|
||||
{
|
||||
out << "[MessageBuffer: ";
|
||||
if (m_consumer_ptr != NULL) {
|
||||
out << " consumer-yes ";
|
||||
}
|
||||
out << m_prio_heap << "] " << m_name << endl;
|
||||
}
|
||||
|
||||
void MessageBuffer::printStats(ostream& out)
|
||||
{
|
||||
out << "MessageBuffer: " << m_name << " stats - msgs:" << m_msg_counter << " full:" << m_not_avail_count << endl;
|
||||
}
|
||||
|
156
src/mem/ruby/buffers/MessageBuffer.hh
Normal file
156
src/mem/ruby/buffers/MessageBuffer.hh
Normal file
|
@ -0,0 +1,156 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Description: Unordered buffer of messages that can be inserted such
|
||||
* that they can be dequeued after a given delta time has expired.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MESSAGEBUFFER_H
|
||||
#define MESSAGEBUFFER_H
|
||||
|
||||
#include "Global.hh"
|
||||
#include "MessageBufferNode.hh"
|
||||
#include "Consumer.hh"
|
||||
#include "EventQueue.hh"
|
||||
#include "Message.hh"
|
||||
#include "PrioHeap.hh"
|
||||
#include "util.hh"
|
||||
|
||||
class Chip;
|
||||
|
||||
class MessageBuffer {
|
||||
public:
|
||||
// Constructors
|
||||
MessageBuffer();
|
||||
MessageBuffer(const Chip* chip_ptr); // The chip_ptr is ignored, but could be used for extra debugging
|
||||
|
||||
// Use Default Destructor
|
||||
// ~MessageBuffer()
|
||||
|
||||
// Public Methods
|
||||
|
||||
static void printConfig(ostream& out) {}
|
||||
|
||||
// TRUE if head of queue timestamp <= SystemTime
|
||||
bool isReady() const {
|
||||
return ((m_prio_heap.size() > 0) &&
|
||||
(m_prio_heap.peekMin().m_time <= g_eventQueue_ptr->getTime()));
|
||||
}
|
||||
|
||||
bool areNSlotsAvailable(int n);
|
||||
int getPriority() { return m_priority_rank; }
|
||||
void setPriority(int rank) { m_priority_rank = rank; }
|
||||
void setConsumer(Consumer* consumer_ptr) { ASSERT(m_consumer_ptr==NULL); m_consumer_ptr = consumer_ptr; }
|
||||
void setDescription(const string& name) { m_name = name; }
|
||||
string getDescription() { return m_name;}
|
||||
|
||||
Consumer* getConsumer() { return m_consumer_ptr; }
|
||||
|
||||
const Message* peekAtHeadOfQueue() const;
|
||||
const Message* peek() const { return peekAtHeadOfQueue(); }
|
||||
const MsgPtr getMsgPtrCopy() const;
|
||||
const MsgPtr& peekMsgPtr() const { assert(isReady()); return m_prio_heap.peekMin().m_msgptr; }
|
||||
const MsgPtr& peekMsgPtrEvenIfNotReady() const {return m_prio_heap.peekMin().m_msgptr; }
|
||||
|
||||
void enqueue(const MsgPtr& message) { enqueue(message, 1); }
|
||||
void enqueue(const MsgPtr& message, Time delta);
|
||||
// void enqueueAbsolute(const MsgPtr& message, Time absolute_time);
|
||||
int dequeue_getDelayCycles(MsgPtr& message); // returns delay cycles of the message
|
||||
void dequeue(MsgPtr& message);
|
||||
int dequeue_getDelayCycles(); // returns delay cycles of the message
|
||||
void dequeue() { pop(); }
|
||||
void pop();
|
||||
void recycle();
|
||||
bool isEmpty() const { return m_prio_heap.size() == 0; }
|
||||
|
||||
void setOrdering(bool order) { m_strict_fifo = order; m_ordering_set = true; }
|
||||
void setSize(int size) {m_max_size = size;}
|
||||
int getSize();
|
||||
void setRandomization(bool random_flag) { m_randomization = random_flag; }
|
||||
|
||||
void clear();
|
||||
|
||||
void print(ostream& out) const;
|
||||
void printStats(ostream& out);
|
||||
void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; }
|
||||
|
||||
private:
|
||||
// Private Methods
|
||||
int setAndReturnDelayCycles(MsgPtr& message);
|
||||
|
||||
// Private copy constructor and assignment operator
|
||||
MessageBuffer(const MessageBuffer& obj);
|
||||
MessageBuffer& operator=(const MessageBuffer& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
Consumer* m_consumer_ptr; // Consumer to signal a wakeup(), can be NULL
|
||||
PrioHeap<MessageBufferNode> m_prio_heap;
|
||||
string m_name;
|
||||
|
||||
int m_max_size;
|
||||
int m_size;
|
||||
|
||||
Time m_time_last_time_size_checked;
|
||||
int m_size_last_time_size_checked;
|
||||
|
||||
// variables used so enqueues appear to happen imediately, while pop happen the next cycle
|
||||
Time m_time_last_time_enqueue;
|
||||
Time m_time_last_time_pop;
|
||||
int m_size_at_cycle_start;
|
||||
int m_msgs_this_cycle;
|
||||
|
||||
int m_not_avail_count; // count the # of times I didn't have N slots available
|
||||
int m_msg_counter;
|
||||
int m_priority_rank;
|
||||
bool m_strict_fifo;
|
||||
bool m_ordering_set;
|
||||
bool m_randomization;
|
||||
Time m_last_arrival_time;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
//template <class TYPE>
|
||||
ostream& operator<<(ostream& out, const MessageBuffer& obj);
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
// Output operator definition
|
||||
extern inline
|
||||
ostream& operator<<(ostream& out, const MessageBuffer& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //MESSAGEBUFFER_H
|
48
src/mem/ruby/buffers/MessageBufferNode.cc
Normal file
48
src/mem/ruby/buffers/MessageBufferNode.cc
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* EventQueueNode.C
|
||||
*
|
||||
* Description: See EventQueueNode.h
|
||||
*
|
||||
* $Id: MessageBufferNode.C,v 3.1 2001/02/02 16:57:54 sorin Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "MessageBufferNode.hh"
|
||||
|
||||
void MessageBufferNode::print(ostream& out) const
|
||||
{
|
||||
out << "[";
|
||||
out << m_time << ", ";
|
||||
out << m_msg_counter << ", ";
|
||||
out << m_msgptr << "; ";
|
||||
out << "]";
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue