ruby: Import the latest ruby changes from gems.
This was done with an automated process, so there could be things that were done in this tree in the past that didn't make it. One known regression is that atomic memory operations do not seem to work properly anymore.
This commit is contained in:
parent
05f6a4a6b9
commit
92de70b69a
|
@ -26,6 +26,10 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: std-includes.hh,v 3.7 2003/02/24 21:05:24 xu Exp $
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "assert.hh"
|
||||
#include "mem/gems_common/util.hh"
|
||||
|
||||
// Split a string into a head and tail strings on the specified
|
||||
|
@ -43,7 +42,7 @@ string string_split(string& str, char split_character)
|
|||
string head = "";
|
||||
string tail = "";
|
||||
|
||||
unsigned counter = 0;
|
||||
uint counter = 0;
|
||||
while(counter < str.size()) {
|
||||
if (str[counter] == split_character) {
|
||||
counter++;
|
||||
|
@ -91,6 +90,19 @@ float string_to_float(string& str)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool string_to_bool(const string & str)
|
||||
{
|
||||
string lower(str);
|
||||
for (size_t i=0;i<str.length();i++)
|
||||
lower[i] = tolower(str[i]);
|
||||
if (lower == "true")
|
||||
return true;
|
||||
else if (lower == "false")
|
||||
return false;
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// Log functions
|
||||
int log_int(long long n)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ 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);
|
||||
bool string_to_bool(const string & str);
|
||||
int log_int(long long n);
|
||||
bool is_power_of_2(long long n);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
|
||||
|
||||
machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
||||
machine(L1Cache, "MSI Directory L1 Cache CMP") : LATENCY_L1_REQUEST_LATENCY LATENCY_L1_RESPONSE_LATENCY LATENCY_TO_L2_LATENCY {
|
||||
|
||||
// NODE L1 CACHE
|
||||
// From this node's L1 cache TO the network
|
||||
|
@ -136,12 +136,21 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
|||
|
||||
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";
|
||||
// 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";
|
||||
CacheMemory L1IcacheMemory, factory='RubySystem::getCache(m_cfg["L1Icache"])';
|
||||
|
||||
CacheMemory L1DcacheMemory, factory='RubySystem::getCache(m_cfg["L1Dcache"])';
|
||||
|
||||
|
||||
// MessageBuffer mandatoryQueue, ordered="false", rank="100", abstract_chip_ptr="true";
|
||||
|
||||
// Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false";
|
||||
Sequencer sequencer, factory='RubySystem::getSequencer(m_cfg["sequencer"])';
|
||||
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
|
||||
int cache_state_to_int(State state);
|
||||
|
||||
|
@ -290,40 +299,40 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
|||
// ** INSTRUCTION ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
trigger(Event:L1_Replacement, in_msg.LineAddress);
|
||||
}
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
|
||||
// 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);
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
|
||||
} else {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) {
|
||||
// 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);
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.Address));
|
||||
trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// *** DATA ACCESS ***
|
||||
|
||||
// Check to see if it is in the OTHER L1
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) {
|
||||
// The block is in the wrong L1, put the request on the queue to the shared L2
|
||||
trigger(Event:L1_Replacement, in_msg.Address);
|
||||
trigger(Event:L1_Replacement, in_msg.LineAddress);
|
||||
}
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.Address)) {
|
||||
if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) {
|
||||
// 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);
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
|
||||
} else {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.Address)) {
|
||||
if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) {
|
||||
// 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);
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
|
||||
} else {
|
||||
// No room in the L1, so we need to make room in the L1
|
||||
trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.Address));
|
||||
trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,7 +526,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
|||
}
|
||||
|
||||
action(j_sendUnblock, "j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="TO_L2_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
|
@ -527,7 +536,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") {
|
|||
}
|
||||
|
||||
action(jj_sendExclusiveUnblock, "\j", desc="send unblock to the L2 cache") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="1") {
|
||||
enqueue(unblockNetwork_out, ResponseMsg, latency="TO_L2_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:EXCLUSIVE_UNBLOCK;
|
||||
out_msg.Sender := machineID;
|
||||
|
|
|
@ -156,9 +156,12 @@ machine(L2Cache, "MOSI Directory L2 Cache CMP") {
|
|||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
TBETable L2_TBEs, template_hack="<L2Cache_TBE>";
|
||||
TBETable L2_TBEs, template_hack="<L2Cache_TBE>", no_vector="true";
|
||||
|
||||
CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)';
|
||||
// CacheMemory L2cacheMemory, template_hack="<L2Cache_Entry>", constructor_hack='L2_CACHE_NUM_SETS_BITS,L2_CACHE_ASSOC,MachineType_L2Cache,int_to_string(i)';
|
||||
|
||||
|
||||
CacheMemory L2cacheMemory, factory='RubySystem::getCache(m_cfg["cache"])', no_vector="true";
|
||||
|
||||
// inclusive cache, returns L2 entries only
|
||||
Entry getL2CacheEntry(Address addr), return_by_ref="yes" {
|
||||
|
|
|
@ -31,23 +31,39 @@
|
|||
* $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, "Token protocol") {
|
||||
|
||||
machine(Directory, "MESI_CMP_filter_directory protocol") : LATENCY_MEMORY_LATENCY LATENCY_TO_MEM_CTRL_LATENCY {
|
||||
|
||||
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";
|
||||
|
||||
MessageBuffer dmaRequestFromDir, network="To", virtual_network="4", ordered="true", no_vector="true";
|
||||
MessageBuffer dmaRequestToDir, network="From", virtual_network="5", ordered="true", no_vector="true";
|
||||
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, desc="Owner";
|
||||
ID, desc="Intermediate state for DMA_READ when in I";
|
||||
ID_W, desc="Intermediate state for DMA_WRITE when in I";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
Fetch, desc="A GETX arrives";
|
||||
Data, desc="A GETS arrives";
|
||||
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";
|
||||
//added by SS for dma
|
||||
DMA_READ, desc="A DMA Read memory request";
|
||||
DMA_WRITE, desc="A DMA Write memory request";
|
||||
|
||||
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
@ -62,10 +78,21 @@ machine(Directory, "Token protocol") {
|
|||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// to simulate detailed DRAM
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
// DirectoryMemory directory, constructor_hack="i";
|
||||
// MemoryControl memBuffer, constructor_hack="i";
|
||||
|
||||
DirectoryMemory directory, factory='RubySystem::getDirectory(m_cfg["directory_name"])';
|
||||
|
||||
MemoryControl memBuffer, factory='RubySystem::getMemoryControl(m_cfg["memory_controller_name"])';
|
||||
|
||||
|
||||
State getState(Address addr) {
|
||||
return State:I;
|
||||
|
@ -74,20 +101,44 @@ machine(Directory, "Token protocol") {
|
|||
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);
|
||||
out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaRequestFromDir);
|
||||
|
||||
// ** IN_PORTS **
|
||||
|
||||
//added by SS for dma
|
||||
in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) {
|
||||
if (dmaRequestQueue_in.isReady()) {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
if (in_msg.Type == DMARequestType:READ) {
|
||||
trigger(Event:DMA_READ, in_msg.PhysicalAddress);
|
||||
} else if (in_msg.Type == DMARequestType:WRITE) {
|
||||
trigger(Event:DMA_WRITE, in_msg.PhysicalAddress);
|
||||
} 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:Fetch, in_msg.Address);
|
||||
} else if (in_msg.Type == CoherenceRequestType:GETX) {
|
||||
if (isGETRequest(in_msg.Type)) {
|
||||
trigger(Event:Fetch, in_msg.Address);
|
||||
} else {
|
||||
DEBUG_EXPR(in_msg);
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
|
@ -108,27 +159,45 @@ machine(Directory, "Token protocol") {
|
|||
}
|
||||
}
|
||||
|
||||
// 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(responseNetwork_in, ResponseMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceResponseType:MEMORY_ACK;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.Destination.add(in_msg.Sender);
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
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") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_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.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Dirty := false;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
|
@ -143,6 +212,42 @@ machine(Directory, "Token protocol") {
|
|||
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="TO_MEM_CTRL_LATENCY") {
|
||||
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="TO_MEM_CTRL_LATENCY") {
|
||||
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;
|
||||
|
@ -150,17 +255,122 @@ machine(Directory, "Token protocol") {
|
|||
DEBUG_EXPR(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
//added by SS for dma
|
||||
action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
out_msg.OriginalRequestorMachId := machineID;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
|
||||
dmaRequestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMAResponseType:DATA;
|
||||
out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
|
||||
out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(dw_writeDMAData, "dw", desc="DMA Write data to memory") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
directory[in_msg.PhysicalAddress].DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.OriginalRequestorMachId := machineID;
|
||||
//out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") {
|
||||
enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMAResponseType:ACK;
|
||||
out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(z_recycleRequestQueue, "z", desc="recycle request queue") {
|
||||
requestNetwork_in.dequeue();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, Fetch) {
|
||||
d_sendData;
|
||||
//d_sendData;
|
||||
qf_queueMemoryFetchRequest;
|
||||
j_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Data) {
|
||||
m_writeDataToMemory;
|
||||
a_sendAck;
|
||||
//a_sendAck;
|
||||
qw_queueMemoryWBRequest;
|
||||
k_popIncomingResponseQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Data) {
|
||||
d_sendData;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(I, Memory_Ack) {
|
||||
a_sendAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
//added by SS for dma support
|
||||
transition(I, DMA_READ, ID) {
|
||||
qf_queueMemoryFetchRequestDMA;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(ID, Memory_Data, I) {
|
||||
dr_sendDMAData;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(I, DMA_WRITE, ID_W) {
|
||||
dw_writeDMAData;
|
||||
qw_queueMemoryWBRequest_partial;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(ID_W, Memory_Ack, I) {
|
||||
da_sendDMAAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition({ID, ID_W}, {Fetch, Data} ) {
|
||||
z_recycleRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -79,6 +79,38 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
|||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
|
||||
READ, desc="Memory Read";
|
||||
WRITE, desc="Memory Write";
|
||||
NULL, desc="Invalid";
|
||||
}
|
||||
|
||||
enumeration(DMAResponseType, desc="...", default="DMAResponseType_NULL") {
|
||||
DATA, desc="DATA read";
|
||||
ACK, desc="ACK write";
|
||||
NULL, desc="Invalid";
|
||||
}
|
||||
|
||||
structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
|
||||
DMARequestType Type, desc="Request type (read/write)";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
NetDest Destination, desc="Destination";
|
||||
DataBlock DataBlk, desc="DataBlk attached to this request";
|
||||
int Offset, desc="The offset into the datablock";
|
||||
int Len, desc="The length of the request";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
DMAResponseType Type, desc="Response type (DATA/ACK)";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
NetDest Destination, desc="Destination";
|
||||
DataBlock DataBlk, desc="DataBlk attached to this request";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
GenericRequestType convertToGenericType(CoherenceRequestType type) {
|
||||
if(type == CoherenceRequestType:PUTX) {
|
||||
|
|
|
@ -2,4 +2,6 @@ MESI_CMP_directory-msg.sm
|
|||
MESI_CMP_directory-L2cache.sm
|
||||
MESI_CMP_directory-L1cache.sm
|
||||
MESI_CMP_directory-mem.sm
|
||||
MESI_CMP_directory-dma.sm
|
||||
standard_CMP-protocol.sm
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
machine(L1Cache, "MI Example") {
|
||||
machine(L1Cache, "MI Example L1 Cache"): LATENCY_CACHE_RESPONSE_LATENCY LATENCY_ISSUE_LATENCY {
|
||||
|
||||
// NETWORK BUFFERS
|
||||
MessageBuffer requestFromCache, network="To", virtual_network="0", ordered="true";
|
||||
|
@ -15,7 +15,7 @@ machine(L1Cache, "MI Example") {
|
|||
M, desc="Modified";
|
||||
MI, desc="Modified, issued PUT";
|
||||
|
||||
IS, desc="Issued request for IFETCH/GETX";
|
||||
IS, desc="Issued request for LOAD/IFETCH";
|
||||
IM, desc="Issued request for STORE/ATOMIC";
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@ machine(L1Cache, "MI Example") {
|
|||
Data, desc="Data from network";
|
||||
Fwd_GETX, desc="Forward from network";
|
||||
|
||||
Inv, desc="Invalidate request from dir";
|
||||
|
||||
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";
|
||||
|
@ -37,21 +39,21 @@ machine(L1Cache, "MI Example") {
|
|||
|
||||
// STRUCTURE DEFINITIONS
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true";
|
||||
Sequencer sequencer, abstract_chip_ptr="true", constructor_hack="i";
|
||||
MessageBuffer mandatoryQueue, ordered="false";
|
||||
Sequencer sequencer, factory='RubySystem::getSequencer(m_cfg["sequencer"])';
|
||||
|
||||
// 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";
|
||||
DataBlock DataBlk, desc="Data in the block";
|
||||
}
|
||||
|
||||
|
||||
external_type(CacheMemory) {
|
||||
bool cacheAvail(Address);
|
||||
Address cacheProbe(Address);
|
||||
void allocate(Address);
|
||||
void allocate(Address, Entry);
|
||||
void deallocate(Address);
|
||||
Entry lookup(Address);
|
||||
void changePermission(Address, AccessPermission);
|
||||
|
@ -62,8 +64,6 @@ machine(L1Cache, "MI Example") {
|
|||
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) {
|
||||
|
@ -76,7 +76,7 @@ machine(L1Cache, "MI Example") {
|
|||
|
||||
// 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";
|
||||
CacheMemory cacheMemory, factory='RubySystem::getCache(m_cfg["cache"])';
|
||||
|
||||
TBETable TBEs, template_hack="<L1Cache_TBE>";
|
||||
|
||||
|
@ -117,6 +117,11 @@ machine(L1Cache, "MI Example") {
|
|||
|
||||
if (cacheMemory.isTagPresent(addr)) {
|
||||
cacheMemory[addr].CacheState := state;
|
||||
if (state == State:M) {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Read_Write);
|
||||
} else {
|
||||
cacheMemory.changePermission(addr, AccessPermission:Invalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +143,9 @@ machine(L1Cache, "MI Example") {
|
|||
else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
|
||||
trigger(Event:Writeback_Nack, in_msg.Address);
|
||||
}
|
||||
else if (in_msg.Type == CoherenceRequestType:INV) {
|
||||
trigger(Event:Inv, in_msg.Address);
|
||||
}
|
||||
else {
|
||||
error("Unexpected message");
|
||||
}
|
||||
|
@ -164,13 +172,13 @@ machine(L1Cache, "MI Example") {
|
|||
peek(mandatoryQueue_in, CacheMsg) {
|
||||
|
||||
|
||||
if (cacheMemory.isTagPresent(in_msg.Address) == false &&
|
||||
cacheMemory.cacheAvail(in_msg.Address) == false ) {
|
||||
if (cacheMemory.isTagPresent(in_msg.LineAddress) == false &&
|
||||
cacheMemory.cacheAvail(in_msg.LineAddress) == false ) {
|
||||
// make room for the block
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.Address));
|
||||
trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress));
|
||||
}
|
||||
else {
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.Address);
|
||||
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +237,7 @@ machine(L1Cache, "MI Example") {
|
|||
|
||||
action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") {
|
||||
if (cacheMemory.isTagPresent(address) == false) {
|
||||
cacheMemory.allocate(address);
|
||||
cacheMemory.allocate(address, new Entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,11 +252,11 @@ machine(L1Cache, "MI Example") {
|
|||
}
|
||||
|
||||
action(n_popResponseQueue, "n", desc="Pop the response queue") {
|
||||
responseNetwork_in.dequeue();
|
||||
profileMsgDelay(1, responseNetwork_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
|
||||
forwardRequestNetwork_in.dequeue();
|
||||
profileMsgDelay(2, forwardRequestNetwork_in.dequeue_getDelayCycles());
|
||||
}
|
||||
|
||||
action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
|
||||
|
@ -292,10 +300,14 @@ machine(L1Cache, "MI Example") {
|
|||
z_stall;
|
||||
}
|
||||
|
||||
transition({IS, IM}, Fwd_GETX) {
|
||||
transition({IS, IM}, {Fwd_GETX, Inv}) {
|
||||
z_stall;
|
||||
}
|
||||
|
||||
transition(MI, Inv) {
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, Store) {
|
||||
s_store_hit;
|
||||
m_popMandatoryQueue;
|
||||
|
@ -306,6 +318,9 @@ machine(L1Cache, "MI Example") {
|
|||
m_popMandatoryQueue;
|
||||
}
|
||||
|
||||
transition(I, Inv) {
|
||||
o_popForwardedRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, Store, IM) {
|
||||
v_allocateTBE;
|
||||
|
@ -344,7 +359,7 @@ machine(L1Cache, "MI Example") {
|
|||
h_deallocateL1CacheBlock;
|
||||
}
|
||||
|
||||
transition(M, Replacement, MI) {
|
||||
transition(M, {Replacement,Inv}, MI) {
|
||||
v_allocateTBE;
|
||||
b_issuePUT;
|
||||
x_copyDataFromCacheToTBE;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
|
||||
machine(Directory, "Directory protocol") {
|
||||
machine(Directory, "Directory protocol") : LATENCY_TO_MEM_CTRL_LATENCY LATENCY_DIRECTORY_LATENCY LATENCY_MEMORY_LATENCY {
|
||||
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="2", ordered="true";
|
||||
MessageBuffer forwardFromDir, network="To", virtual_network="2", ordered="false";
|
||||
MessageBuffer responseFromDir, network="To", virtual_network="1", ordered="false";
|
||||
MessageBuffer dmaRequestFromDir, network="To", virtual_network="4", ordered="true";
|
||||
|
||||
MessageBuffer requestToDir, network="From", virtual_network="0", ordered="true";
|
||||
MessageBuffer unblockToDir, network="From", virtual_network="3", ordered="true";
|
||||
MessageBuffer dmaRequestToDir, network="From", virtual_network="5", ordered="true";
|
||||
|
||||
// STATES
|
||||
enumeration(State, desc="Directory states", default="Directory_State_I") {
|
||||
|
@ -13,17 +14,32 @@ machine(Directory, "Directory protocol") {
|
|||
I, desc="Invalid";
|
||||
M, desc="Modified";
|
||||
|
||||
MI, desc="Blocked on a writeback";
|
||||
M_DRD, desc="Blocked on an invalidation for a DMA read";
|
||||
M_DWR, desc="Blocked on an invalidation for a DMA write";
|
||||
|
||||
M_DWRI, desc="Intermediate state M_DWR-->I";
|
||||
|
||||
IM, desc="Intermediate state I-->M";
|
||||
MI, desc="Intermediate state M-->I";
|
||||
ID, desc="Intermediate state for DMA_READ when in I";
|
||||
ID_W, desc="Intermediate state for DMA_WRITE when in I";
|
||||
}
|
||||
|
||||
// Events
|
||||
enumeration(Event, desc="Directory events") {
|
||||
// processor requests
|
||||
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";
|
||||
|
||||
// DMA requests
|
||||
DMA_READ, desc="A DMA Read memory request";
|
||||
DMA_WRITE, desc="A DMA Write memory request";
|
||||
|
||||
// Memory Controller
|
||||
Memory_Data, desc="Fetched data from memory arrives";
|
||||
Memory_Ack, desc="Writeback Ack from memory arrives";
|
||||
}
|
||||
|
||||
// TYPES
|
||||
|
@ -39,26 +55,58 @@ machine(Directory, "Directory protocol") {
|
|||
external_type(DirectoryMemory) {
|
||||
Entry lookup(Address);
|
||||
bool isPresent(Address);
|
||||
void invalidateBlock(Address);
|
||||
}
|
||||
|
||||
external_type(MemoryControl, inport="yes", outport="yes") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ** OBJECTS **
|
||||
// TBE entries for DMA requests
|
||||
structure(TBE, desc="TBE entries for outstanding DMA requests") {
|
||||
State TBEState, desc="Transient State";
|
||||
DataBlock DataBlk, desc="Data to be written (DMA write only)";
|
||||
int Offset, desc="...";
|
||||
int Len, desc="...";
|
||||
}
|
||||
|
||||
DirectoryMemory directory, constructor_hack="i";
|
||||
external_type(TBETable) {
|
||||
TBE lookup(Address);
|
||||
void allocate(Address);
|
||||
void deallocate(Address);
|
||||
bool isPresent(Address);
|
||||
}
|
||||
|
||||
// ** OBJECTS **
|
||||
DirectoryMemory directory, factory='RubySystem::getDirectory(m_cfg["directory_name"])';
|
||||
|
||||
MemoryControl memBuffer, factory='RubySystem::getMemoryControl(m_cfg["memory_controller_name"])';
|
||||
|
||||
TBETable TBEs, template_hack="<Directory_TBE>";
|
||||
|
||||
State getState(Address addr) {
|
||||
return directory[addr].DirectoryState;
|
||||
if (TBEs.isPresent(addr)) {
|
||||
return TBEs[addr].TBEState;
|
||||
} else if (directory.isPresent(addr)) {
|
||||
return directory[addr].DirectoryState;
|
||||
} else {
|
||||
return State:I;
|
||||
}
|
||||
}
|
||||
|
||||
void setState(Address addr, State state) {
|
||||
|
||||
if (TBEs.isPresent(addr)) {
|
||||
TBEs[addr].TBEState := 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) {
|
||||
} else if (state == State:M) {
|
||||
assert(directory[addr].Owner.count() == 1);
|
||||
assert(directory[addr].Sharers.count() == 0);
|
||||
}
|
||||
|
@ -71,9 +119,25 @@ machine(Directory, "Directory protocol") {
|
|||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests
|
||||
out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaRequestFromDir);
|
||||
|
||||
//added by SS
|
||||
out_port(memQueue_out, MemoryMsg, memBuffer);
|
||||
// ** IN_PORTS **
|
||||
|
||||
in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) {
|
||||
if (dmaRequestQueue_in.isReady()) {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
if (in_msg.Type == DMARequestType:READ) {
|
||||
trigger(Event:DMA_READ, in_msg.PhysicalAddress);
|
||||
} else if (in_msg.Type == DMARequestType:WRITE) {
|
||||
trigger(Event:DMA_WRITE, in_msg.PhysicalAddress);
|
||||
} else {
|
||||
error("Invalid message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(requestQueue_in, RequestMsg, requestToDir) {
|
||||
if (requestQueue_in.isReady()) {
|
||||
|
@ -88,8 +152,6 @@ machine(Directory, "Directory protocol") {
|
|||
} 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");
|
||||
}
|
||||
|
@ -97,20 +159,23 @@ machine(Directory, "Directory protocol") {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
//added by SS
|
||||
// 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") {
|
||||
|
@ -125,6 +190,18 @@ machine(Directory, "Directory protocol") {
|
|||
}
|
||||
}
|
||||
|
||||
action(l_sendWriteBackAck, "la", desc="Send writeback ack to requestor") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:WB_ACK;
|
||||
out_msg.Requestor := in_msg.OriginalRequestorMachId;
|
||||
out_msg.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
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") {
|
||||
|
@ -141,31 +218,90 @@ machine(Directory, "Directory protocol") {
|
|||
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.MessageSize := MessageSizeType:Response_Data;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
action(d_sendData, "d", desc="Send data to requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="MEMORY_LATENCY") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(responseNetwork_out, ResponseMsg, latency="TO_MEM_CTRL_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.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.Destination.add(in_msg.OriginalRequestorMachId);
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
|
||||
// peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
// enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
// out_msg.PhysicalAddress := address;
|
||||
// out_msg.Type := DMAResponseType:DATA;
|
||||
// out_msg.DataBlk := directory[in_msg.PhysicalAddress].DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
|
||||
// out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
// out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
|
||||
peek(memQueue_in, MemoryMsg) {
|
||||
enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMAResponseType:DATA;
|
||||
out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
|
||||
out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
action(drp_sendDMAData, "drp", desc="Send Data to DMA controller from incoming PUTX") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMAResponseType:DATA;
|
||||
out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be
|
||||
out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
out_msg.MessageSize := MessageSizeType:Response_Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") {
|
||||
enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="MEMORY_LATENCY") {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMAResponseType:ACK;
|
||||
out_msg.Destination.add(map_Address_to_DMA(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
|
||||
action(d_deallocateDirectory, "\d", desc="Deallocate Directory Entry") {
|
||||
directory.invalidateBlock(address);
|
||||
}
|
||||
|
||||
action(e_ownerIsRequestor, "e", desc="The owner is now the requestor") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
directory[address].Owner.clear();
|
||||
|
@ -184,26 +320,32 @@ machine(Directory, "Directory protocol") {
|
|||
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;
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(inv_sendCacheInvalidate, "inv", desc="Invalidate a cache block") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(forwardNetwork_out, RequestMsg, latency="DIRECTORY_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := CoherenceRequestType:INV;
|
||||
out_msg.Requestor := machineID;
|
||||
out_msg.Destination := directory[in_msg.PhysicalAddress].Owner;
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_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(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
|
||||
dmaRequestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
|
||||
// peek(unblockNetwork_in, ResponseMsg) {
|
||||
action(l_writeDataToMemory, "l", desc="Write PUTX data to memory") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
// assert(in_msg.Dirty);
|
||||
// assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
|
||||
|
@ -213,16 +355,218 @@ machine(Directory, "Directory protocol") {
|
|||
}
|
||||
}
|
||||
|
||||
action(dw_writeDMAData, "dw", desc="DMA Write data to memory") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
directory[in_msg.PhysicalAddress].DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
|
||||
}
|
||||
}
|
||||
|
||||
action(dwt_writeDMADataFromTBE, "dwt", desc="DMA Write data to memory from TBE") {
|
||||
directory[address].DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len);
|
||||
}
|
||||
|
||||
action(v_allocateTBE, "v", desc="Allocate TBE") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
TBEs.allocate(address);
|
||||
TBEs[address].DataBlk := in_msg.DataBlk;
|
||||
TBEs[address].Offset := in_msg.Offset;
|
||||
TBEs[address].Len := in_msg.Len;
|
||||
}
|
||||
}
|
||||
|
||||
action(w_deallocateTBE, "w", desc="Deallocate TBE") {
|
||||
TBEs.deallocate(address);
|
||||
}
|
||||
|
||||
action(z_recycleRequestQueue, "z", desc="recycle request queue") {
|
||||
requestQueue_in.recycle();
|
||||
}
|
||||
|
||||
|
||||
action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
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.DataBlk := directory[in_msg.Address].DataBlk;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_READ;
|
||||
out_msg.Sender := machineID;
|
||||
//out_msg.OriginalRequestorMachId := machineID;
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
out_msg.DataBlk := directory[address].DataBlk;
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
|
||||
// peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
// enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
// out_msg.Address := address;
|
||||
// out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
// out_msg.OriginalRequestorMachId := machineID;
|
||||
// out_msg.DataBlk := in_msg.DataBlk;
|
||||
// out_msg.MessageSize := in_msg.MessageSize;
|
||||
|
||||
// DEBUG_EXPR(out_msg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
//out_msg.OriginalRequestorMachId := machineID;
|
||||
//out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.DataBlk.copyPartial(in_msg.DataBlk, in_msg.Offset, in_msg.Len);
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
out_msg.OriginalRequestorMachId := in_msg.Requestor;
|
||||
//out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len);
|
||||
out_msg.MessageSize := in_msg.MessageSize;
|
||||
//out_msg.Prefetch := in_msg.Prefetch;
|
||||
|
||||
DEBUG_EXPR(out_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") {
|
||||
peek(requestQueue_in, RequestMsg) {
|
||||
enqueue(memQueue_out, MemoryMsg, latency="TO_MEM_CTRL_LATENCY") {
|
||||
out_msg.Address := address;
|
||||
out_msg.Type := MemoryRequestType:MEMORY_WB;
|
||||
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(l_popMemQueue, "q", desc="Pop off-chip request queue") {
|
||||
memQueue_in.dequeue();
|
||||
}
|
||||
|
||||
// TRANSITIONS
|
||||
|
||||
transition(I, GETX, M) {
|
||||
d_sendData;
|
||||
transition({M_DRD, M_DWR}, GETX) {
|
||||
z_recycleRequestQueue;
|
||||
}
|
||||
|
||||
transition({IM, MI, ID, ID_W}, {GETX, GETS, DMA_READ, DMA_WRITE, PUTX, PUTX_NotOwner} ) {
|
||||
z_recycleRequestQueue;
|
||||
}
|
||||
|
||||
transition(I, GETX, IM) {
|
||||
//d_sendData;
|
||||
qf_queueMemoryFetchRequest;
|
||||
e_ownerIsRequestor;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(IM, Memory_Data, M) {
|
||||
d_sendData;
|
||||
//e_ownerIsRequestor;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(I, DMA_READ, ID) {
|
||||
//dr_sendDMAData;
|
||||
qf_queueMemoryFetchRequestDMA;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(ID, Memory_Data, I) {
|
||||
dr_sendDMAData;
|
||||
//p_popIncomingDMARequestQueue;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
transition(I, DMA_WRITE, ID_W) {
|
||||
dw_writeDMAData;
|
||||
// da_sendDMAAck;
|
||||
qw_queueMemoryWBRequest_partial;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(ID_W, Memory_Ack, I) {
|
||||
da_sendDMAAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(M, DMA_READ, M_DRD) {
|
||||
inv_sendCacheInvalidate;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(M_DRD, PUTX, I) {
|
||||
drp_sendDMAData;
|
||||
c_clearOwner;
|
||||
a_sendWriteBackAck;
|
||||
// d_deallocateDirectory;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M, DMA_WRITE, M_DWR) {
|
||||
v_allocateTBE;
|
||||
inv_sendCacheInvalidate;
|
||||
p_popIncomingDMARequestQueue;
|
||||
}
|
||||
|
||||
transition(M_DWR, PUTX, M_DWRI) {
|
||||
dwt_writeDMADataFromTBE;
|
||||
qw_queueMemoryWBRequest_partialTBE;
|
||||
//a_sendWriteBackAck;
|
||||
c_clearOwner;
|
||||
//da_sendDMAAck;
|
||||
w_deallocateTBE;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(M_DWRI, Memory_Ack, I) {
|
||||
//dwt_writeDMADataFromTBE;
|
||||
l_sendWriteBackAck;
|
||||
//c_clearOwner;
|
||||
da_sendDMAAck;
|
||||
//w_deallocateTBE;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
transition(M, GETX, M) {
|
||||
|
@ -231,14 +575,20 @@ machine(Directory, "Directory protocol") {
|
|||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
// transition(M, PUTX, MI) {
|
||||
transition(M, PUTX, I) {
|
||||
transition(M, PUTX, MI) {
|
||||
c_clearOwner;
|
||||
l_writeDataToMemory;
|
||||
a_sendWriteBackAck;
|
||||
// l_writeDataToMemory;
|
||||
l_queueMemoryWBRequest;
|
||||
// a_sendWriteBackAck;
|
||||
d_deallocateDirectory;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
transition(MI, Memory_Ack, I) {
|
||||
l_sendWriteBackAck;
|
||||
l_popMemQueue;
|
||||
}
|
||||
|
||||
transition(M, PUTX_NotOwner, M) {
|
||||
b_sendWriteBackNack;
|
||||
i_popIncomingRequestQueue;
|
||||
|
@ -246,12 +596,8 @@ machine(Directory, "Directory protocol") {
|
|||
|
||||
transition(I, PUTX_NotOwner, I) {
|
||||
b_sendWriteBackNack;
|
||||
d_deallocateDirectory;
|
||||
i_popIncomingRequestQueue;
|
||||
}
|
||||
|
||||
|
||||
transition(MI, Unblock, M) {
|
||||
j_popIncomingUnblockQueue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
135
src/mem/protocol/MI_example-dma.sm
Normal file
135
src/mem/protocol/MI_example-dma.sm
Normal file
|
@ -0,0 +1,135 @@
|
|||
|
||||
machine(DMA, "DMA Controller") {
|
||||
|
||||
MessageBuffer responseFromDir, network="From", virtual_network="4", ordered="true", no_vector="true";
|
||||
MessageBuffer reqToDirectory, network="To", virtual_network="5", ordered="false", no_vector="true";
|
||||
|
||||
enumeration(State, desc="DMA states", default="DMA_State_READY") {
|
||||
READY, desc="Ready to accept a new request";
|
||||
BUSY_RD, desc="Busy: currently processing a request";
|
||||
BUSY_WR, desc="Busy: currently processing a request";
|
||||
}
|
||||
|
||||
enumeration(Event, desc="DMA events") {
|
||||
ReadRequest, desc="A new read request";
|
||||
WriteRequest, desc="A new write request";
|
||||
Data, desc="Data from a DMA memory read";
|
||||
Ack, desc="DMA write to memory completed";
|
||||
}
|
||||
|
||||
external_type(DMASequencer) {
|
||||
void ackCallback();
|
||||
void dataCallback(DataBlock);
|
||||
}
|
||||
|
||||
MessageBuffer mandatoryQueue, ordered="false", no_vector="true";
|
||||
DMASequencer dma_sequencer, factory='RubySystem::getDMASequencer(m_cfg["dma_sequencer"])', no_vector="true";
|
||||
State cur_state, no_vector="true";
|
||||
|
||||
State getState(Address addr) {
|
||||
return cur_state;
|
||||
}
|
||||
void setState(Address addr, State state) {
|
||||
cur_state := state;
|
||||
}
|
||||
|
||||
out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="...");
|
||||
|
||||
in_port(dmaRequestQueue_in, DMARequestMsg, mandatoryQueue, desc="...") {
|
||||
if (dmaRequestQueue_in.isReady()) {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
if (in_msg.Type == DMARequestType:READ ) {
|
||||
trigger(Event:ReadRequest, in_msg.PhysicalAddress);
|
||||
} else if (in_msg.Type == DMARequestType:WRITE) {
|
||||
trigger(Event:WriteRequest, in_msg.PhysicalAddress);
|
||||
} else {
|
||||
error("Invalid request type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_port(dmaResponseQueue_in, DMAResponseMsg, responseFromDir, desc="...") {
|
||||
if (dmaResponseQueue_in.isReady()) {
|
||||
peek( dmaResponseQueue_in, DMAResponseMsg) {
|
||||
if (in_msg.Type == DMAResponseType:ACK) {
|
||||
trigger(Event:Ack, in_msg.PhysicalAddress);
|
||||
} else if (in_msg.Type == DMAResponseType:DATA) {
|
||||
trigger(Event:Data, in_msg.PhysicalAddress);
|
||||
} else {
|
||||
error("Invalid response type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(reqToDirectory_out, DMARequestMsg) {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMARequestType:READ;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Len := in_msg.Len;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") {
|
||||
peek(dmaRequestQueue_in, DMARequestMsg) {
|
||||
enqueue(reqToDirectory_out, DMARequestMsg) {
|
||||
out_msg.PhysicalAddress := address;
|
||||
out_msg.Type := DMARequestType:WRITE;
|
||||
out_msg.DataBlk := in_msg.DataBlk;
|
||||
out_msg.Len := in_msg.Len;
|
||||
out_msg.Destination.add(map_Address_to_Directory(address));
|
||||
out_msg.MessageSize := MessageSizeType:Writeback_Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action(a_ackCallback, "a", desc="Notify dma controller that write request completed") {
|
||||
peek (dmaResponseQueue_in, DMAResponseMsg) {
|
||||
dma_sequencer.ackCallback();
|
||||
}
|
||||
}
|
||||
|
||||
action(d_dataCallback, "d", desc="Write data to dma sequencer") {
|
||||
peek (dmaResponseQueue_in, DMAResponseMsg) {
|
||||
dma_sequencer.dataCallback(in_msg.DataBlk);
|
||||
}
|
||||
}
|
||||
|
||||
action(p_popRequestQueue, "p", desc="Pop request queue") {
|
||||
dmaRequestQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(p_popResponseQueue, "\p", desc="Pop request queue") {
|
||||
dmaResponseQueue_in.dequeue();
|
||||
}
|
||||
|
||||
action(z_stall, "z", desc="dma is busy..stall") {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
transition(READY, ReadRequest, BUSY_RD) {
|
||||
s_sendReadRequest;
|
||||
p_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(READY, WriteRequest, BUSY_WR) {
|
||||
s_sendWriteRequest;
|
||||
p_popRequestQueue;
|
||||
}
|
||||
|
||||
transition(BUSY_RD, Data, READY) {
|
||||
d_dataCallback;
|
||||
p_popResponseQueue;
|
||||
}
|
||||
|
||||
transition(BUSY_WR, Ack, READY) {
|
||||
a_ackCallback;
|
||||
p_popResponseQueue;
|
||||
}
|
||||
}
|
|
@ -74,7 +74,6 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
|
|||
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";
|
||||
}
|
||||
|
@ -87,6 +86,35 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
|
|||
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";
|
||||
}
|
||||
|
||||
enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
|
||||
READ, desc="Memory Read";
|
||||
WRITE, desc="Memory Write";
|
||||
NULL, desc="Invalid";
|
||||
}
|
||||
|
||||
enumeration(DMAResponseType, desc="...", default="DMAResponseType_NULL") {
|
||||
DATA, desc="DATA read";
|
||||
ACK, desc="ACK write";
|
||||
NULL, desc="Invalid";
|
||||
}
|
||||
|
||||
structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
|
||||
DMARequestType Type, desc="Request type (read/write)";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
NetDest Destination, desc="Destination";
|
||||
DataBlock DataBlk, desc="DataBlk attached to this request";
|
||||
int Offset, desc="The offset into the datablock";
|
||||
int Len, desc="The length of the request";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
||||
structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
|
||||
DMAResponseType Type, desc="Response type (DATA/ACK)";
|
||||
Address PhysicalAddress, desc="Physical address for this request";
|
||||
NetDest Destination, desc="Destination";
|
||||
DataBlock DataBlk, desc="DataBlk attached to this request";
|
||||
MessageSizeType MessageSize, desc="size category of the message";
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
MI_example-msg.sm
|
||||
MI_example-cache.sm
|
||||
MI_example-dir.sm
|
||||
standard_1level_SMP-protocol.sm
|
||||
MI_example-dma.sm
|
||||
standard_1level_CMP-protocol.sm
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
// Mapping functions
|
||||
|
||||
// NodeID map_address_to_node(Address addr);
|
||||
MachineID map_Address_to_DMA(Address addr);
|
||||
MachineID map_Address_to_Directory(Address addr);
|
||||
NodeID map_Address_to_DirectoryNode(Address addr);
|
||||
MachineID map_Address_to_CentralArbiterNode(Address addr);
|
||||
|
|
|
@ -131,6 +131,12 @@ enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
|
|||
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";
|
||||
}
|
||||
|
||||
|
@ -156,6 +162,12 @@ enumeration(GenericRequestType, desc="...", default="GenericRequestType_NULL") {
|
|||
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";
|
||||
}
|
||||
|
||||
|
@ -211,27 +223,15 @@ enumeration(PrefetchBit, default="PrefetchBit_No", desc="...") {
|
|||
|
||||
// CacheMsg
|
||||
structure(CacheMsg, desc="...", interface="Message") {
|
||||
Address Address, desc="Line address for this request";
|
||||
Address LineAddress, 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 RequestTime, desc="The cycle in which this request was issued";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MaskPredictorType
|
||||
enumeration(MaskPredictorType, "MaskPredictorType_Undefined", desc="...") {
|
||||
Undefined, desc="Undefined";
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
external_type(DataBlock, desc="..."){
|
||||
void clear();
|
||||
void copyPartial(DataBlock, int, int);
|
||||
}
|
||||
|
||||
external_type(MessageBuffer, buffer="yes", inport="yes", outport="yes");
|
||||
|
@ -48,8 +49,7 @@ external_type(InPort, primitive="yes") {
|
|||
external_type(NodeID, default="0");
|
||||
external_type(MachineID);
|
||||
|
||||
external_type(StoreBuffer);
|
||||
|
||||
MessageBuffer getMandatoryQueue(int core_id);
|
||||
|
||||
external_type(Set, non_obj="yes") {
|
||||
void setSize(int);
|
||||
|
@ -96,53 +96,11 @@ external_type(NetDest, non_obj="yes") {
|
|||
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") {
|
||||
|
@ -153,4 +111,16 @@ external_type(TimerTable, inport="yes") {
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* 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
|
||||
|
@ -28,23 +28,13 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* init.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INIT_H
|
||||
#define INIT_H
|
||||
// global protocol features
|
||||
global(Protocol, desc="Global properties of this protocol",
|
||||
interface = "AbstractProtocol") {
|
||||
bool TwoLevelCache := false;
|
||||
bool CMP := true;
|
||||
}
|
||||
|
||||
class Driver;
|
||||
|
||||
extern void init_variables();
|
||||
//extern void init_variables(const char* config_str);
|
||||
extern void init_simulator();
|
||||
extern void init_simulator(Driver* _driver);
|
||||
extern void destroy_simulator();
|
||||
|
||||
#endif //INIT_H
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "mem/ruby/buffers/MessageBuffer.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
|
||||
MessageBuffer::MessageBuffer()
|
||||
{
|
||||
|
@ -180,17 +181,18 @@ void MessageBuffer::enqueue(const MsgPtr& message, Time delta)
|
|||
// the plus one is a kluge because of a SLICC issue
|
||||
|
||||
if (!m_ordering_set) {
|
||||
WARN_EXPR(*this);
|
||||
// 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.
|
||||
// printf ("delta %i \n", delta);
|
||||
assert(delta>0);
|
||||
Time current_time = g_eventQueue_ptr->getTime();
|
||||
Time arrival_time = 0;
|
||||
if (!RANDOMIZATION || (m_randomization == false)) {
|
||||
if (!RubySystem::getRandomization() || (m_randomization == false)) {
|
||||
// No randomization
|
||||
arrival_time = current_time + delta;
|
||||
|
||||
|
@ -294,7 +296,7 @@ void MessageBuffer::pop()
|
|||
{
|
||||
DEBUG_MSG(QUEUE_COMP,MedPrio,"pop from " + m_name);
|
||||
assert(isReady());
|
||||
m_prio_heap.extractMin();
|
||||
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;
|
||||
|
@ -321,13 +323,13 @@ void MessageBuffer::clear()
|
|||
|
||||
void MessageBuffer::recycle()
|
||||
{
|
||||
// const int RECYCLE_LATENCY = 3;
|
||||
// const int RubyConfig::getRecycleLatency() = 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;
|
||||
node.m_time = g_eventQueue_ptr->getTime() + m_recycle_latency;
|
||||
m_prio_heap.insert(node);
|
||||
g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, g_eventQueue_ptr->getTime() + RECYCLE_LATENCY);
|
||||
g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, g_eventQueue_ptr->getTime() + m_recycle_latency);
|
||||
}
|
||||
|
||||
int MessageBuffer::setAndReturnDelayCycles(MsgPtr& message)
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
// Public Methods
|
||||
|
||||
static void printConfig(ostream& out) {}
|
||||
void setRecycleLatency(int recycle_latency) { m_recycle_latency = recycle_latency; }
|
||||
|
||||
// TRUE if head of queue timestamp <= SystemTime
|
||||
bool isReady() const {
|
||||
|
@ -105,6 +106,9 @@ public:
|
|||
void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; }
|
||||
|
||||
private:
|
||||
//added by SS
|
||||
int m_recycle_latency;
|
||||
|
||||
// Private Methods
|
||||
int setAndReturnDelayCycles(MsgPtr& message);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 1999 Mark D. Hill and David A. Wood
|
||||
* All rights reserved.
|
||||
|
@ -26,12 +27,16 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef ADDRESS_H
|
||||
#define ADDRESS_H
|
||||
|
||||
#include <iomanip>
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/system/NodeID.hh"
|
||||
#include "mem/ruby/system/MachineID.hh"
|
||||
|
||||
|
@ -63,17 +68,16 @@ public:
|
|||
physical_address_t maskHighOrderBits(int number) const;
|
||||
physical_address_t shiftLowOrderBits(int number) const;
|
||||
physical_address_t getLineAddress() const
|
||||
{ return bitSelect(RubyConfig::dataBlockBits(), ADDRESS_WIDTH); }
|
||||
{ return bitSelect(RubySystem::getBlockSizeBits(), ADDRESS_WIDTH); }
|
||||
physical_address_t getOffset() const
|
||||
{ return bitSelect(0, RubyConfig::dataBlockBits()-1); }
|
||||
{ return bitSelect(0, RubySystem::getBlockSizeBits()-1); }
|
||||
|
||||
void makeLineAddress() { m_address = maskLowOrderBits(RubyConfig::dataBlockBits()); }
|
||||
void makeLineAddress() { m_address = maskLowOrderBits(RubySystem::getBlockSizeBits()); }
|
||||
// returns the next stride address based on line address
|
||||
void makeNextStrideAddress( int stride) {
|
||||
m_address = maskLowOrderBits(RubyConfig::dataBlockBits())
|
||||
+ RubyConfig::dataBlockBytes()*stride;
|
||||
m_address = maskLowOrderBits(RubySystem::getBlockSizeBits())
|
||||
+ RubySystem::getBlockSizeBytes()*stride;
|
||||
}
|
||||
void makePageAddress() { m_address = maskLowOrderBits(RubyConfig::pageSizeBits()); }
|
||||
int getBankSetNum() const;
|
||||
int getBankSetDist() const;
|
||||
|
||||
|
@ -103,6 +107,7 @@ private:
|
|||
inline
|
||||
Address line_address(const Address& addr) { Address temp(addr); temp.makeLineAddress(); return temp; }
|
||||
|
||||
/*
|
||||
inline
|
||||
Address next_stride_address(const Address& addr, int stride) {
|
||||
Address temp = addr;
|
||||
|
@ -110,9 +115,7 @@ Address next_stride_address(const Address& addr, int stride) {
|
|||
temp.setAddress(temp.maskHighOrderBits(ADDRESS_WIDTH-RubyConfig::memorySizeBits())); // surpress wrap-around problem
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline
|
||||
Address page_address(const Address& addr) { Address temp(addr); temp.makePageAddress(); return temp; }
|
||||
*/
|
||||
|
||||
// Output operator declaration
|
||||
ostream& operator<<(ostream& out, const Address& obj);
|
||||
|
@ -202,17 +205,19 @@ physical_address_t Address::shiftLowOrderBits(int number) const
|
|||
inline
|
||||
integer_t Address::memoryModuleIndex() const
|
||||
{
|
||||
integer_t index = bitSelect(RubyConfig::dataBlockBits()+RubyConfig::memoryBits(), ADDRESS_WIDTH);
|
||||
integer_t index = bitSelect(RubySystem::getBlockSizeBits()+RubySystem::getMemorySizeBits(), ADDRESS_WIDTH);
|
||||
assert (index >= 0);
|
||||
/*
|
||||
if (index >= RubyConfig::memoryModuleBlocks()) {
|
||||
cerr << " memoryBits: " << RubyConfig::memoryBits() << " memorySizeBits: " << RubyConfig::memorySizeBits()
|
||||
<< " Address: " << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubyConfig::dataBlockBits()) << dec << "]" << flush
|
||||
cerr << " memoryBits: " << RubySystem::getMemorySizeBits() << " memorySizeBits: " << RubySystem::getMemorySizeBits()
|
||||
<< " Address: " << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubySystem::getBlockSizeBits()) << dec << "]" << flush
|
||||
<< "error: limit exceeded. " <<
|
||||
" dataBlockBits: " << RubyConfig::dataBlockBits() <<
|
||||
" getDataBlockBits: " << RubySystem::getBlockSizeBits() <<
|
||||
" memoryModuleBlocks: " << RubyConfig::memoryModuleBlocks() <<
|
||||
" index: " << index << endl;
|
||||
}
|
||||
assert (index < RubyConfig::memoryModuleBlocks());
|
||||
*/
|
||||
return index;
|
||||
|
||||
// Index indexHighPortion = address.bitSelect(MEMORY_SIZE_BITS-1, PAGE_SIZE_BITS+NUMBER_OF_MEMORY_MODULE_BITS);
|
||||
|
@ -239,7 +244,7 @@ ADDRESS_WIDTH MEMORY_SIZE_BITS PAGE_SIZE_BITS DATA_BLOCK_BITS
|
|||
inline
|
||||
void Address::print(ostream& out) const
|
||||
{
|
||||
out << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubyConfig::dataBlockBits()) << dec << "]" << flush;
|
||||
out << "[" << hex << "0x" << m_address << "," << " line 0x" << maskLowOrderBits(RubySystem::getBlockSizeBits()) << dec << "]" << flush;
|
||||
}
|
||||
|
||||
class Address;
|
||||
|
|
|
@ -53,7 +53,8 @@ public:
|
|||
virtual ~Consumer() { }
|
||||
|
||||
// Public Methods - pure virtual methods
|
||||
void triggerWakeup() { Time time = g_eventQueue_ptr->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }}
|
||||
// void triggerWakeup() { Time time = g_eventQueue_ptr->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }}
|
||||
void triggerWakeup(RubyEventQueue * eventQueue) { Time time = eventQueue->getTime(); if (m_last_wakeup != time) { wakeup(); m_last_wakeup = time; }}
|
||||
virtual void wakeup() = 0;
|
||||
virtual void print(ostream& out) const = 0;
|
||||
const Time& getLastScheduledWakeup() const { return m_last_scheduled_wakeup; }
|
||||
|
|
|
@ -1,91 +1,16 @@
|
|||
|
||||
/*
|
||||
* 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 "mem/ruby/common/DataBlock.hh"
|
||||
|
||||
DataBlock::DataBlock()
|
||||
DataBlock &
|
||||
DataBlock::operator=(const DataBlock & obj)
|
||||
{
|
||||
if (DATA_BLOCK || XACT_MEMORY) {
|
||||
m_data.setSize(RubyConfig::dataBlockBytes());
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
DataBlock::~DataBlock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DataBlock::clear()
|
||||
{
|
||||
int size = m_data.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
m_data[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool DataBlock::equal(const DataBlock& obj) const
|
||||
{
|
||||
bool value = true;
|
||||
int size = m_data.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
value = value && (m_data[i] == obj.m_data[i]);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void DataBlock::print(ostream& out) const
|
||||
{
|
||||
int size = m_data.size();
|
||||
for (int i = 0; i < size; i+=4) {
|
||||
out << hex << *((uint32*)(&(m_data[i]))) << " ";
|
||||
}
|
||||
out << dec << "]" << flush;
|
||||
}
|
||||
|
||||
uint8 DataBlock::getByte(int whichByte) const
|
||||
{
|
||||
if (DATA_BLOCK || XACT_MEMORY) {
|
||||
return m_data[whichByte];
|
||||
if (this == &obj) {
|
||||
// assert(false);
|
||||
} else {
|
||||
return 0;
|
||||
if (!m_alloc)
|
||||
m_data = new uint8[RubySystem::getBlockSizeBytes()];
|
||||
memcpy(m_data, obj.m_data, RubySystem::getBlockSizeBytes());
|
||||
m_alloc = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DataBlock::setByte(int whichByte, uint8 data)
|
||||
{
|
||||
if (DATA_BLOCK || XACT_MEMORY) {
|
||||
m_data[whichByte] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,29 +31,41 @@
|
|||
#define DATABLOCK_H
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/gems_common/Vector.hh"
|
||||
|
||||
class DataBlock {
|
||||
public:
|
||||
public:
|
||||
// Constructors
|
||||
DataBlock();
|
||||
DataBlock() {alloc();}
|
||||
DataBlock(const DataBlock & cp) {
|
||||
m_data = new uint8[RubySystem::getBlockSizeBytes()];
|
||||
memcpy(m_data, cp.m_data, RubySystem::getBlockSizeBytes());
|
||||
m_alloc = true;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~DataBlock();
|
||||
~DataBlock() { if(m_alloc) delete [] m_data;}
|
||||
|
||||
DataBlock& operator=(const DataBlock& obj);
|
||||
|
||||
// Public Methods
|
||||
void assign(uint8* data);
|
||||
|
||||
void clear();
|
||||
uint8 getByte(int whichByte) const;
|
||||
const uint8* getData(int offset, int len) const;
|
||||
void setByte(int whichByte, uint8 data);
|
||||
void setData(uint8* data, int offset, int len);
|
||||
void copyPartial(const DataBlock & dblk, int offset, int len);
|
||||
bool equal(const DataBlock& obj) const;
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
// Private Methods
|
||||
|
||||
void alloc();
|
||||
// Data Members (m_ prefix)
|
||||
Vector<uint8> m_data;
|
||||
uint8* m_data;
|
||||
bool m_alloc;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
|
@ -61,6 +73,78 @@ ostream& operator<<(ostream& out, const DataBlock& obj);
|
|||
|
||||
bool operator==(const DataBlock& obj1, const DataBlock& obj2);
|
||||
|
||||
// inline functions for speed
|
||||
|
||||
inline
|
||||
void DataBlock::assign(uint8* data)
|
||||
{
|
||||
delete [] m_data;
|
||||
m_data = data;
|
||||
m_alloc = false;
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::alloc()
|
||||
{
|
||||
m_data = new uint8[RubySystem::getBlockSizeBytes()];
|
||||
m_alloc = true;
|
||||
clear();
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::clear()
|
||||
{
|
||||
memset(m_data, 0, RubySystem::getBlockSizeBytes());
|
||||
}
|
||||
|
||||
inline
|
||||
bool DataBlock::equal(const DataBlock& obj) const
|
||||
{
|
||||
return !memcmp(m_data, obj.m_data, RubySystem::getBlockSizeBytes());
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::print(ostream& out) const
|
||||
{
|
||||
int size = RubySystem::getBlockSizeBytes();
|
||||
out << "[ ";
|
||||
for (int i = 0; i < size; i+=4) {
|
||||
out << hex << *((uint32*)(&(m_data[i]))) << " ";
|
||||
}
|
||||
out << dec << "]" << flush;
|
||||
}
|
||||
|
||||
inline
|
||||
uint8 DataBlock::getByte(int whichByte) const
|
||||
{
|
||||
return m_data[whichByte];
|
||||
}
|
||||
|
||||
inline
|
||||
const uint8* DataBlock::getData(int offset, int len) const
|
||||
{
|
||||
assert(offset + len <= RubySystem::getBlockSizeBytes());
|
||||
return &m_data[offset];
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::setByte(int whichByte, uint8 data)
|
||||
{
|
||||
m_data[whichByte] = data;
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::setData(uint8* data, int offset, int len)
|
||||
{
|
||||
assert(offset + len <= RubySystem::getBlockSizeBytes());
|
||||
memcpy(&m_data[offset], data, len);
|
||||
}
|
||||
|
||||
inline
|
||||
void DataBlock::copyPartial(const DataBlock & dblk, int offset, int len)
|
||||
{
|
||||
setData(&dblk.m_data[offset], offset, len);
|
||||
}
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
|
|
|
@ -38,36 +38,28 @@
|
|||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/common/Debug.hh"
|
||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||
#include "mem/gems_common/util.hh"
|
||||
|
||||
class Debug;
|
||||
extern Debug* g_debug_ptr;
|
||||
std::ostream * debug_cout_ptr;
|
||||
|
||||
struct DebugComponentData
|
||||
{
|
||||
const char *desc;
|
||||
const char ch;
|
||||
};
|
||||
bool Debug::m_protocol_trace = false;
|
||||
|
||||
// component character list
|
||||
DebugComponentData debugComponents[] =
|
||||
const char DEFINE_COMP_CHAR[] =
|
||||
{
|
||||
{"System", 's' },
|
||||
{"Node", 'N' },
|
||||
{"Queue", 'q' },
|
||||
{"Event Queue", 'e' },
|
||||
{"Network", 'n' },
|
||||
{"Sequencer", 'S' },
|
||||
{"Tester", 't' },
|
||||
{"Generated", 'g' },
|
||||
{"SLICC", 'l' },
|
||||
{"Network Queues", 'Q' },
|
||||
{"Time", 'T' },
|
||||
{"Network Internals", 'i' },
|
||||
{"Store Buffer", 'b' },
|
||||
{"Cache", 'c' },
|
||||
{"Predictor", 'p' },
|
||||
{"Allocator", 'a' },
|
||||
#undef DEFINE_COMP
|
||||
#define DEFINE_COMP(component, character, description) character,
|
||||
#include "Debug.def"
|
||||
};
|
||||
|
||||
// component description list
|
||||
const char* DEFINE_COMP_DESCRIPTION[] =
|
||||
{
|
||||
#undef DEFINE_COMP
|
||||
#define DEFINE_COMP(component, character, description) description,
|
||||
#include "Debug.def"
|
||||
};
|
||||
|
||||
extern "C" void changeDebugVerbosity(VerbosityLevel vb);
|
||||
|
@ -83,6 +75,32 @@ void changeDebugFilter(int filter)
|
|||
g_debug_ptr->setFilter(filter);
|
||||
}
|
||||
|
||||
Debug::Debug()
|
||||
{
|
||||
m_verbosityLevel = No_Verb;
|
||||
m_starting_cycle = ~0;
|
||||
clearFilter();
|
||||
debug_cout_ptr = &cout;
|
||||
}
|
||||
|
||||
Debug::Debug( const string & name, const vector<string> & argv )
|
||||
{
|
||||
for (size_t i=0;i<argv.size();i+=2){
|
||||
if (argv[i] == "filter_string")
|
||||
setFilterString( argv[i+1].c_str() );
|
||||
else if (argv[i] == "verbosity_string")
|
||||
setVerbosityString( argv[i+1].c_str() );
|
||||
else if (argv[i] == "start_time")
|
||||
m_starting_cycle = atoi( argv[i+1].c_str() );
|
||||
else if (argv[i] == "output_filename")
|
||||
setDebugOutputFile( argv[i+1].c_str() );
|
||||
else if (argv[i] == "protocol_trace")
|
||||
m_protocol_trace = string_to_bool(argv[i+1]);
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
Debug::Debug( const char *filterString, const char *verboseString,
|
||||
Time filterStartTime, const char *filename )
|
||||
{
|
||||
|
@ -208,7 +226,7 @@ bool Debug::checkFilter(char ch)
|
|||
{
|
||||
for (int i=0; i<NUMBER_OF_COMPS; i++) {
|
||||
// Look at all components to find a character match
|
||||
if (debugComponents[i].ch == ch) {
|
||||
if (DEFINE_COMP_CHAR[i] == ch) {
|
||||
// We found a match - return no error
|
||||
return false; // no error
|
||||
}
|
||||
|
@ -274,9 +292,9 @@ bool Debug::addFilter(char ch)
|
|||
{
|
||||
for (int i=0; i<NUMBER_OF_COMPS; i++) {
|
||||
// Look at all components to find a character match
|
||||
if (debugComponents[i].ch == ch) {
|
||||
if (DEFINE_COMP_CHAR[i] == ch) {
|
||||
// We found a match - update the filter bit mask
|
||||
cout << " Debug: Adding to filter: '" << ch << "' (" << debugComponents[i].desc << ")" << endl;
|
||||
cout << " Debug: Adding to filter: '" << ch << "' (" << DEFINE_COMP_DESCRIPTION[i] << ")" << endl;
|
||||
m_filter |= (1 << i);
|
||||
return false; // no error
|
||||
}
|
||||
|
@ -302,7 +320,7 @@ void Debug::usageInstructions(void)
|
|||
{
|
||||
cerr << "Debug components: " << endl;
|
||||
for (int i=0; i<NUMBER_OF_COMPS; i++) {
|
||||
cerr << " " << debugComponents[i].ch << ": " << debugComponents[i].desc << endl;
|
||||
cerr << " " << DEFINE_COMP_CHAR[i] << ": " << DEFINE_COMP_DESCRIPTION[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,37 +31,21 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __MEM_RUBY_DEBUG_HH__
|
||||
#define __MEM_RUBY_DEBUG_HH__
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "config/ruby_debug.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
|
||||
extern std::ostream * debug_cout_ptr;
|
||||
|
||||
// component enumeration
|
||||
enum DebugComponents
|
||||
{
|
||||
SYSTEM_COMP,
|
||||
NODE_COMP,
|
||||
QUEUE_COMP,
|
||||
EVENTQUEUE_COMP,
|
||||
NETWORK_COMP,
|
||||
SEQUENCER_COMP,
|
||||
TESTER_COMP,
|
||||
GENERATED_COMP,
|
||||
SLICC_COMP,
|
||||
NETWORKQUEUE_COMP,
|
||||
TIME_COMP,
|
||||
NETWORK_INTERNALS_COMP,
|
||||
STOREBUFFER_COMP,
|
||||
CACHE_COMP,
|
||||
PREDICTOR_COMP,
|
||||
ALLOCATOR_COMP,
|
||||
NUMBER_OF_COMPS
|
||||
#undef DEFINE_COMP
|
||||
#define DEFINE_COMP(component, character, description) component,
|
||||
#include "Debug.def"
|
||||
NUMBER_OF_COMPS
|
||||
};
|
||||
|
||||
enum PriorityLevel {HighPrio, MedPrio, LowPrio};
|
||||
|
@ -70,6 +54,8 @@ enum VerbosityLevel {No_Verb, Low_Verb, Med_Verb, High_Verb};
|
|||
class Debug {
|
||||
public:
|
||||
// Constructors
|
||||
Debug();
|
||||
Debug( const string & name, const vector<string> & argv );
|
||||
Debug( const char *filterString, const char *verboseString,
|
||||
Time filterStartTime, const char *filename );
|
||||
|
||||
|
@ -77,6 +63,7 @@ public:
|
|||
~Debug();
|
||||
|
||||
// Public Methods
|
||||
static bool getProtocolTrace() { return m_protocol_trace; }
|
||||
bool validDebug(int module, PriorityLevel priority);
|
||||
void printVerbosity(ostream& out) const;
|
||||
void setVerbosity(VerbosityLevel vb);
|
||||
|
@ -108,6 +95,7 @@ private:
|
|||
Debug& operator=(const Debug& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
static bool m_protocol_trace;
|
||||
VerbosityLevel m_verbosityLevel;
|
||||
int m_filter;
|
||||
Time m_starting_cycle;
|
||||
|
@ -155,7 +143,7 @@ const bool ASSERT_FLAG = true;
|
|||
<< __PRETTY_FUNCTION__ << " in "\
|
||||
<< __FILE__ << ":"\
|
||||
<< __LINE__ << endl << flush;\
|
||||
if(isatty(STDERR_FILENO)) {\
|
||||
if(isatty(STDIN_FILENO)) {\
|
||||
cerr << "At this point you might want to attach a debug to ";\
|
||||
cerr << "the running and get to the" << endl;\
|
||||
cerr << "crash site; otherwise press enter to continue" << endl;\
|
||||
|
@ -176,7 +164,7 @@ const bool ASSERT_FLAG = true;
|
|||
<< __PRETTY_FUNCTION__ << " in "\
|
||||
<< __FILE__ << ":"\
|
||||
<< __LINE__ << endl << flush;\
|
||||
if(isatty(STDERR_FILENO)) {\
|
||||
if(isatty(STDIN_FILENO)) {\
|
||||
cerr << "press enter to continue" << endl;\
|
||||
cerr << "PID: " << getpid();\
|
||||
cerr << endl << flush; \
|
||||
|
@ -303,5 +291,5 @@ const bool ASSERT_FLAG = true;
|
|||
}\
|
||||
}
|
||||
|
||||
#endif // __MEM_RUBY_DEBUG_HH__
|
||||
#endif //DEBUG_H
|
||||
|
||||
|
|
|
@ -27,6 +27,13 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
|
@ -34,7 +41,6 @@
|
|||
#include "mem/ruby/common/Consumer.hh"
|
||||
#include "mem/ruby/system/NodeID.hh"
|
||||
#include "mem/protocol/CacheRequestType.hh"
|
||||
#include "mem/packet.hh"
|
||||
|
||||
class RubySystem;
|
||||
class SubBlock;
|
||||
|
@ -52,10 +58,15 @@ public:
|
|||
|
||||
// Public Methods
|
||||
virtual void get_network_config() {}
|
||||
virtual void hitCallback(Packet* pkt) = 0;
|
||||
virtual void dmaHitCallback() = 0;
|
||||
virtual void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) = 0; // Called by sequencer
|
||||
virtual void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) { assert(0) }; // Called by sequencer
|
||||
virtual integer_t getInstructionCount(int procID) const { return 1; }
|
||||
virtual integer_t getCycleCount(int procID) const { return 1; }
|
||||
|
||||
virtual void addThreadDependency(int procID, int requestor_thread, int conflict_thread) const { assert(0);}
|
||||
virtual int inTransaction(int procID, int thread ) const{
|
||||
cout << "Driver.hh inTransaction " << endl;
|
||||
return false; } //called by Sequencer
|
||||
virtual void printDebug(){} //called by Sequencer
|
||||
|
||||
virtual void printStats(ostream& out) const = 0;
|
||||
|
@ -63,6 +74,8 @@ public:
|
|||
|
||||
virtual void printConfig(ostream& out) const = 0;
|
||||
|
||||
//virtual void abortCallback(NodeID proc){}
|
||||
|
||||
virtual integer_t readPhysicalMemory(int procID, physical_address_t address,
|
||||
int len ){ ASSERT(0); return 0; }
|
||||
|
||||
|
|
|
@ -32,9 +32,10 @@
|
|||
*
|
||||
* */
|
||||
|
||||
#ifndef __MEM_RUBY_GLOBAL_HH__
|
||||
#define __MEM_RUBY_GLOBAL_HH__
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
/*
|
||||
#ifdef SINGLE_LEVEL_CACHE
|
||||
const bool TWO_LEVEL_CACHE = false;
|
||||
#define L1I_CACHE_MEMBER_VARIABLE m_L1Cache_cacheMemory_vec[m_version] // currently all protocols require L1s == nodes
|
||||
|
@ -60,24 +61,11 @@ const bool TWO_LEVEL_CACHE = true;
|
|||
#define DIRECTORY_MEMBER_VARIABLE m_Directory_directory_vec[m_version]
|
||||
#define TBE_TABLE_MEMBER_VARIABLE m_L1Cache_TBEs_vec[m_version]
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long uint64;
|
||||
*/
|
||||
|
||||
typedef signed char int8;
|
||||
typedef int int32;
|
||||
typedef long long int64;
|
||||
|
||||
typedef long long integer_t;
|
||||
typedef unsigned long long uinteger_t;
|
||||
|
||||
typedef int64 Time;
|
||||
typedef uint64 physical_address_t;
|
||||
typedef uint64 la_t;
|
||||
typedef uint64 pa_t;
|
||||
typedef integer_t simtime_t;
|
||||
|
||||
// external includes for all classes
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
#include "mem/gems_common/std-includes.hh"
|
||||
#include "mem/ruby/common/Debug.hh"
|
||||
|
||||
|
@ -85,6 +73,7 @@ typedef integer_t simtime_t;
|
|||
typedef Time LogicalTime;
|
||||
typedef int64 Index; // what the address bit ripper returns
|
||||
typedef int word; // one word of a cache line
|
||||
typedef unsigned int uint;
|
||||
typedef int SwitchID;
|
||||
typedef int LinkID;
|
||||
|
||||
|
@ -105,5 +94,5 @@ extern inline int max_tokens()
|
|||
}
|
||||
|
||||
|
||||
#endif // __MEM_RUBY_GLOBAL_HH__
|
||||
#endif //GLOBAL_H
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
// set sizes
|
||||
|
||||
#include "mem/ruby/common/Set.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
|
||||
#if __amd64__ || __LP64__
|
||||
|
@ -51,7 +52,7 @@
|
|||
Set::Set()
|
||||
{
|
||||
m_p_nArray = NULL;
|
||||
setSize(RubyConfig::numberOfProcessors());
|
||||
setSize(RubySystem::getNumberOfSequencers());
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
|
@ -511,7 +512,7 @@ void Set::setSize(int size)
|
|||
#endif // __32BITS__
|
||||
|
||||
// decide whether to use dynamic or static alloction
|
||||
if(m_nArrayLen<=NUMBER_WORDS_PER_SET) { // constant defined in RubyConfig.h
|
||||
if(m_nArrayLen<=NUMBER_WORDS_PER_SET) { // constant defined in RubyConfig.hh
|
||||
// its OK to use the static allocation, and it will
|
||||
// probably be faster (as m_nArrayLen is already in the
|
||||
// cache and they will probably share the same cache line)
|
||||
|
@ -560,7 +561,7 @@ void Set::print(ostream& out) const
|
|||
return;
|
||||
}
|
||||
char buff[24];
|
||||
out << "[Set 0x ";
|
||||
out << "[Set (" << m_nSize << ") 0x ";
|
||||
for (int i=m_nArrayLen-1; i>=0; i--) {
|
||||
#ifdef __32BITS__
|
||||
sprintf(buff,"%08X ",m_p_nArray[i]);
|
||||
|
|
|
@ -42,16 +42,6 @@ SubBlock::SubBlock(const Address& addr, int size)
|
|||
}
|
||||
}
|
||||
|
||||
SubBlock::SubBlock(const Address& addr, const Address& logicalAddress, int size)
|
||||
{
|
||||
m_address = addr;
|
||||
m_logicalAddress = logicalAddress;
|
||||
setSize(size);
|
||||
for(int i=0; i<size; i++) {
|
||||
setByte(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SubBlock::internalMergeFrom(const DataBlock& data)
|
||||
{
|
||||
int size = getSize();
|
||||
|
|
|
@ -46,16 +46,13 @@ public:
|
|||
// Constructors
|
||||
SubBlock() { }
|
||||
SubBlock(const Address& addr, int size);
|
||||
SubBlock(const Address& addr, const Address& logicalAddress, int size);
|
||||
|
||||
// Destructor
|
||||
~SubBlock() { }
|
||||
|
||||
// Public Methods
|
||||
const Address& getAddress() const { return m_address; }
|
||||
const Address& getLogicalAddress() const { return m_logicalAddress; }
|
||||
void setAddress(const Address& addr) { m_address = addr; }
|
||||
void setLogicalAddress(const Address& addr) { m_logicalAddress = addr; }
|
||||
|
||||
int getSize() const { return m_data.size(); }
|
||||
void setSize(int size) { m_data.setSize(size); }
|
||||
|
@ -68,24 +65,18 @@ public:
|
|||
|
||||
// Merging to and from DataBlocks - We only need to worry about
|
||||
// updates when we are using DataBlocks
|
||||
void mergeTo(DataBlock& data) const { if (DATA_BLOCK) { internalMergeTo(data); } }
|
||||
void mergeFrom(const DataBlock& data) { if (DATA_BLOCK) { internalMergeFrom(data); } }
|
||||
void mergeTo(DataBlock& data) const { internalMergeTo(data); }
|
||||
void mergeFrom(const DataBlock& data) { internalMergeFrom(data); }
|
||||
|
||||
void print(ostream& out) const;
|
||||
private:
|
||||
// Private Methods
|
||||
// SubBlock(const SubBlock& obj);
|
||||
// SubBlock& operator=(const SubBlock& obj);
|
||||
// bool bytePresent(const Address& addr) { return ((addr.getAddress() >= m_address.getAddress()) && (addr.getAddress() < (m_address.getAddress()+getSize()))); }
|
||||
// uint8 getByte(const Address& addr) { return m_data[addr.getAddress() - m_address.getAddress()]; }
|
||||
|
||||
void internalMergeTo(DataBlock& data) const;
|
||||
void internalMergeFrom(const DataBlock& data);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
Address m_address;
|
||||
Address m_logicalAddress;
|
||||
Vector<unsigned> m_data;
|
||||
Vector<uint> m_data;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
|
|
23
src/mem/ruby/common/TypeDefines.hh
Normal file
23
src/mem/ruby/common/TypeDefines.hh
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef TYPEDEFINES_H
|
||||
#define TYPEDEFINES_H
|
||||
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
typedef signed char int8;
|
||||
typedef int int32;
|
||||
typedef long long int64;
|
||||
|
||||
typedef long long integer_t;
|
||||
typedef unsigned long long uinteger_t;
|
||||
|
||||
typedef int64 Time;
|
||||
typedef uint64 physical_address_t;
|
||||
typedef uint64 la_t;
|
||||
typedef uint64 pa_t;
|
||||
typedef integer_t simtime_t;
|
||||
|
||||
#endif
|
64
src/mem/ruby/config/MI_example-homogeneous.rb
Normal file
64
src/mem/ruby/config/MI_example-homogeneous.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/ruby
|
||||
#
|
||||
# Creates a homogeneous CMP system with a single unified cache per
|
||||
# core and a crossbar network. Uses the default parameters listed
|
||||
# below, which can be overridden if a wrapper script sets the hash
|
||||
# libruby_args.
|
||||
#
|
||||
|
||||
require "cfg.rb"
|
||||
|
||||
# default values
|
||||
|
||||
num_cores = 16
|
||||
L1_CACHE_SIZE_KB = 32
|
||||
L1_CACHE_ASSOC = 8
|
||||
L1_CACHE_LATENCY = "auto"
|
||||
num_memories = 2
|
||||
memory_size_mb = 1024
|
||||
NUM_DMA = 1
|
||||
|
||||
# check for overrides
|
||||
|
||||
for i in 0..$*.size-1 do
|
||||
if $*[i] == "-p"
|
||||
num_cores = $*[i+1].to_i
|
||||
i = i+1
|
||||
elsif $*[i] == "-m"
|
||||
num_memories = $*[i+1].to_i
|
||||
i = i+1
|
||||
elsif $*[i] == "-s"
|
||||
memory_size_mb = $*[i+1].to_i
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
net_ports = Array.new
|
||||
iface_ports = Array.new
|
||||
|
||||
num_cores.times { |n|
|
||||
cache = SetAssociativeCache.new("l1u_"+n.to_s, L1_CACHE_SIZE_KB, L1_CACHE_LATENCY, L1_CACHE_ASSOC, "PSEUDO_LRU")
|
||||
sequencer = Sequencer.new("Sequencer_"+n.to_s, cache, cache)
|
||||
iface_ports << sequencer
|
||||
net_ports << MI_example_CacheController.new("L1CacheController_"+n.to_s,
|
||||
"L1Cache",
|
||||
[cache],
|
||||
sequencer)
|
||||
}
|
||||
num_memories.times { |n|
|
||||
directory = DirectoryMemory.new("DirectoryMemory_"+n.to_s, memory_size_mb/num_memories)
|
||||
memory_control = MemoryControl.new("MemoryControl_"+n.to_s)
|
||||
net_ports << MI_example_DirectoryController.new("DirectoryController_"+n.to_s,
|
||||
"Directory",
|
||||
directory, memory_control)
|
||||
}
|
||||
NUM_DMA.times { |n|
|
||||
dma_sequencer = DMASequencer.new("DMASequencer_"+n.to_s)
|
||||
iface_ports << dma_sequencer
|
||||
net_ports << DMAController.new("DMAController_"+n.to_s, "DMA", dma_sequencer)
|
||||
}
|
||||
|
||||
topology = CrossbarTopology.new("theTopology", net_ports)
|
||||
on_chip_net = Network.new("theNetwork", topology)
|
||||
|
||||
RubySystem.init(iface_ports, on_chip_net)
|
|
@ -36,135 +36,191 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "config/ruby_debug.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/protocol/protocol_name.hh"
|
||||
//#include "mem/protocol/protocol_name.hh"
|
||||
#include "mem/gems_common/util.hh"
|
||||
#include "mem/protocol/Protocol.hh"
|
||||
|
||||
#define CONFIG_DEF_FILE "mem/ruby/config/config.hh"
|
||||
|
||||
#define ERROR_MSG(MESSAGE)\
|
||||
{\
|
||||
cerr << "Fatal Error: in fn "\
|
||||
<< __PRETTY_FUNCTION__ << " in "\
|
||||
<< __FILE__ << ":"\
|
||||
<< __LINE__ << ": "\
|
||||
<< (MESSAGE) << endl << flush;\
|
||||
abort();\
|
||||
}
|
||||
|
||||
// declare all configuration variables
|
||||
#define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
bool RubyConfig::m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
const char* RubyConfig::m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
uint64 RubyConfig::m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
int RubyConfig::m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
TYPE* RubyConfig::m_##NAME = NULL;
|
||||
#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
TYPE** RubyConfig::m_##NAME = NULL;
|
||||
#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
TYPE*** RubyConfig::m_##NAME = NULL;
|
||||
#include CONFIG_DEF_FILE
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM
|
||||
#undef PARAM_ARRAY
|
||||
#undef PARAM_ARRAY2D
|
||||
#undef PARAM_ARRAY3D
|
||||
|
||||
#define CHECK_POWER_OF_2(N) { if (!is_power_of_2(N)) { ERROR_MSG(#N " must be a power of 2."); }}
|
||||
#define CHECK_ZERO(N) { if (N != 0) { ERROR_MSG(#N " must be zero at initialization."); }}
|
||||
#define CHECK_NON_ZERO(N) { if (N == 0) { ERROR_MSG(#N " must be non-zero."); }}
|
||||
|
||||
uint32 RubyConfig::m_data_block_mask;
|
||||
|
||||
void RubyConfig::reset()
|
||||
{
|
||||
#define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = DEFAULT_VALUE;
|
||||
#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = new TYPE[DEFAULT_ARRAY_SIZE]; \
|
||||
for (int i=0; i<DEFAULT_ARRAY_SIZE; i++) \
|
||||
m_##NAME[i] = DEFAULT_VALUE;
|
||||
#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = new TYPE*[D1_DEFAULT_ARRAY_SIZE]; \
|
||||
for (int i=0; i<D1_DEFAULT_ARRAY_SIZE; i++) { \
|
||||
m_##NAME[i] = new TYPE[D2_DEFAULT_ARRAY_SIZE]; \
|
||||
for (int j=0; j<D2_DEFAULT_ARRAY_SIZE; j++) \
|
||||
m_##NAME[i][j] = DEFAULT_VALUE; \
|
||||
}
|
||||
#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
m_##NAME = new TYPE**[D1_DEFAULT_ARRAY_SIZE]; \
|
||||
for (int i=0; i<D1_DEFAULT_ARRAY_SIZE; i++) { \
|
||||
m_##NAME[i] = new TYPE*[D2_DEFAULT_ARRAY_SIZE]; \
|
||||
for (int j=0; j<D2_DEFAULT_ARRAY_SIZE; j++) { \
|
||||
m_##NAME[i][j] = new TYPE[D3_DEFAULT_ARRAY_SIZE]; \
|
||||
for (int k=0; k<D3_DEFAULT_ARRAY_SIZE; k++) \
|
||||
m_##NAME[i][j][k] = DEFUALT_VALUE; \
|
||||
} \
|
||||
}
|
||||
#include CONFIG_DEF_FILE
|
||||
#undef PARAM_BOOL
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ULONG
|
||||
#undef PARAM
|
||||
#undef PARAM_ARRAY
|
||||
#undef PARAM_ARRAY2D
|
||||
#undef PARAM_ARRAY3D
|
||||
}
|
||||
|
||||
void RubyConfig::init()
|
||||
{
|
||||
/*
|
||||
// MemoryControl:
|
||||
CHECK_NON_ZERO(MEM_BUS_CYCLE_MULTIPLIER);
|
||||
CHECK_NON_ZERO(BANKS_PER_RANK);
|
||||
CHECK_NON_ZERO(RANKS_PER_DIMM);
|
||||
CHECK_NON_ZERO(DIMMS_PER_CHANNEL);
|
||||
CHECK_NON_ZERO(BANK_QUEUE_SIZE);
|
||||
CHECK_NON_ZERO(BANK_BUSY_TIME);
|
||||
CHECK_NON_ZERO(MEM_CTL_LATENCY);
|
||||
CHECK_NON_ZERO(REFRESH_PERIOD);
|
||||
CHECK_NON_ZERO(BASIC_BUS_BUSY_TIME);
|
||||
CHECK_NON_ZERO(m_MEM_BUS_CYCLE_MULTIPLIER);
|
||||
CHECK_NON_ZERO(m_BANKS_PER_RANK);
|
||||
CHECK_NON_ZERO(m_RANKS_PER_DIMM);
|
||||
CHECK_NON_ZERO(m_DIMMS_PER_CHANNEL);
|
||||
CHECK_NON_ZERO(m_BANK_QUEUE_SIZE);
|
||||
CHECK_NON_ZERO(m_BankBusyTime);
|
||||
CHECK_NON_ZERO(m_MEM_CTL_LATENCY);
|
||||
CHECK_NON_ZERO(m_REFRESH_PERIOD);
|
||||
CHECK_NON_ZERO(m_BASIC_BUS_BUSY_TIME);
|
||||
|
||||
CHECK_POWER_OF_2(BANKS_PER_RANK);
|
||||
CHECK_POWER_OF_2(RANKS_PER_DIMM);
|
||||
CHECK_POWER_OF_2(DIMMS_PER_CHANNEL);
|
||||
CHECK_POWER_OF_2(m_BANKS_PER_RANK);
|
||||
CHECK_POWER_OF_2(m_RANKS_PER_DIMM);
|
||||
CHECK_POWER_OF_2(m_DIMMS_PER_CHANNEL);
|
||||
|
||||
CHECK_NON_ZERO(g_MEMORY_SIZE_BYTES);
|
||||
CHECK_NON_ZERO(g_DATA_BLOCK_BYTES);
|
||||
CHECK_NON_ZERO(g_PAGE_SIZE_BYTES);
|
||||
CHECK_NON_ZERO(g_NUM_PROCESSORS);
|
||||
CHECK_NON_ZERO(g_PROCS_PER_CHIP);
|
||||
if(g_NUM_SMT_THREADS == 0){ //defaults to single-threaded
|
||||
g_NUM_SMT_THREADS = 1;
|
||||
CHECK_NON_ZERO(m_MemorySizeBytes);
|
||||
// CHECK_NON_ZERO(m_DATA_BLOCK_BYTES);
|
||||
CHECK_NON_ZERO(m_NUM_PROCESSORS);
|
||||
CHECK_NON_ZERO(m_ProcsPerChip);
|
||||
|
||||
if (m_NUM_L2_BANKS == 0) { // defaults to number of ruby nodes
|
||||
m_NUM_L2_BANKS = m_NUM_PROCESSORS;
|
||||
}
|
||||
if (g_NUM_L2_BANKS == 0) { // defaults to number of ruby nodes
|
||||
g_NUM_L2_BANKS = g_NUM_PROCESSORS;
|
||||
}
|
||||
if (g_NUM_MEMORIES == 0) { // defaults to number of ruby nodes
|
||||
g_NUM_MEMORIES = g_NUM_PROCESSORS;
|
||||
if (m_NUM_MEMORIES == 0) { // defaults to number of ruby nodes
|
||||
m_NUM_MEMORIES = m_NUM_PROCESSORS;
|
||||
}
|
||||
|
||||
CHECK_ZERO(g_MEMORY_SIZE_BITS);
|
||||
CHECK_ZERO(g_DATA_BLOCK_BITS);
|
||||
CHECK_ZERO(g_PAGE_SIZE_BITS);
|
||||
CHECK_ZERO(g_NUM_PROCESSORS_BITS);
|
||||
CHECK_ZERO(g_NUM_CHIP_BITS);
|
||||
CHECK_ZERO(g_NUM_L2_BANKS_BITS);
|
||||
CHECK_ZERO(g_NUM_MEMORIES_BITS);
|
||||
CHECK_ZERO(g_PROCS_PER_CHIP_BITS);
|
||||
CHECK_ZERO(g_NUM_L2_BANKS_PER_CHIP);
|
||||
CHECK_ZERO(g_NUM_L2_BANKS_PER_CHIP_BITS);
|
||||
CHECK_ZERO(g_NUM_MEMORIES_BITS);
|
||||
CHECK_ZERO(g_MEMORY_MODULE_BLOCKS);
|
||||
CHECK_ZERO(g_MEMORY_MODULE_BITS);
|
||||
CHECK_ZERO(g_NUM_MEMORIES_PER_CHIP);
|
||||
CHECK_ZERO(m_MEMORY_SIZE_BITS);
|
||||
CHECK_ZERO(m_NUM_PROCESSORS_BITS);
|
||||
CHECK_ZERO(m_NUM_CHIP_BITS);
|
||||
CHECK_ZERO(m_NUM_L2_BANKS_BITS);
|
||||
CHECK_ZERO(m_NUM_MEMORIES_BITS);
|
||||
CHECK_ZERO(m_PROCS_PER_CHIP_BITS);
|
||||
CHECK_ZERO(m_NUM_L2_BANKS_PER_CHIP);
|
||||
CHECK_ZERO(m_NUM_L2_BANKS_PER_CHIP_BITS);
|
||||
CHECK_ZERO(m_NUM_MEMORIES_BITS);
|
||||
CHECK_ZERO(m_MEMORY_MODULE_BLOCKS);
|
||||
CHECK_ZERO(m_MEMORY_MODULE_BITS);
|
||||
CHECK_ZERO(m_NUM_MEMORIES_PER_CHIP);
|
||||
|
||||
CHECK_POWER_OF_2(g_MEMORY_SIZE_BYTES);
|
||||
CHECK_POWER_OF_2(g_DATA_BLOCK_BYTES);
|
||||
CHECK_POWER_OF_2(g_NUM_PROCESSORS);
|
||||
CHECK_POWER_OF_2(g_NUM_L2_BANKS);
|
||||
CHECK_POWER_OF_2(g_NUM_MEMORIES);
|
||||
CHECK_POWER_OF_2(g_PROCS_PER_CHIP);
|
||||
CHECK_POWER_OF_2(m_MemorySizeBytes);
|
||||
CHECK_POWER_OF_2(m_NUM_PROCESSORS);
|
||||
CHECK_POWER_OF_2(m_NUM_L2_BANKS);
|
||||
CHECK_POWER_OF_2(m_NUM_MEMORIES);
|
||||
CHECK_POWER_OF_2(m_ProcsPerChip);
|
||||
|
||||
ASSERT(g_NUM_PROCESSORS >= g_PROCS_PER_CHIP); // obviously can't have less processors than procs/chip
|
||||
g_NUM_CHIPS = g_NUM_PROCESSORS/g_PROCS_PER_CHIP;
|
||||
ASSERT(g_NUM_L2_BANKS >= g_NUM_CHIPS); // cannot have a single L2cache across multiple chips
|
||||
assert(m_NUM_PROCESSORS >= m_ProcsPerChip); // obviously can't have less processors than procs/chip
|
||||
m_NUM_CHIPS = m_NUM_PROCESSORS/m_ProcsPerChip;
|
||||
assert(m_NUM_L2_BANKS >= m_NUM_CHIPS); // cannot have a single L2cache across multiple chips
|
||||
|
||||
g_NUM_L2_BANKS_PER_CHIP = g_NUM_L2_BANKS/g_NUM_CHIPS;
|
||||
m_NUM_L2_BANKS_PER_CHIP = m_NUM_L2_BANKS/m_NUM_CHIPS;
|
||||
|
||||
ASSERT(L2_CACHE_NUM_SETS_BITS > log_int(g_NUM_L2_BANKS_PER_CHIP)); // cannot have less than one set per bank
|
||||
L2_CACHE_NUM_SETS_BITS = L2_CACHE_NUM_SETS_BITS - log_int(g_NUM_L2_BANKS_PER_CHIP);
|
||||
|
||||
if (g_NUM_CHIPS > g_NUM_MEMORIES) {
|
||||
g_NUM_MEMORIES_PER_CHIP = 1; // some chips have a memory, others don't
|
||||
if (m_NUM_CHIPS > m_NUM_MEMORIES) {
|
||||
m_NUM_MEMORIES_PER_CHIP = 1; // some chips have a memory, others don't
|
||||
} else {
|
||||
g_NUM_MEMORIES_PER_CHIP = g_NUM_MEMORIES/g_NUM_CHIPS;
|
||||
m_NUM_MEMORIES_PER_CHIP = m_NUM_MEMORIES/m_NUM_CHIPS;
|
||||
}
|
||||
|
||||
g_NUM_CHIP_BITS = log_int(g_NUM_CHIPS);
|
||||
g_MEMORY_SIZE_BITS = log_int(g_MEMORY_SIZE_BYTES);
|
||||
g_DATA_BLOCK_BITS = log_int(g_DATA_BLOCK_BYTES);
|
||||
g_PAGE_SIZE_BITS = log_int(g_PAGE_SIZE_BYTES);
|
||||
g_NUM_PROCESSORS_BITS = log_int(g_NUM_PROCESSORS);
|
||||
g_NUM_L2_BANKS_BITS = log_int(g_NUM_L2_BANKS);
|
||||
g_NUM_L2_BANKS_PER_CHIP_BITS = log_int(g_NUM_L2_BANKS_PER_CHIP);
|
||||
g_NUM_MEMORIES_BITS = log_int(g_NUM_MEMORIES);
|
||||
g_PROCS_PER_CHIP_BITS = log_int(g_PROCS_PER_CHIP);
|
||||
m_NUM_CHIP_BITS = log_int(m_NUM_CHIPS);
|
||||
m_MEMORY_SIZE_BITS = log_int(m_MemorySizeBytes);
|
||||
|
||||
g_MEMORY_MODULE_BITS = g_MEMORY_SIZE_BITS - g_DATA_BLOCK_BITS - g_NUM_MEMORIES_BITS;
|
||||
g_MEMORY_MODULE_BLOCKS = (int64(1) << g_MEMORY_MODULE_BITS);
|
||||
m_data_block_mask = ~ (~0 << m_DATA_BLOCK_BITS);
|
||||
|
||||
if ((!Protocol::m_CMP) && (g_PROCS_PER_CHIP > 1)) {
|
||||
ERROR_MSG("Non-CMP protocol should set g_PROCS_PER_CHIP to 1");
|
||||
}
|
||||
m_NUM_PROCESSORS_BITS = log_int(m_NUM_PROCESSORS);
|
||||
m_NUM_L2_BANKS_BITS = log_int(m_NUM_L2_BANKS);
|
||||
m_NUM_L2_BANKS_PER_CHIP_BITS = log_int(m_NUM_L2_BANKS_PER_CHIP);
|
||||
m_NUM_MEMORIES_BITS = log_int(m_NUM_MEMORIES);
|
||||
m_PROCS_PER_CHIP_BITS = log_int(m_ProcsPerChip);
|
||||
|
||||
m_MEMORY_MODULE_BITS = m_MEMORY_SIZE_BITS - m_DATA_BLOCK_BITS - m_NUM_MEMORIES_BITS;
|
||||
m_MEMORY_MODULE_BLOCKS = (int64(1) << m_MEMORY_MODULE_BITS);
|
||||
|
||||
*/
|
||||
|
||||
// Randomize the execution
|
||||
srandom(g_RANDOM_SEED);
|
||||
}
|
||||
|
||||
int RubyConfig::L1CacheNumToL2Base(NodeID L1CacheNum)
|
||||
{
|
||||
return L1CacheNum/g_PROCS_PER_CHIP;
|
||||
// srandom(m_RandomSeed);
|
||||
}
|
||||
|
||||
static void print_parameters(ostream& out)
|
||||
{
|
||||
|
||||
#define PARAM(NAME) { out << #NAME << ": " << NAME << endl; }
|
||||
#define PARAM_UINT(NAME) { out << #NAME << ": " << NAME << endl; }
|
||||
#define PARAM_ULONG(NAME) { out << #NAME << ": " << NAME << endl; }
|
||||
#define PARAM_BOOL(NAME) { out << #NAME << ": " << bool_to_string(NAME) << endl; }
|
||||
#define PARAM_DOUBLE(NAME) { out << #NAME << ": " << NAME << endl; }
|
||||
#define PARAM_STRING(NAME) { assert(NAME != NULL); out << #NAME << ": " << string(NAME) << endl; }
|
||||
#define PARAM_ARRAY(PTYPE, NAME, ARRAY_SIZE) \
|
||||
{ \
|
||||
out << #NAME << ": ("; \
|
||||
for (int i = 0; i < ARRAY_SIZE; i++) { \
|
||||
if (i != 0) { \
|
||||
out << ", "; \
|
||||
} \
|
||||
out << NAME[i]; \
|
||||
} \
|
||||
out << ")" << endl; \
|
||||
} \
|
||||
#define print_true(NAME)
|
||||
#define print_false(NAME) \
|
||||
out << #NAME << ": " << RubyConfig::get##NAME () << endl
|
||||
|
||||
|
||||
#include "mem/ruby/config/config.hh"
|
||||
#define PARAM(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_UINT(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_ULONG(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_BOOL(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_DOUBLE(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_STRING(NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR) { print_##CUSTOM_ACCESSOR(NAME); }
|
||||
#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY" << endl; }
|
||||
#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY2D" << endl; }
|
||||
#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) { out << #NAME << ": ARRAY3D" << endl; }
|
||||
#include CONFIG_VAR_FILENAME
|
||||
#undef PARAM
|
||||
#undef PARAM_UINT
|
||||
#undef PARAM_ULONG
|
||||
|
@ -172,15 +228,17 @@ static void print_parameters(ostream& out)
|
|||
#undef PARAM_DOUBLE
|
||||
#undef PARAM_STRING
|
||||
#undef PARAM_ARRAY
|
||||
#undef PARAM_ARRAY2D
|
||||
#undef PARAM_ARRAY3D
|
||||
}
|
||||
|
||||
void RubyConfig::printConfiguration(ostream& out) {
|
||||
out << "Ruby Configuration" << endl;
|
||||
out << "------------------" << endl;
|
||||
|
||||
out << "protocol: " << CURRENT_PROTOCOL << endl;
|
||||
//out << "protocol: " << CURRENT_PROTOCOL << endl;
|
||||
out << "compiled_at: " << __TIME__ << ", " << __DATE__ << endl;
|
||||
out << "RUBY_DEBUG: " << bool_to_string(RUBY_DEBUG) << endl;
|
||||
// out << "RUBY_DEBUG: " << bool_to_string(RUBY_DEBUG) << endl;
|
||||
|
||||
char buffer[100];
|
||||
gethostname(buffer, 50);
|
||||
|
|
|
@ -40,12 +40,13 @@
|
|||
#ifndef RUBYCONFIG_H
|
||||
#define RUBYCONFIG_H
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/gems_common/ioutil/vardecl.hh"
|
||||
#include "mem/ruby/system/NodeID.hh"
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <assert.h>
|
||||
|
||||
#define MEMORY_LATENCY RubyConfig::memoryResponseLatency()
|
||||
#define ABORT_DELAY m_chip_ptr->getTransactionManager(m_version)->getAbortDelay()
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
#define CONFIG_VAR_FILENAME "mem/ruby/config/config.hh"
|
||||
|
||||
// Set paramterization
|
||||
/*
|
||||
|
@ -61,96 +62,169 @@
|
|||
*/
|
||||
const int NUMBER_WORDS_PER_SET = 4;
|
||||
|
||||
using namespace std;
|
||||
|
||||
class RubyConfig {
|
||||
public:
|
||||
|
||||
// CACHE BLOCK CONFIG VARIBLES
|
||||
static int dataBlockBits() { return g_DATA_BLOCK_BITS; }
|
||||
static int dataBlockBytes() { return g_DATA_BLOCK_BYTES; }
|
||||
static uint32 dataBlockMask() { return m_data_block_mask; }
|
||||
|
||||
static int numberOfDMA() { return 1; }
|
||||
static int numberOfDMAPerChip() { return 1; }
|
||||
static int DMATransitionsPerCycle() { return 1; }
|
||||
|
||||
// SUPPORTED PHYSICAL MEMORY CONFIG VARIABLES
|
||||
static int pageSizeBits() { return g_PAGE_SIZE_BITS; }
|
||||
static int pageSizeBytes() { return g_PAGE_SIZE_BYTES; }
|
||||
static int memorySizeBits() { return g_MEMORY_SIZE_BITS; }
|
||||
static int64 memorySizeBytes() { return g_MEMORY_SIZE_BYTES; }
|
||||
static int memoryModuleBits() { return g_MEMORY_MODULE_BITS; }
|
||||
static int64 memoryModuleBlocks() { return g_MEMORY_MODULE_BLOCKS; }
|
||||
// static int memoryModuleBits() { return m_MEMORY_MODULE_BITS; }
|
||||
// static int64 memoryModuleBlocks() { return m_MEMORY_MODULE_BLOCKS; }
|
||||
|
||||
// returns number of SMT threads per physical processor
|
||||
static int numberofSMTThreads() { return g_NUM_SMT_THREADS; }
|
||||
// defines the number of simics processors (power of 2)
|
||||
static int numberOfProcessors() { return g_NUM_PROCESSORS; }
|
||||
static int procsPerChipBits() { return g_PROCS_PER_CHIP_BITS; }
|
||||
static int numberOfProcsPerChip() { return g_PROCS_PER_CHIP; }
|
||||
static int numberOfChips() { return g_NUM_CHIPS; }
|
||||
// static int numberOfProcessors() { return m_NUM_PROCESSORS; }
|
||||
// static int procsPerChipBits() { return m_PROCS_PER_CHIP_BITS; }
|
||||
// static int numberOfProcsPerChip() { return m_ProcsPerChip; }
|
||||
// static int numberOfChips() { return m_NUM_CHIPS; }
|
||||
|
||||
// MACHINE INSTANIATION CONFIG VARIABLES
|
||||
// -------------------------------------
|
||||
// L1 CACHE MACHINES
|
||||
// defines the number of L1banks - idependent of ruby chips (power of 2)
|
||||
// NOTE - no protocols currently supports L1s != processors, just a placeholder
|
||||
static int L1CacheBits() { return g_NUM_PROCESSORS_BITS; }
|
||||
static int numberOfL1Cache() { return g_NUM_PROCESSORS; }
|
||||
static int L1CachePerChipBits() { return procsPerChipBits() ; } // L1s != processors not currently supported
|
||||
static int numberOfL1CachePerChip() { return numberOfProcsPerChip(); } // L1s != processors not currently supported
|
||||
static int numberOfL1CachePerChip(NodeID myNodeID) { return numberOfL1CachePerChip(); }
|
||||
static int L1CacheTransitionsPerCycle() { return L1CACHE_TRANSITIONS_PER_RUBY_CYCLE; }
|
||||
|
||||
// L2 CACHE MACHINES
|
||||
// defines the number of L2banks/L2Caches - idependent of ruby chips (power of 2)
|
||||
static int L2CacheBits() { return g_NUM_L2_BANKS_BITS; }
|
||||
static int numberOfL2Cache() { return g_NUM_L2_BANKS; }
|
||||
static int L1CacheNumToL2Base(NodeID L1RubyNodeID);
|
||||
static int L2CachePerChipBits() { return g_NUM_L2_BANKS_PER_CHIP_BITS; }
|
||||
static int numberOfL2CachePerChip() { return g_NUM_L2_BANKS_PER_CHIP; }
|
||||
static int numberOfL2CachePerChip(NodeID myNodeID) { return numberOfL2CachePerChip(); }
|
||||
static int L2CacheTransitionsPerCycle() { return L2CACHE_TRANSITIONS_PER_RUBY_CYCLE; }
|
||||
|
||||
// DIRECTORY/MEMORY MACHINES
|
||||
// defines the number of ruby memories - idependent of ruby chips (power of 2)
|
||||
static int memoryBits() { return g_NUM_MEMORIES_BITS; }
|
||||
static int numberOfDirectory() { return numberOfMemories(); }
|
||||
static int numberOfMemories() { return g_NUM_MEMORIES; }
|
||||
static int numberOfDirectoryPerChip() { return g_NUM_MEMORIES_PER_CHIP; }
|
||||
static int numberOfDirectoryPerChip(NodeID myNodeID) { return g_NUM_MEMORIES_PER_CHIP; }
|
||||
static int DirectoryTransitionsPerCycle() { return DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE; }
|
||||
|
||||
// PERSISTENT ARBITER MACHINES
|
||||
static int numberOfPersistentArbiter() { return numberOfMemories(); }
|
||||
static int numberOfPersistentArbiterPerChip() {return numberOfDirectoryPerChip(); }
|
||||
static int numberOfPersistentArbiterPerChip(NodeID myNodeID) {return numberOfDirectoryPerChip(myNodeID); }
|
||||
static int PersistentArbiterTransitionsPerCycle() { return L2CACHE_TRANSITIONS_PER_RUBY_CYCLE; }
|
||||
// static int memoryBits() { return m_NUM_MEMORIES_BITS; }
|
||||
// static int numberOfDirectory() { return numberOfMemories(); }
|
||||
// static int numberOfMemories() { return m_NUM_MEMORIES; }
|
||||
// static int numberOfDirectoryPerChip() { return m_NUM_MEMORIES_PER_CHIP; }
|
||||
// static int DirectoryTransitionsPerCycle() { return m_DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE; }
|
||||
|
||||
// ---- END MACHINE SPECIFIC VARIABLES ----
|
||||
|
||||
// VARIABLE MEMORY RESPONSE LATENCY
|
||||
// *** NOTE *** This is where variation is added to the simulation
|
||||
// see Alameldeen et al. HPCA 2003 for further details
|
||||
static int memoryResponseLatency() { return MEMORY_RESPONSE_LATENCY_MINUS_2+(random() % 5); }
|
||||
// static int getMemoryLatency() { return m_MEMORY_RESPONSE_LATENCY_MINUS_2+(random() % 5); }
|
||||
|
||||
static void reset();
|
||||
static void init();
|
||||
static void printConfiguration(ostream& out);
|
||||
static void printConfiguration(std::ostream& out);
|
||||
|
||||
// Memory Controller
|
||||
static int memBusCycleMultiplier () { return MEM_BUS_CYCLE_MULTIPLIER; }
|
||||
static int banksPerRank () { return BANKS_PER_RANK; }
|
||||
static int ranksPerDimm () { return RANKS_PER_DIMM; }
|
||||
static int dimmsPerChannel () { return DIMMS_PER_CHANNEL; }
|
||||
static int bankBit0 () { return BANK_BIT_0; }
|
||||
static int rankBit0 () { return RANK_BIT_0; }
|
||||
static int dimmBit0 () { return DIMM_BIT_0; }
|
||||
static int bankQueueSize () { return BANK_QUEUE_SIZE; }
|
||||
static int bankBusyTime () { return BANK_BUSY_TIME; }
|
||||
static int rankRankDelay () { return RANK_RANK_DELAY; }
|
||||
static int readWriteDelay () { return READ_WRITE_DELAY; }
|
||||
static int basicBusBusyTime () { return BASIC_BUS_BUSY_TIME; }
|
||||
static int memCtlLatency () { return MEM_CTL_LATENCY; }
|
||||
static int refreshPeriod () { return REFRESH_PERIOD; }
|
||||
static int tFaw () { return TFAW; }
|
||||
static int memRandomArbitrate () { return MEM_RANDOM_ARBITRATE; }
|
||||
static int memFixedDelay () { return MEM_FIXED_DELAY; }
|
||||
|
||||
// static int memBusCycleMultiplier () { return m_MEM_BUS_CYCLE_MULTIPLIER; }
|
||||
/* static int banksPerRank () { return m_BANKS_PER_RANK; }
|
||||
static int ranksPerDimm () { return m_RANKS_PER_DIMM; }
|
||||
static int dimmsPerChannel () { return m_DIMMS_PER_CHANNEL; }
|
||||
static int bankBit0 () { return m_BANK_BIT_0; }
|
||||
static int rankBit0 () { return m_RANK_BIT_0; }
|
||||
static int dimmBit0 () { return m_DIMM_BIT_0; }
|
||||
static int bankQueueSize () { return m_BANK_QUEUE_SIZE; }
|
||||
static int bankBusyTime () { return m_BankBusyTime; }
|
||||
static int rankRankDelay () { return m_RANK_RANK_DELAY; }
|
||||
static int readWriteDelay () { return m_READ_WRITE_DELAY; }
|
||||
static int basicBusBusyTime () { return m_BASIC_BUS_BUSY_TIME; }
|
||||
static int memCtlLatency () { return m_MEM_CTL_LATENCY; }
|
||||
static int refreshPeriod () { return m_REFRESH_PERIOD; }
|
||||
static int tFaw () { return m_TFAW; }
|
||||
static int memRandomArbitrate () { return m_MEM_RANDOM_ARBITRATE; }
|
||||
static int memFixedDelay () { return m_MEM_FIXED_DELAY; }
|
||||
*/
|
||||
/* cache accessors */
|
||||
static int getCacheIDFromParams(int level, int num, string split_type) {
|
||||
// TODO: this function
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define accessor_true( TYPE, NAME )
|
||||
#define accessor_false( TYPE, NAME ) \
|
||||
static TYPE get##NAME() { return m_##NAME; } \
|
||||
static void set##NAME(TYPE val) { m_##NAME = val; }
|
||||
|
||||
#define array_accessor_true( TYPE, NAME, DEFAULT_ARRAY_SIZE )
|
||||
#define array_accessor_false( TYPE, NAME, DEFAULT_ARRAY_SIZE ) \
|
||||
static TYPE get##NAME(int idx) { \
|
||||
assert(m_##NAME != NULL); \
|
||||
return m_##NAME[idx]; \
|
||||
} \
|
||||
static void set##NAME(int idx, TYPE val) { \
|
||||
if(m_##NAME == NULL) { \
|
||||
assert(DEFAULT_ARRAY_SIZE > 0); \
|
||||
m_##NAME = new TYPE[DEFAULT_ARRAY_SIZE]; \
|
||||
} \
|
||||
m_##NAME[idx] = val; \
|
||||
}
|
||||
|
||||
#define array2d_accessor_true( TYPE, NAME )
|
||||
#define array2d_accessor_false( TYPE, NAME ) \
|
||||
static TYPE get##NAME(int idx1, int idx2) { return m_##NAME[idx1][idx2]; } \
|
||||
static void set##NAME(int idx1, int idx2, TYPE val) { m_##NAME[idx1][idx2] = val; }
|
||||
|
||||
#define array3d_accessor_true( TYPE, NAME )
|
||||
#define array3d_accessor_false( TYPE, NAME ) \
|
||||
static TYPE get##NAME(int idx1, int idx2, int idx3) { return m_##NAME[idx1][idx2][idx3]; } \
|
||||
static void set##NAME(int idx1, int idx2, int idx3, TYPE val) { m_##NAME[idx1][idx2][idx3] = val; }
|
||||
|
||||
#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(int32,NAME)
|
||||
#define PARAM_UINT( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(uint32,NAME)
|
||||
#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(uint64,NAME)
|
||||
#define PARAM_BOOL( NAME, DEFAULT_VALUE,CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(bool,NAME)
|
||||
#define PARAM_DOUBLE( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(double,NAME)
|
||||
#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
accessor_##CUSTOM_ACCESSOR(const char*,NAME)
|
||||
#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
array_accessor_##CUSTOM_ACCESSOR(TYPE, NAME, DEFAULT_ARRAY_SIZE)
|
||||
#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
array2d_accessor_##CUSTOM_ACCESSOR(TYPE, NAME)
|
||||
#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
array3d_accessor_##CUSTOM_ACCESSOR(TYPE, 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
|
||||
#undef PARAM_ARRAY2D
|
||||
#undef PARAM_ARRAY3D
|
||||
|
||||
private:
|
||||
static uint32 m_data_block_mask;
|
||||
|
||||
#define PARAM( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static int32 m_##NAME;
|
||||
#define PARAM_UINT( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static uint32 m_##NAME;
|
||||
#define PARAM_ULONG( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static uint64 m_##NAME;
|
||||
#define PARAM_BOOL( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static bool m_##NAME;
|
||||
#define PARAM_DOUBLE( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static double m_##NAME;
|
||||
#define PARAM_STRING( NAME, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static const char *m_##NAME;
|
||||
#define PARAM_ARRAY( NAME, TYPE, DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static TYPE* m_##NAME;
|
||||
#define PARAM_ARRAY2D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static TYPE** m_##NAME;
|
||||
#define PARAM_ARRAY3D( NAME, TYPE, D1_DEFAULT_ARRAY_SIZE, D2_DEFAULT_ARRAY_SIZE, D3_DEFAULT_ARRAY_SIZE, DEFAULT_VALUE, CUSTOM_ACCESSOR ) \
|
||||
static TYPE*** m_##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
|
||||
#undef PARAM_ARRAY2D
|
||||
#undef PARAM_ARRAY3D
|
||||
|
||||
};
|
||||
|
||||
#endif //RUBYCONFIG_H
|
||||
|
|
751
src/mem/ruby/config/cfg.rb
Normal file
751
src/mem/ruby/config/cfg.rb
Normal file
|
@ -0,0 +1,751 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
class AssertionFailure < RuntimeError
|
||||
end
|
||||
|
||||
class Boolean
|
||||
def self.is_a?(obj)
|
||||
return self.name == "Boolean"
|
||||
end
|
||||
end
|
||||
|
||||
def assert(condition,message)
|
||||
unless condition
|
||||
raise AssertionFailure, "Assertion failed: #{message}"
|
||||
end
|
||||
end
|
||||
|
||||
class LibRubyObject
|
||||
@@all_objs = Array.new
|
||||
attr_reader :obj_name
|
||||
@@default_params = Hash.new
|
||||
|
||||
def initialize(obj_name)
|
||||
assert obj_name.is_a?(String), "Obj_Name must be a string"
|
||||
@obj_name = obj_name
|
||||
@@all_objs << self
|
||||
@params = Hash.new
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
raise NotImplementedException
|
||||
end
|
||||
|
||||
def self.param(param_name, type)
|
||||
idx = self.name.to_sym
|
||||
@@default_params[idx] = Hash.new if ! @@default_params.key?(idx)
|
||||
@@default_params[idx][param_name] = nil
|
||||
send :define_method, param_name do
|
||||
@params[param_name] = @@default_params[idx][param_name] if ! @params.key?(param_name)
|
||||
@params[param_name]
|
||||
end
|
||||
method_name = (param_name.to_s + "=").to_sym
|
||||
send :define_method, method_name do |val|
|
||||
if val.is_a?(FalseClass) || val.is_a?(TrueClass)
|
||||
assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false"
|
||||
else
|
||||
assert val.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}"
|
||||
end
|
||||
# assert val.is_a?(type), "#{param_name} must be of type #{type}"
|
||||
@params[param_name] = val
|
||||
end
|
||||
end
|
||||
|
||||
def self.default_param(param_name, type, default)
|
||||
idx = self.name.to_sym
|
||||
@@default_params[idx] = Hash.new if ! @@default_params.key?(idx)
|
||||
if default.is_a?(FalseClass) || default.is_a?(TrueClass)
|
||||
assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false"
|
||||
else
|
||||
assert default.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}"
|
||||
end
|
||||
@@default_params[idx][param_name] = default
|
||||
send :define_method, param_name do
|
||||
@params[param_name] = @@default_params[idx][param_name] if ! @params.key?(param_name)
|
||||
@params[param_name]
|
||||
end
|
||||
method_name = (param_name.to_s + "=").to_sym
|
||||
send :define_method, method_name do |val|
|
||||
assert val.is_a?(type), "#{param_name} must be of type #{type}"
|
||||
@params[param_name] = val
|
||||
end
|
||||
end
|
||||
|
||||
def applyDefaults()
|
||||
idx = self.class.name.to_sym
|
||||
@@default_params[idx] = Hash.new if ! @@default_params.key?(idx)
|
||||
@@default_params[idx].each { |key, val|
|
||||
@params[key] = val if ! @params.key?(key)
|
||||
}
|
||||
end
|
||||
|
||||
def argv()
|
||||
str = ""
|
||||
|
||||
applyDefaults
|
||||
|
||||
@params.each { |key, val|
|
||||
str += key.id2name + " "
|
||||
if val.is_a?(LibRubyObject)
|
||||
str += val.obj_name + " "
|
||||
else
|
||||
if val.is_a?(String) and val == ""
|
||||
str += "null "
|
||||
else
|
||||
str += val.to_s + " "
|
||||
end
|
||||
end
|
||||
}
|
||||
return str
|
||||
end
|
||||
|
||||
def self.printConstructors()
|
||||
@@all_objs.each { |obj|
|
||||
print obj.cppClassName, " ", obj.obj_name, " ",obj.argv,"\n"
|
||||
}
|
||||
end
|
||||
def self.all()
|
||||
@@all_objs
|
||||
end
|
||||
end
|
||||
|
||||
class IfacePort < LibRubyObject
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
end
|
||||
|
||||
def bochsConnType
|
||||
raise NotImplementedException
|
||||
end
|
||||
end
|
||||
|
||||
class NetPort < LibRubyObject
|
||||
attr :mach_type
|
||||
attr_reader :version
|
||||
|
||||
@@type_cnt = Hash.new
|
||||
@type_id
|
||||
def initialize(obj_name, mach_type)
|
||||
super(obj_name)
|
||||
@mach_type = mach_type
|
||||
@@type_cnt[mach_type] ||= 0
|
||||
@type_id = @@type_cnt[mach_type]
|
||||
@@type_cnt[mach_type] += 1
|
||||
|
||||
idx = "NetPort".to_sym
|
||||
@@default_params[idx] = Hash.new if ! @@default_params.key?(idx)
|
||||
@@default_params[idx].each { |key, val|
|
||||
@params[key] = val if ! @params.key?(key)
|
||||
}
|
||||
end
|
||||
|
||||
def port_name
|
||||
mach_type
|
||||
end
|
||||
def port_num
|
||||
@type_id
|
||||
end
|
||||
def cppClassName
|
||||
"NetPort"
|
||||
end
|
||||
end
|
||||
|
||||
class MemoryVector < LibRubyObject
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
end
|
||||
|
||||
def cppClassName
|
||||
"MemoryController"
|
||||
end
|
||||
end
|
||||
|
||||
class Debug < LibRubyObject
|
||||
def initialize *args
|
||||
case args.size
|
||||
when 1
|
||||
super(args[0])
|
||||
when 6
|
||||
init_params *args[1]
|
||||
else
|
||||
raise Exception
|
||||
end
|
||||
end
|
||||
|
||||
def init_params (protocol_trace, filter_string, verbosity_string, start_time, output_filename)
|
||||
@params[:protocol_trace] = protocol_trace
|
||||
@params[:filter_string] = filter_string
|
||||
@params[:verbosity_string] = verbosity_string
|
||||
@params[:start_time] = start_time
|
||||
@params[:output_filename] = output_filename
|
||||
end
|
||||
|
||||
def cppClassName
|
||||
"Debug"
|
||||
end
|
||||
end
|
||||
|
||||
class RubySystem
|
||||
|
||||
@@params = Hash.new
|
||||
@@network = nil
|
||||
|
||||
def self.init(iface_ports, network)
|
||||
@@iface_ports = iface_ports
|
||||
@@network = network
|
||||
end
|
||||
|
||||
def self.default_param(param_name, type, default)
|
||||
if default.is_a?(FalseClass) || default.is_a?(TrueClass)
|
||||
assert type.is_a?(Boolean), "default value of param \"#{param_name}\" must be either true or false"
|
||||
else
|
||||
assert default.is_a?(type), "default value of param \"#{param_name}\" does not match type #{type}"
|
||||
end
|
||||
@@params[param_name] = default
|
||||
method_name = (param_name.to_s).to_sym
|
||||
instance_eval <<-EOS
|
||||
def #{method_name.to_s}
|
||||
@@params[:#{param_name.to_s}]
|
||||
end
|
||||
EOS
|
||||
instance_eval <<-EOS
|
||||
def #{method_name.to_s}=(val)
|
||||
@@params[:#{param_name.to_s}] = val
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def self.generateConfig()
|
||||
# get current time for random seed if set to "rand"
|
||||
if @@params[:random_seed] == "rand"
|
||||
t = Time.now
|
||||
@@params[:random_seed] = t.usec.to_i
|
||||
end
|
||||
if ! @@params[:random_seed].is_a?(Integer)
|
||||
raise TypeException
|
||||
end
|
||||
print "System sys0 ",argv,"\n"
|
||||
LibRubyObject.all.each { |obj|
|
||||
if obj.is_a?(SetAssociativeCache)
|
||||
obj.calculateLatency
|
||||
end
|
||||
}
|
||||
LibRubyObject.printConstructors
|
||||
end
|
||||
|
||||
def self.printIfacePorts()
|
||||
@@iface_ports.each { |port|
|
||||
print port.obj_name, " "
|
||||
}
|
||||
puts
|
||||
end
|
||||
|
||||
def self.getBochsConnections()
|
||||
ports = Hash.new
|
||||
@@iface_ports.each { |port|
|
||||
ports[port.obj_name] = port.bochsConnType
|
||||
}
|
||||
return ports
|
||||
end
|
||||
|
||||
def self.getMemorySizeMB()
|
||||
DirectoryMemory.memorySizeMB
|
||||
end
|
||||
|
||||
# override the default accessors (generated by default_param) for random_seed
|
||||
def self.random_seed=(seed)
|
||||
assert (val.is_a?(Integer) or val == "rand"), "RubySystem.random_seed takes either an integer value or the string \"rand\""
|
||||
@@params[:random_seed] = seed
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.argv()
|
||||
str = ""
|
||||
@@params.each { |key, val|
|
||||
str += key.id2name + " "
|
||||
str += val.to_s + " "
|
||||
}
|
||||
return str
|
||||
end
|
||||
|
||||
def self.writeConfig()
|
||||
@@network.printTopology
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#require "defaults.rb"
|
||||
|
||||
|
||||
|
||||
class CacheController < NetPort
|
||||
@@total_cache_controllers = 0
|
||||
attr :caches
|
||||
attr :sequencer
|
||||
def initialize(obj_name, mach_type, caches, sequencer)
|
||||
super(obj_name, mach_type)
|
||||
@caches = caches
|
||||
@caches.each { |cache|
|
||||
cache.controller = self
|
||||
}
|
||||
|
||||
@sequencer = sequencer
|
||||
@sequencer.controller = self
|
||||
|
||||
@version = @@total_cache_controllers
|
||||
@@total_cache_controllers += 1
|
||||
@sequencer.version = @version
|
||||
buffer_size()
|
||||
end
|
||||
|
||||
def argv()
|
||||
vec = "version "+@version.to_s
|
||||
@caches.each { |cache|
|
||||
vec += " cache " + cache.obj_name
|
||||
}
|
||||
vec += " sequencer "+@sequencer.obj_name
|
||||
vec += " transitions_per_cycle "+@params[:transitions_per_cycle].to_s
|
||||
vec += " buffer_size "+@params[:buffer_size].to_s
|
||||
vec += " number_of_TBEs "+@params[:number_of_TBEs].to_s
|
||||
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"generated:"+@mach_type
|
||||
end
|
||||
end
|
||||
|
||||
class DirectoryController < NetPort
|
||||
@@total_directory_controllers = 0
|
||||
attr :directory
|
||||
attr :memory_control
|
||||
|
||||
def initialize(obj_name, mach_type, directory, memory_control)
|
||||
super(obj_name, mach_type)
|
||||
|
||||
@directory = directory
|
||||
directory.controller = self
|
||||
|
||||
@memory_control = memory_control
|
||||
|
||||
@version = @@total_directory_controllers
|
||||
@@total_directory_controllers += 1
|
||||
buffer_size()
|
||||
end
|
||||
|
||||
def argv()
|
||||
"version "+@version.to_s+" directory_name "+@directory.obj_name+" transitions_per_cycle "+@params[:transitions_per_cycle].to_s + " buffer_size "+@params[:buffer_size].to_s + " number_of_TBEs "+@params[:number_of_TBEs].to_s + " memory_controller_name "+@memory_control.obj_name + " recycle_latency "+@params[:recycle_latency].to_s
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"generated:"+@mach_type
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class DMAController < NetPort
|
||||
@@total_dma_controllers = 0
|
||||
attr :dma_sequencer
|
||||
def initialize(obj_name, mach_type, dma_sequencer)
|
||||
super(obj_name, mach_type)
|
||||
@dma_sequencer = dma_sequencer
|
||||
@version = @@total_dma_controllers
|
||||
@@total_dma_controllers += 1
|
||||
dma_sequencer.controller = self
|
||||
buffer_size
|
||||
end
|
||||
|
||||
def argv()
|
||||
"version "+@version.to_s+" dma_sequencer "+@dma_sequencer.obj_name+" transitions_per_cycle "+@params[:transitions_per_cycle].to_s + " buffer_size "+@params[:buffer_size].to_s + " number_of_TBEs "+@params[:number_of_TBEs].to_s
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"generated:"+@mach_type
|
||||
end
|
||||
end
|
||||
|
||||
class Cache < LibRubyObject
|
||||
attr :size_kb, :latency
|
||||
attr_writer :controller
|
||||
def initialize(obj_name, size_kb, latency)
|
||||
super(obj_name)
|
||||
assert size_kb.is_a?(Integer), "Cache size must be an integer"
|
||||
@size_kb = size_kb
|
||||
@latency = latency
|
||||
end
|
||||
|
||||
def args
|
||||
"controller "+@controller.obj_name+" size_kb "+@size_kb.to_s+" latency "+@latency.to_s
|
||||
end
|
||||
end
|
||||
|
||||
class SetAssociativeCache < Cache
|
||||
attr :assoc, :replacement_policy
|
||||
|
||||
# latency can be either an integer, a float, or the string "auto"
|
||||
# when an integer, it represents the number of cycles for a hit
|
||||
# when a float, it represents the cache access time in ns
|
||||
# when set to "auto", libruby will attempt to find a realistic latency by running CACTI
|
||||
def initialize(obj_name, size_kb, latency, assoc, replacement_policy)
|
||||
super(obj_name, size_kb, latency)
|
||||
@assoc = assoc
|
||||
@replacement_policy = replacement_policy
|
||||
end
|
||||
|
||||
def calculateLatency()
|
||||
if @latency == "auto"
|
||||
cacti_args = Array.new()
|
||||
cacti_args << (@size_kb*1024) << RubySystem.block_size_bytes << @assoc
|
||||
cacti_args << 1 << 0 << 0 << 0 << 1
|
||||
cacti_args << RubySystem.tech_nm << RubySystem.block_size_bytes*8
|
||||
cacti_args << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 1
|
||||
cacti_args << 360 << 0 << 0 << 0 << 0 << 1 << 1 << 1 << 1 << 0 << 0
|
||||
cacti_args << 50 << 10 << 10 << 0 << 1 << 1
|
||||
|
||||
cacti_cmd = File.dirname(__FILE__) + "/cacti/cacti " + cacti_args.join(" ")
|
||||
|
||||
IO.popen(cacti_cmd) { |pipe|
|
||||
str1 = pipe.readline
|
||||
str2 = pipe.readline
|
||||
results = str2.split(", ")
|
||||
if results.size != 61
|
||||
print "CACTI ERROR: CACTI produced unexpected output.\n"
|
||||
print "Are you using the version shipped with libruby?\n"
|
||||
raise Exception
|
||||
end
|
||||
latency_ns = results[5].to_f
|
||||
if (latency_ns == "1e+39")
|
||||
print "CACTI ERROR: CACTI was unable to realistically model the cache ",@obj_name,"\n"
|
||||
print "Either change the cache parameters or manually set the latency values\n"
|
||||
raise Exception
|
||||
end
|
||||
clk_period_ns = 1e9 * (1.0 / (RubySystem.freq_mhz * 1e6))
|
||||
latency_cycles = (latency_ns / clk_period_ns).ceil
|
||||
@latency = latency_cycles
|
||||
}
|
||||
elsif @latency.is_a?(Float)
|
||||
clk_period_ns = 1e9 * (1.0 / (RubySystem.freq_mhz * 1e6))
|
||||
latency_cycles = (@latency / clk_period_ns).ceil
|
||||
@latency = latency_cycles
|
||||
elsif ! @latency.is_a?(Integer)
|
||||
raise Exception
|
||||
end
|
||||
end
|
||||
|
||||
def argv()
|
||||
args+" assoc "+@assoc.to_s+" replacement_policy "+@replacement_policy
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"SetAssociativeCache"
|
||||
end
|
||||
end
|
||||
|
||||
class DirectoryMemory < LibRubyObject
|
||||
attr :size_mb
|
||||
attr_writer :controller
|
||||
@@total_size_mb = 0
|
||||
|
||||
def initialize(obj_name, size_mb)
|
||||
super(obj_name)
|
||||
@size_mb = size_mb
|
||||
@@total_size_mb += size_mb
|
||||
end
|
||||
|
||||
def argv()
|
||||
"version "+@controller.version.to_s+" size_mb "+@size_mb.to_s+" controller "+@controller.obj_name
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"DirectoryMemory"
|
||||
end
|
||||
|
||||
def self.memorySizeMB()
|
||||
@@total_size_mb
|
||||
end
|
||||
end
|
||||
|
||||
#added by SS
|
||||
class MemoryControl < LibRubyObject
|
||||
attr :name
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
@name = obj_name
|
||||
end
|
||||
|
||||
def argv()
|
||||
vec = super()
|
||||
vec += " mem_bus_cycle_multiplier "+mem_bus_cycle_multiplier.to_s
|
||||
vec += " banks_per_rank "+banks_per_rank.to_s
|
||||
vec += " ranks_per_dimm "+ranks_per_dimm.to_s
|
||||
vec += " dimms_per_channel "+dimms_per_channel.to_s
|
||||
vec += " bank_bit_0 "+bank_bit_0.to_s
|
||||
vec += " rank_bit_0 "+rank_bit_0.to_s
|
||||
vec += " dimm_bit_0 "+dimm_bit_0.to_s
|
||||
vec += " bank_queue_size "+bank_queue_size.to_s
|
||||
vec += " bank_busy_time "+bank_busy_time.to_s
|
||||
vec += " rank_rank_delay "+rank_rank_delay.to_s
|
||||
vec += " read_write_delay "+read_write_delay.to_s
|
||||
vec += " basic_bus_busy_time "+basic_bus_busy_time.to_s
|
||||
vec += " mem_ctl_latency "+mem_ctl_latency.to_s
|
||||
vec += " refresh_period "+refresh_period.to_s
|
||||
vec += " tFaw "+tFaw.to_s
|
||||
vec += " mem_random_arbitrate "+mem_random_arbitrate.to_s
|
||||
vec += " mem_fixed_delay "+mem_fixed_delay.to_s
|
||||
vec += " memory_controller_name "+@name
|
||||
|
||||
end
|
||||
|
||||
|
||||
def cppClassName()
|
||||
"MemoryControl"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Sequencer < IfacePort
|
||||
|
||||
def cppClassName()
|
||||
"Sequencer"
|
||||
end
|
||||
|
||||
param :controller, NetPort # must be set after initialization
|
||||
param :icache, Cache
|
||||
param :dcache, Cache
|
||||
param :version, Integer
|
||||
|
||||
def initialize(obj_name, icache, dcache)
|
||||
super(obj_name)
|
||||
self.icache=icache
|
||||
self.dcache=dcache
|
||||
end
|
||||
|
||||
def bochsConnType()
|
||||
return "cpu"+version.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
class DMASequencer < IfacePort
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
@params = {
|
||||
:controller => nil,
|
||||
:version => nil
|
||||
}
|
||||
end
|
||||
|
||||
def controller=(controller)
|
||||
@params[:controller] = controller.obj_name
|
||||
@params[:version] = controller.version
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"DMASequencer"
|
||||
end
|
||||
|
||||
def bochsConnType()
|
||||
return "dma"+@params[:version].to_s
|
||||
end
|
||||
end
|
||||
|
||||
class IntNode
|
||||
@@num = 0
|
||||
def initialize()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class Network < LibRubyObject
|
||||
end
|
||||
|
||||
class Topology < LibRubyObject
|
||||
attr :net_ports
|
||||
param :network, Network
|
||||
def initialize(name, net_ports)
|
||||
super(name)
|
||||
@net_ports = net_ports
|
||||
end
|
||||
|
||||
def cppClassName
|
||||
"Topology"
|
||||
end
|
||||
end
|
||||
|
||||
class Network < LibRubyObject
|
||||
param :topology, Topology
|
||||
def initialize(name, topo)
|
||||
super(name)
|
||||
@params[:topology] = topo
|
||||
topo.network= self
|
||||
end
|
||||
|
||||
def argv()
|
||||
vec = super()
|
||||
|
||||
vec += " endpoint_bandwidth "+endpoint_bandwidth.to_s
|
||||
vec += " adaptive_routing "+adaptive_routing.to_s
|
||||
vec += " number_of_virtual_networks "+number_of_virtual_networks.to_s
|
||||
vec += " fan_out_degree "+fan_out_degree.to_s
|
||||
|
||||
vec += " buffer_size "+buffer_size.to_s
|
||||
vec += " link_latency "+adaptive_routing.to_s
|
||||
vec += " on_chip_latency "+on_chip_latency.to_s
|
||||
|
||||
end
|
||||
|
||||
def printTopology()
|
||||
topology.printFile
|
||||
end
|
||||
def cppClassName()
|
||||
"SimpleNetwork"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class PtToPtTopology < Topology
|
||||
|
||||
param :connections,String
|
||||
|
||||
def initialize(name, net_ports)
|
||||
super(name, net_ports)
|
||||
@params[:connections] = ""
|
||||
@net_ports.each_index { |idx|
|
||||
@params[:connections] << ("ext_node:"+@net_ports[idx].port_name+":"+@net_ports[idx].port_num.to_s)
|
||||
@params[:connections] << ("%int_node:"+ idx.to_s+ "%link_latency:"+ link_latency.to_s)
|
||||
@params[:connections] << ("%bw_multiplier:"+external_bw.to_s+"#")
|
||||
}
|
||||
@net_ports.each_index { |outer_idx|
|
||||
@net_ports.each_index { |inner_idx|
|
||||
if (outer_idx != inner_idx)
|
||||
@params[:connections] << ("int_node:"+ outer_idx.to_s+ "%int_node:"+ inner_idx.to_s)
|
||||
@params[:connections] << ("%link_latency:"+link_latency.to_s+"%bw_multiplier:"+internal_bw.to_s)
|
||||
@params[:connections] << ("%link_weight:"+1.to_s+"#")
|
||||
end
|
||||
}
|
||||
}
|
||||
# call the accessors of the parent class to initialize them
|
||||
# need to find a better method!!
|
||||
print_config
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class CrossbarTopology < Topology
|
||||
param :connections,String
|
||||
|
||||
def initialize(name, net_ports)
|
||||
super(name, net_ports)
|
||||
@params[:connections] = ""
|
||||
crossbar_node = @net_ports.size
|
||||
@net_ports.each_index { |idx|
|
||||
@params[:connections] << ("ext_node:"+@net_ports[idx].port_name+":"+@net_ports[idx].port_num.to_s)
|
||||
@params[:connections] << ("%int_node:"+ idx.to_s+ "%link_latency:"+ link_latency.to_s)
|
||||
@params[:connections] << ("%bw_multiplier:"+external_bw.to_s+"#")
|
||||
}
|
||||
@net_ports.each_index { |idx|
|
||||
@params[:connections] << ("int_node:"+idx.to_s+"%int_node:"+crossbar_node.to_s)
|
||||
@params[:connections] << ("%link_latency:"+link_latency.to_s+"%bw_multiplier:"+internal_bw.to_s)
|
||||
@params[:connections] << ("%link_weight:"+1.to_s+"#")
|
||||
}
|
||||
print_config
|
||||
end
|
||||
end
|
||||
|
||||
#added by SS
|
||||
class Tracer < LibRubyObject
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"Tracer"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Profiler < LibRubyObject
|
||||
def initialize(obj_name)
|
||||
super(obj_name)
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"Profiler"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MI_example_CacheController < CacheController
|
||||
def initialize(obj_name, mach_type, caches, sequencer)
|
||||
super(obj_name, mach_type, caches, sequencer)
|
||||
end
|
||||
def argv()
|
||||
vec = super()
|
||||
vec += " issue_latency "+issue_latency.to_s
|
||||
vec += " cache_response_latency "+cache_response_latency.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class MI_example_DirectoryController < DirectoryController
|
||||
def initialize(obj_name, mach_type, directory, memory_control)
|
||||
super(obj_name, mach_type, directory, memory_control)
|
||||
end
|
||||
def argv()
|
||||
vec = super()
|
||||
vec += " to_mem_ctrl_latency "+to_mem_ctrl_latency.to_s
|
||||
vec += " directory_latency "+directory_latency.to_s
|
||||
vec += " memory_latency "+memory_latency.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#added by SS
|
||||
class GarnetNetwork < Network
|
||||
def initialize(name, topo)
|
||||
super(name, topo)
|
||||
end
|
||||
def argv()
|
||||
vec = super()
|
||||
vec += " flit_size "+flit_size.to_s
|
||||
vec += " number_of_pipe_stages "+number_of_pipe_stages.to_s
|
||||
vec += " vcs_per_class "+vcs_per_class.to_s
|
||||
vec += " buffer_size "+buffer_size.to_s
|
||||
vec += " using_network_testing "+using_network_testing.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class GarnetFixedPipeline < GarnetNetwork
|
||||
def initialize(name, net_ports)
|
||||
super(name, net_ports)
|
||||
end
|
||||
|
||||
def argv()
|
||||
super()
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"GarnetNetwork_d"
|
||||
end
|
||||
end
|
||||
|
||||
class GarnetFlexiblePipeline < GarnetNetwork
|
||||
def initialize(name, net_ports)
|
||||
super(name, net_ports)
|
||||
end
|
||||
|
||||
def argv()
|
||||
super()
|
||||
end
|
||||
|
||||
def cppClassName()
|
||||
"GarnetNetwork"
|
||||
end
|
||||
end
|
||||
|
||||
require "defaults.rb"
|
|
@ -1,74 +1,23 @@
|
|||
//
|
||||
// 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). For information about
|
||||
// ATMTP, see the GEMS website: http://www.cs.wisc.edu/gems/.
|
||||
//
|
||||
// Please send email to atmtp-interest@sun.com with feedback, questions, or
|
||||
// to request future announcements about ATMTP.
|
||||
//
|
||||
// ----------------------------------------------------------------------
|
||||
//
|
||||
// File modification date: 2008-02-23
|
||||
//
|
||||
// ----------------------------------------------------------------------
|
||||
//
|
||||
// ATMTP is distributed as part of the GEMS software toolset and is
|
||||
// available for use and modification under the terms of version 2 of the
|
||||
// GNU General Public License. The GNU General Public License is contained
|
||||
// in the file $GEMS/LICENSE.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// ----------------------------------------------------------------------
|
||||
//
|
||||
|
||||
// see rubyconfig.defaults for some explanations
|
||||
|
||||
PARAM( g_RANDOM_SEED );
|
||||
|
||||
// Maximum number of cycles a request is can be outstanding before the
|
||||
// Sequencer of StoreBuffer declares we're in deadlock/livelock
|
||||
PARAM( g_DEADLOCK_THRESHOLD );
|
||||
PARAM_BOOL( RANDOMIZATION );
|
||||
PARAM_BOOL( g_SYNTHETIC_DRIVER );
|
||||
PARAM_BOOL( g_DETERMINISTIC_DRIVER );
|
||||
|
||||
// FOR MOESI_CMP_token
|
||||
PARAM_BOOL( g_FILTERING_ENABLED );
|
||||
PARAM_BOOL( g_DISTRIBUTED_PERSISTENT_ENABLED );
|
||||
PARAM_BOOL( g_DYNAMIC_TIMEOUT_ENABLED );
|
||||
PARAM( g_RETRY_THRESHOLD );
|
||||
PARAM( g_FIXED_TIMEOUT_LATENCY );
|
||||
//PARAM_BOOL( FilteringEnabled, false, false );
|
||||
//PARAM_BOOL( DistributedPersistentEnabled, true, false );
|
||||
//PARAM_BOOL( DynamicTimeoutEnabled, true, false );
|
||||
//PARAM( RetryThreshold, 1, false );
|
||||
//PARAM( FixedTimeoutLatency, 300, false );
|
||||
|
||||
PARAM( g_trace_warmup_length );
|
||||
PARAM_DOUBLE( g_bash_bandwidth_adaptive_threshold );
|
||||
//PARAM( TraceWarmupLength, 1000000, false );
|
||||
|
||||
PARAM( g_tester_length );
|
||||
PARAM( g_synthetic_locks );
|
||||
PARAM( g_deterministic_addrs );
|
||||
// Specified Generator: See SpecifiedGeneratorType in external.sm for valid values
|
||||
PARAM_STRING( g_SpecifiedGenerator );
|
||||
PARAM( g_callback_counter );
|
||||
PARAM( g_NUM_COMPLETIONS_BEFORE_PASS );
|
||||
//PARAM( callback_counter, 0, false );
|
||||
//PARAM( NUM_COMPLETIONS_BEFORE_PASS, 0, false );
|
||||
|
||||
PARAM( g_NUM_SMT_THREADS );
|
||||
|
||||
PARAM( g_think_time );
|
||||
PARAM( g_hold_time );
|
||||
PARAM( g_wait_time );
|
||||
//PARAM( tester_length, 0, false );
|
||||
//PARAM( synthetic_locks, 2048, false );
|
||||
//PARAM( think_time, 5, false );
|
||||
//PARAM( wait_time, 5, false );
|
||||
//PARAM( hold_time, 5, false );
|
||||
//PARAM( deterministic_addrs, 1, false );
|
||||
//PARAM_STRING( SpecifiedGenerator, "DetermInvGenerator", false );
|
||||
|
||||
// For debugging purposes, one can enable a trace of all the protocol
|
||||
// state machine changes. Unfortunately, the code to generate the
|
||||
|
@ -80,243 +29,208 @@ PARAM( g_wait_time );
|
|||
// "g_debug_ptr->setDebugTime(1)" to beging the following to set the
|
||||
// debug begin time
|
||||
//
|
||||
// this use to be ruby/common/Global.h
|
||||
// this use to be ruby/common/Global.hh
|
||||
|
||||
PARAM_BOOL( PROTOCOL_DEBUG_TRACE );
|
||||
// a string for filtering debugging output (for all g_debug vars see Debug.h)
|
||||
PARAM_STRING( DEBUG_FILTER_STRING );
|
||||
//PARAM_BOOL( ProtocolDebugTrace, true, false );
|
||||
// a string for filtering debugging output (for all g_debug vars see Debug.hh)
|
||||
//PARAM_STRING( DEBUG_FILTER_STRING, "", false );
|
||||
// filters debugging messages based on priority (low, med, high)
|
||||
PARAM_STRING( DEBUG_VERBOSITY_STRING );
|
||||
//PARAM_STRING( DEBUG_VERBOSITY_STRING, "", false );
|
||||
// filters debugging messages based on a ruby time
|
||||
PARAM_ULONG( DEBUG_START_TIME );
|
||||
//PARAM_ULONG( DEBUG_START_TIME, 0, false );
|
||||
// sends debugging messages to a output filename
|
||||
PARAM_STRING( DEBUG_OUTPUT_FILENAME );
|
||||
//PARAM_STRING( DEBUG_OUTPUT_FILENAME, "", false );
|
||||
|
||||
// defines relative (integer) clock multipliers between ruby, opal, and simics
|
||||
PARAM( SIMICS_RUBY_MULTIPLIER );
|
||||
PARAM( OPAL_RUBY_MULTIPLIER );
|
||||
|
||||
PARAM_BOOL( TRANSACTION_TRACE_ENABLED );
|
||||
PARAM_BOOL( USER_MODE_DATA_ONLY );
|
||||
PARAM_BOOL( PROFILE_HOT_LINES );
|
||||
//PARAM_BOOL( ProfileHotLines, false, false );
|
||||
|
||||
// PROFILE_ALL_INSTRUCTIONS is used if you want Ruby to profile all instructions executed
|
||||
// The following need to be true for this to work correctly:
|
||||
// 1. Disable istc and dstc for this simulation run
|
||||
// 2. Add the following line to the object "sim" in the checkpoint you run from:
|
||||
// instruction_profile_line_size: 4
|
||||
// instruction_profile_line_size: 4
|
||||
// This is used to have simics report back all instruction requests
|
||||
|
||||
// For more details on how to find out how to interpret the output physical instruction
|
||||
// address, please read the document in the simics-howto directory
|
||||
PARAM_BOOL( PROFILE_ALL_INSTRUCTIONS );
|
||||
//PARAM_BOOL( ProfileAllInstructions, false, false );
|
||||
|
||||
// Set the following variable to true if you want a complete trace of
|
||||
// PCs (physical address of program counters, with executing processor IDs)
|
||||
// to be printed to stdout. Make sure to direct the simics output to a file.
|
||||
// Otherwise, the run will take a really long time!
|
||||
// A long run may write a file that can exceed the OS limit on file length
|
||||
PARAM_BOOL( PRINT_INSTRUCTION_TRACE );
|
||||
PARAM( g_DEBUG_CYCLE );
|
||||
|
||||
// Don't allow any datablocks to enter the STC
|
||||
PARAM_BOOL( BLOCK_STC );
|
||||
//PARAM_BOOL( PRINT_INSTRUCTION_TRACE, false, false );
|
||||
//PARAM( DEBUG_CYCLE, 0, false );
|
||||
|
||||
// Make the entire memory system perfect
|
||||
PARAM_BOOL( PERFECT_MEMORY_SYSTEM );
|
||||
PARAM( PERFECT_MEMORY_SYSTEM_LATENCY );
|
||||
|
||||
PARAM_BOOL( DATA_BLOCK ); // Define NO_DATA_BLOCK to make the DataBlock take zero space
|
||||
|
||||
PARAM_BOOL( REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH );
|
||||
//PARAM_BOOL( PERFECT_MEMORY_SYSTEM, false, false );
|
||||
//PARAM( PERFECT_MEMORY_SYSTEM_LATENCY, 0, false );
|
||||
|
||||
// *********************************************
|
||||
// CACHE & MEMORY PARAMETERS
|
||||
// SYSTEM PARAMETERS
|
||||
// *********************************************
|
||||
|
||||
//PARAM( NumberOfChips, 1, false );
|
||||
//PARAM( NumberOfCores, 2, false );
|
||||
//PARAM_ARRAY( NumberOfCoresPerChip, int, m_NumberOfChips, 2, false);
|
||||
|
||||
PARAM( L1_CACHE_ASSOC );
|
||||
PARAM( L1_CACHE_NUM_SETS_BITS );
|
||||
PARAM( L2_CACHE_ASSOC );
|
||||
PARAM( L2_CACHE_NUM_SETS_BITS );
|
||||
// *********************************************
|
||||
// CACHE PARAMETERS
|
||||
// *********************************************
|
||||
|
||||
PARAM_ULONG( g_MEMORY_SIZE_BYTES );
|
||||
PARAM( g_DATA_BLOCK_BYTES );
|
||||
// The following page size parameter is used by the stride prefetcher
|
||||
PARAM( g_PAGE_SIZE_BYTES );
|
||||
PARAM_STRING( g_REPLACEMENT_POLICY );
|
||||
//PARAM( NumberOfCaches, m_NumberOfCores, false );
|
||||
//PARAM( NumberOfCacheLevels, 1, false );
|
||||
/* this returns the number of discrete CacheMemories per level (i.e. a split L1 counts for 2) */
|
||||
//PARAM_ARRAY( NumberOfCachesPerLevel, int, m_NumberOfCacheLevels, m_NumberOfCores, false ); // this is the number of discrete caches if the level is private
|
||||
// or the number of banks if the level is shared
|
||||
//PARAM( CacheIDFromParams, 1, true ); // returns a unique CacheID from the parameters (level, num, split_type)
|
||||
//PARAM_ARRAY( CacheLatency, int, m_NumberOfCaches, 1, false ); // returns the latency for cache, indexed by CacheID
|
||||
//PARAM_ARRAY( CacheSplitType, string, m_NumberOfCaches, "unified", false ); // returns "data", "instruction", or "unified", indexed by CacheID
|
||||
//PARAM_ARRAY( CacheType, string, m_NumberOfCaches, "SetAssociative", false ); // returns the type of a cache, indexed by CacheID
|
||||
//PARAM_ARRAY( CacheAssoc, int, m_NumberOfCaches, 4, false ); // returns the cache associativity, indexed by CacheID
|
||||
//PARAM_ARRAY( NumberOfCacheSets, int, m_NumberOfCaches, 256, false ); // returns the number of cache sets, indexed by CacheID
|
||||
//PARAM_ARRAY( NumberOfCacheSetBits, int, m_NumberOfCaches, log_int(256), false ); // returns the number of cache set bits, indexed by CacheID
|
||||
//PARAM_ARRAY( CacheReplacementPolicy, string, m_NumberOfCaches, "PSEUDO_LRU", false ); // other option is "LRU"
|
||||
|
||||
PARAM( g_NUM_PROCESSORS );
|
||||
PARAM( g_NUM_L2_BANKS );
|
||||
PARAM( g_NUM_MEMORIES );
|
||||
PARAM( g_PROCS_PER_CHIP );
|
||||
//PARAM( DataBlockBytes, 64, false );
|
||||
//PARAM( DataBlockBits, log_int(m_DataBlockBytes), false);
|
||||
|
||||
// ********************************************
|
||||
// MEMORY PARAMETERS
|
||||
// ********************************************
|
||||
|
||||
//PARAM_ARRAY( NumberOfControllersPerType, int, m_NumberOfCacheLevels+2, m_NumberOfCores, false);
|
||||
//PARAM_ARRAY2D( NumberOfControllersPerTypePerChip, int, m_NumberOfCacheLevels+2, m_NumberOfChips, m_NumberOfCores, false);
|
||||
|
||||
// ********************************************
|
||||
// DMA CONTROLLER PARAMETERS
|
||||
// ********************************************
|
||||
|
||||
//PARAM( NumberOfDMA, 1, false );
|
||||
//PARAM_ARRAY( NumberOfDMAPerChip, int, m_NumberOfChips, 1, false);
|
||||
//PARAM_ARRAY( ChipNumFromDMAVersion, int, m_NumberOfDMA, 0, false );
|
||||
|
||||
//PARAM_ULONG( MemorySizeBytes, 4294967296, false );
|
||||
//PARAM_ULONG( MemorySizeBits, 32, false);
|
||||
|
||||
//PARAM( NUM_PROCESSORS, 0, false );
|
||||
//PARAM( NUM_L2_BANKS, 0, false );
|
||||
//PARAM( NUM_MEMORIES, 0, false );
|
||||
//PARAM( ProcsPerChip, 1, false );
|
||||
|
||||
// The following group of parameters are calculated. They must
|
||||
// _always_ be left at zero.
|
||||
PARAM( g_NUM_CHIPS );
|
||||
PARAM( g_NUM_CHIP_BITS );
|
||||
PARAM( g_MEMORY_SIZE_BITS );
|
||||
PARAM( g_DATA_BLOCK_BITS );
|
||||
PARAM( g_PAGE_SIZE_BITS );
|
||||
PARAM( g_NUM_PROCESSORS_BITS );
|
||||
PARAM( g_PROCS_PER_CHIP_BITS );
|
||||
PARAM( g_NUM_L2_BANKS_BITS );
|
||||
PARAM( g_NUM_L2_BANKS_PER_CHIP_BITS );
|
||||
PARAM( g_NUM_L2_BANKS_PER_CHIP );
|
||||
PARAM( g_NUM_MEMORIES_BITS );
|
||||
PARAM( g_NUM_MEMORIES_PER_CHIP );
|
||||
PARAM( g_MEMORY_MODULE_BITS );
|
||||
PARAM_ULONG( g_MEMORY_MODULE_BLOCKS );
|
||||
|
||||
// determines the mapping between L2 banks and sets within L2 banks
|
||||
PARAM_BOOL( MAP_L2BANKS_TO_LOWEST_BITS );
|
||||
//PARAM( NUM_CHIPS, 0, false );
|
||||
//PARAM( NUM_CHIP_BITS, 0, false );
|
||||
//PARAM( MEMORY_SIZE_BITS, 0, false );
|
||||
//PARAM( DATA_BLOCK_BITS, 0, false );
|
||||
//PARAM( PAGE_SIZE_BITS, 0, false );
|
||||
//PARAM( NUM_PROCESSORS_BITS, 0, false );
|
||||
//PARAM( PROCS_PER_CHIP_BITS, 0, false );
|
||||
//PARAM( NUM_L2_BANKS_BITS, 0, false );
|
||||
//PARAM( NUM_L2_BANKS_PER_CHIP_BITS, 0, false );
|
||||
//PARAM( NUM_L2_BANKS_PER_CHIP, 0, false );
|
||||
//PARAM( NUM_MEMORIES_BITS, 0, false );
|
||||
//PARAM( NUM_MEMORIES_PER_CHIP, 0, false );
|
||||
//PARAM( MEMORY_MODULE_BITS, 0, false );
|
||||
//PARAM_ULONG( MEMORY_MODULE_BLOCKS, 0, false );
|
||||
|
||||
// TIMING PARAMETERS
|
||||
PARAM( DIRECTORY_CACHE_LATENCY );
|
||||
//PARAM( DIRECTORY_CACHE_LATENCY, 6, false );
|
||||
|
||||
PARAM( NULL_LATENCY );
|
||||
PARAM( ISSUE_LATENCY );
|
||||
PARAM( CACHE_RESPONSE_LATENCY );
|
||||
PARAM( L2_RESPONSE_LATENCY );
|
||||
PARAM( L2_TAG_LATENCY );
|
||||
PARAM( L1_RESPONSE_LATENCY );
|
||||
PARAM( MEMORY_RESPONSE_LATENCY_MINUS_2 );
|
||||
PARAM( DIRECTORY_LATENCY );
|
||||
PARAM( NETWORK_LINK_LATENCY );
|
||||
PARAM( COPY_HEAD_LATENCY );
|
||||
PARAM( ON_CHIP_LINK_LATENCY );
|
||||
PARAM( RECYCLE_LATENCY );
|
||||
PARAM( L2_RECYCLE_LATENCY );
|
||||
PARAM( TIMER_LATENCY );
|
||||
PARAM( TBE_RESPONSE_LATENCY );
|
||||
PARAM_BOOL( PERIODIC_TIMER_WAKEUPS );
|
||||
//PARAM( NULL_LATENCY, 1, false );
|
||||
//PARAM( ISSUE_LATENCY, 2, false );
|
||||
//PARAM( CACHE_RESPONSE_LATENCY, 12, false );
|
||||
//PARAM( L2_RESPONSE_LATENCY, 6, false );
|
||||
//PARAM( L2_TAG_LATENCY, 6, false );
|
||||
//PARAM( L1_RESPONSE_LATENCY, 3, false );
|
||||
|
||||
// constants used by TM protocols
|
||||
PARAM_BOOL( PROFILE_EXCEPTIONS );
|
||||
PARAM_BOOL( PROFILE_XACT );
|
||||
PARAM_BOOL( PROFILE_NONXACT );
|
||||
PARAM_BOOL( XACT_DEBUG );
|
||||
PARAM ( XACT_DEBUG_LEVEL );
|
||||
PARAM_BOOL( XACT_MEMORY );
|
||||
PARAM_BOOL( XACT_ENABLE_TOURMALINE );
|
||||
PARAM( XACT_NUM_CURRENT );
|
||||
PARAM( XACT_LAST_UPDATE );
|
||||
PARAM_BOOL( XACT_ISOLATION_CHECK );
|
||||
PARAM_BOOL( PERFECT_FILTER );
|
||||
PARAM_STRING( READ_WRITE_FILTER );
|
||||
PARAM_BOOL( PERFECT_VIRTUAL_FILTER );
|
||||
PARAM_STRING( VIRTUAL_READ_WRITE_FILTER );
|
||||
PARAM_BOOL( PERFECT_SUMMARY_FILTER );
|
||||
PARAM_STRING( SUMMARY_READ_WRITE_FILTER );
|
||||
PARAM_BOOL( XACT_EAGER_CD );
|
||||
PARAM_BOOL( XACT_LAZY_VM );
|
||||
PARAM_STRING( XACT_CONFLICT_RES );
|
||||
PARAM_BOOL( XACT_VISUALIZER );
|
||||
PARAM( XACT_COMMIT_TOKEN_LATENCY ) ;
|
||||
PARAM_BOOL( XACT_NO_BACKOFF );
|
||||
PARAM ( XACT_LOG_BUFFER_SIZE );
|
||||
PARAM ( XACT_STORE_PREDICTOR_HISTORY);
|
||||
PARAM ( XACT_STORE_PREDICTOR_ENTRIES);
|
||||
PARAM ( XACT_STORE_PREDICTOR_THRESHOLD);
|
||||
PARAM ( XACT_FIRST_ACCESS_COST );
|
||||
PARAM ( XACT_FIRST_PAGE_ACCESS_COST );
|
||||
PARAM_BOOL( ENABLE_MAGIC_WAITING );
|
||||
PARAM_BOOL( ENABLE_WATCHPOINT );
|
||||
PARAM_BOOL( XACT_ENABLE_VIRTUALIZATION_LOGTM_SE );
|
||||
//PARAM( MEMORY_RESPONSE_LATENCY_MINUS_2, 158, false );
|
||||
//PARAM( DirectoryLatency, 6, false );
|
||||
|
||||
// ATMTP
|
||||
PARAM_BOOL( ATMTP_ENABLED );
|
||||
PARAM_BOOL( ATMTP_ABORT_ON_NON_XACT_INST );
|
||||
PARAM_BOOL( ATMTP_ALLOW_SAVE_RESTORE_IN_XACT );
|
||||
PARAM( ATMTP_XACT_MAX_STORES );
|
||||
PARAM( ATMTP_DEBUG_LEVEL );
|
||||
//PARAM( NetworkLinkLatency, 1, false );
|
||||
//PARAM( COPY_HEAD_LATENCY, 4, false );
|
||||
//PARAM( OnChipLinkLatency, 1, false );
|
||||
//PARAM( RecycleLatency, 10, false );
|
||||
//PARAM( L2_RECYCLE_LATENCY, 5, false );
|
||||
//PARAM( TIMER_LATENCY, 10000, false );
|
||||
//PARAM( TBE_RESPONSE_LATENCY, 1, false );
|
||||
//PARAM_BOOL( PERIODIC_TIMER_WAKEUPS, true, false );
|
||||
|
||||
// constants used by CMP protocols
|
||||
PARAM( L1_REQUEST_LATENCY );
|
||||
PARAM( L2_REQUEST_LATENCY );
|
||||
PARAM_BOOL( SINGLE_ACCESS_L2_BANKS ); // hack to simulate multi-cycle L2 bank accesses
|
||||
//PARAM( L1_REQUEST_LATENCY, 2, false );
|
||||
//PARAM( L2_REQUEST_LATENCY, 4, false );
|
||||
//PARAM_BOOL( SINGLE_ACCESS_L2_BANKS, true, false ); // hack to simulate multi-cycle L2 bank accesses
|
||||
|
||||
// Ruby cycles between when a sequencer issues a miss it arrives at
|
||||
// the L1 cache controller
|
||||
PARAM( SEQUENCER_TO_CONTROLLER_LATENCY );
|
||||
//PARAM( SequencerToControllerLatency, 4, false );
|
||||
|
||||
// Number of transitions each controller state machines can complete per cycle
|
||||
PARAM( L1CACHE_TRANSITIONS_PER_RUBY_CYCLE );
|
||||
PARAM( L2CACHE_TRANSITIONS_PER_RUBY_CYCLE );
|
||||
PARAM( DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE );
|
||||
|
||||
// Maximum number of requests (including prefetches) outstanding from
|
||||
// the sequencer (Note: this also include items buffered in the store
|
||||
// buffer)
|
||||
PARAM( g_SEQUENCER_OUTSTANDING_REQUESTS );
|
||||
//PARAM( L1CacheTransitionsPerCycle, 32, false );
|
||||
//PARAM( L2CACHE_TRANSITIONS_PER_RUBY_CYCLE, 32, false );
|
||||
//PARAM( DirectoryTransitionsPerCycle, 32, false );
|
||||
//PARAM( DMATransitionsPerCycle, 1, false );
|
||||
|
||||
// Number of TBEs available for demand misses, prefetches, and replacements
|
||||
PARAM( NUMBER_OF_TBES );
|
||||
PARAM( NUMBER_OF_L1_TBES );
|
||||
PARAM( NUMBER_OF_L2_TBES );
|
||||
//PARAM( NumberOfTBEs, 128, false );
|
||||
//PARAM( NumberOfL1TBEs, 32, false );
|
||||
//PARAM( NumberOfL2TBEs, 32, false );
|
||||
|
||||
// NOTE: Finite buffering allows us to simulate a wormhole routed network
|
||||
// with idealized flow control. All message buffers within the network (i.e.
|
||||
// the switch's input and output buffers) are set to the size specified below
|
||||
// by the PROTOCOL_BUFFER_SIZE
|
||||
PARAM_BOOL( FINITE_BUFFERING );
|
||||
PARAM( FINITE_BUFFER_SIZE ); // Zero is unbounded buffers
|
||||
//PARAM_BOOL( FiniteBuffering, false, false );
|
||||
//PARAM( FiniteBufferSize, 3, false ); // Zero is unbounded buffers
|
||||
// Number of requests buffered between the sequencer and the L1 conroller
|
||||
// This can be more accurately simulated in Opal, therefore it's set to an
|
||||
// infinite number
|
||||
// Only effects the simualtion when FINITE_BUFFERING is enabled
|
||||
PARAM( PROCESSOR_BUFFER_SIZE );
|
||||
//PARAM( ProcessorBufferSize, 10, false );
|
||||
// The PROTOCOL_BUFFER_SIZE limits the size of all other buffers connecting to
|
||||
// Controllers. Controlls the number of request issued by the L2 HW Prefetcher
|
||||
PARAM( PROTOCOL_BUFFER_SIZE );
|
||||
|
||||
// Enable the TSO (Total Store Order) memory model
|
||||
PARAM_BOOL( TSO ); // Note: This also disables the "write" STCs
|
||||
//PARAM( ProtocolBufferSize, 32, false );
|
||||
|
||||
// NETWORK PARAMETERS
|
||||
|
||||
// Network Topology: See TopologyType in external.sm for valid values
|
||||
PARAM_STRING( g_NETWORK_TOPOLOGY );
|
||||
//PARAM_STRING( NetworkTopology, "PT_TO_PT", false );
|
||||
|
||||
// Cache Design specifies file prefix for topology
|
||||
PARAM_STRING( g_CACHE_DESIGN );
|
||||
//PARAM_STRING( CacheDesign, "NUCA", false );
|
||||
|
||||
PARAM( g_endpoint_bandwidth );
|
||||
PARAM_BOOL( g_adaptive_routing );
|
||||
PARAM( NUMBER_OF_VIRTUAL_NETWORKS );
|
||||
PARAM( FAN_OUT_DEGREE );
|
||||
PARAM_BOOL( g_PRINT_TOPOLOGY );
|
||||
|
||||
// transactional memory
|
||||
PARAM( XACT_LENGTH );
|
||||
PARAM( XACT_SIZE );
|
||||
PARAM( ABORT_RETRY_TIME );
|
||||
//PARAM( EndpointBandwidth, 10000, false );
|
||||
//PARAM_BOOL( AdaptiveRouting, true, false );
|
||||
//PARAM( NumberOfVirtualNetworks, 6, false );
|
||||
//PARAM( FanOutDegree, 4, false );
|
||||
//PARAM_BOOL( PrintTopology, true, false );
|
||||
|
||||
// Princeton Network (Garnet)
|
||||
PARAM_BOOL( g_GARNET_NETWORK );
|
||||
PARAM_BOOL( g_DETAIL_NETWORK );
|
||||
PARAM_BOOL( g_NETWORK_TESTING );
|
||||
PARAM( g_FLIT_SIZE );
|
||||
PARAM( g_NUM_PIPE_STAGES );
|
||||
PARAM( g_VCS_PER_CLASS );
|
||||
PARAM( g_BUFFER_SIZE );
|
||||
//PARAM_BOOL( UsingGarnetNetwork, true, false );
|
||||
//PARAM_BOOL( UsingDetailNetwork, false, false );
|
||||
//PARAM_BOOL( UsingNetworkTesting, false, false );
|
||||
//PARAM( FlitSize, 16, false );
|
||||
//PARAM( NumberOfPipeStages, 4, false );
|
||||
//PARAM( VCSPerClass, 4, false );
|
||||
//PARAM( BufferSize, 4, false );
|
||||
|
||||
// MemoryControl:
|
||||
PARAM( MEM_BUS_CYCLE_MULTIPLIER );
|
||||
PARAM( BANKS_PER_RANK );
|
||||
PARAM( RANKS_PER_DIMM );
|
||||
PARAM( DIMMS_PER_CHANNEL );
|
||||
PARAM( BANK_BIT_0 );
|
||||
PARAM( RANK_BIT_0 );
|
||||
PARAM( DIMM_BIT_0 );
|
||||
PARAM( BANK_QUEUE_SIZE );
|
||||
PARAM( BANK_BUSY_TIME );
|
||||
PARAM( RANK_RANK_DELAY );
|
||||
PARAM( READ_WRITE_DELAY );
|
||||
PARAM( BASIC_BUS_BUSY_TIME );
|
||||
PARAM( MEM_CTL_LATENCY );
|
||||
PARAM( REFRESH_PERIOD );
|
||||
PARAM( TFAW );
|
||||
PARAM( MEM_RANDOM_ARBITRATE );
|
||||
PARAM( MEM_FIXED_DELAY );
|
||||
//PARAM( MEM_BUS_CYCLE_MULTIPLIER, 10, false );
|
||||
//PARAM( BANKS_PER_RANK, 8, false );
|
||||
//PARAM( RANKS_PER_DIMM, 2, false );
|
||||
//PARAM( DIMMS_PER_CHANNEL, 2, false );
|
||||
//PARAM( BANK_BIT_0, 8, false );
|
||||
//PARAM( RANK_BIT_0, 11, false );
|
||||
//PARAM( DIMM_BIT_0, 12, false );
|
||||
//PARAM( BANK_QUEUE_SIZE, 12, false );
|
||||
//PARAM( BankBusyTime, 11, false );
|
||||
//PARAM( RANK_RANK_DELAY, 1, false );
|
||||
//PARAM( READ_WRITE_DELAY, 2, false );
|
||||
//PARAM( BASIC_BUS_BUSY_TIME, 2, false );
|
||||
//PARAM( MEM_CTL_LATENCY, 12, false );
|
||||
//PARAM( REFRESH_PERIOD, 1560, false );
|
||||
//PARAM( TFAW, 0, false );
|
||||
//PARAM( MEM_RANDOM_ARBITRATE, 0, false );
|
||||
//PARAM( MEM_FIXED_DELAY, 0, false );
|
||||
|
||||
|
|
181
src/mem/ruby/config/defaults.rb
Normal file
181
src/mem/ruby/config/defaults.rb
Normal file
|
@ -0,0 +1,181 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
|
||||
|
||||
class NetPort < LibRubyObject
|
||||
# number of transitions a SLICC state machine can transition per
|
||||
# cycle
|
||||
default_param :transitions_per_cycle, Integer, 32
|
||||
|
||||
# buffer_size limits the size of all other buffers connecting to
|
||||
# SLICC Controllers. When 0, infinite buffering is used.
|
||||
default_param :buffer_size, Integer, 32
|
||||
|
||||
# added by SS for TBE
|
||||
default_param :number_of_TBEs, Integer, 128
|
||||
|
||||
default_param :recycle_latency, Integer, 10
|
||||
end
|
||||
|
||||
class Sequencer < IfacePort
|
||||
# Maximum number of requests (including prefetches) outstanding from
|
||||
# the sequencer
|
||||
default_param :max_outstanding_requests, Integer, 16
|
||||
|
||||
# Maximum number of cycles a request is can be outstanding before
|
||||
# the Sequencer declares we're in deadlock/livelock
|
||||
default_param :deadlock_threshold, Integer, 500000
|
||||
|
||||
end
|
||||
|
||||
class Debug < LibRubyObject
|
||||
# For debugging purposes, one can enable a trace of all the protocol
|
||||
# state machine changes. Unfortunately, the code to generate the
|
||||
# trace is protocol specific. To enable the code for some of the
|
||||
# standard protocols,
|
||||
# 1. change protocol_trace = true
|
||||
# 2. enable debug in the Ruby Makefile
|
||||
# 3. set start_time = 1
|
||||
default_param :protocol_trace, Boolean, false
|
||||
|
||||
# a string for filtering debugging output (for all g_debug vars see Debug.h)
|
||||
default_param :filter_string, String, "q"
|
||||
|
||||
# filters debugging messages based on priority (low, med, high)
|
||||
default_param :verbosity_string, String, "none"
|
||||
|
||||
# filters debugging messages based on a ruby time
|
||||
default_param :start_time, Integer, 1
|
||||
|
||||
# sends debugging messages to a output filename
|
||||
default_param :output_filename, String, ""
|
||||
end
|
||||
|
||||
class Topology < LibRubyObject
|
||||
# The default link latency between all nodes (internal and external)
|
||||
# in the toplogy
|
||||
default_param :link_latency, Integer, 1
|
||||
|
||||
# the bandwidth from an external network port to it's corresponding
|
||||
# internal switch
|
||||
default_param :external_bw, Integer, 64
|
||||
|
||||
# the bandwitch between internal switches in the network
|
||||
default_param :internal_bw, Integer, 16
|
||||
|
||||
# indicates whether the topology config will be displayed in the
|
||||
# stats file
|
||||
default_param :print_config, Boolean, true
|
||||
end
|
||||
|
||||
class Network < LibRubyObject
|
||||
default_param :endpoint_bandwidth, Integer, 10000
|
||||
default_param :adaptive_routing, Boolean, true
|
||||
default_param :number_of_virtual_networks, Integer, 6
|
||||
default_param :fan_out_degree, Integer, 4
|
||||
|
||||
# default buffer size. Setting to 0 indicates infinite buffering
|
||||
default_param :buffer_size, Integer, 3
|
||||
|
||||
# local memory latency ?? NetworkLinkLatency
|
||||
default_param :link_latency, Integer, 1
|
||||
|
||||
# on chip latency
|
||||
default_param :on_chip_latency, Integer, 1
|
||||
end
|
||||
|
||||
class GarnetNetwork < Network
|
||||
default_param :flit_size, Integer, 16
|
||||
default_param :number_of_pipe_stages, Integer, 4
|
||||
default_param :vcs_per_class, Integer, 4
|
||||
default_param :buffer_size, Integer, 4
|
||||
default_param :using_network_testing, Boolean, false
|
||||
end
|
||||
|
||||
|
||||
|
||||
#added by SS
|
||||
class Tracer < LibRubyObject
|
||||
default_param :warmup_length, Integer, 1000000
|
||||
end
|
||||
|
||||
#added by SS
|
||||
class Profiler < LibRubyObject
|
||||
default_param :hot_lines, Boolean, false
|
||||
default_param :all_instructions, Boolean, false
|
||||
end
|
||||
|
||||
#added by SS
|
||||
class MI_example_CacheController < CacheController
|
||||
default_param :issue_latency, Integer, 2
|
||||
default_param :cache_response_latency, Integer, 12
|
||||
end
|
||||
|
||||
class MI_example_DirectoryController < DirectoryController
|
||||
default_param :to_mem_ctrl_latency, Integer, 1
|
||||
default_param :directory_latency, Integer, 6
|
||||
default_param :memory_latency, Integer, 158
|
||||
end
|
||||
|
||||
|
||||
#added by SS
|
||||
class MemoryControl < LibRubyObject
|
||||
|
||||
default_param :mem_bus_cycle_multiplier, Integer, 10
|
||||
default_param :banks_per_rank, Integer, 8
|
||||
default_param :ranks_per_dimm, Integer, 2
|
||||
default_param :dimms_per_channel, Integer, 2
|
||||
default_param :bank_bit_0, Integer, 8
|
||||
default_param :rank_bit_0, Integer, 11
|
||||
default_param :dimm_bit_0, Integer, 12
|
||||
default_param :bank_queue_size, Integer, 12
|
||||
default_param :bank_busy_time, Integer, 11
|
||||
default_param :rank_rank_delay, Integer, 1
|
||||
default_param :read_write_delay, Integer, 2
|
||||
default_param :basic_bus_busy_time, Integer, 2
|
||||
default_param :mem_ctl_latency, Integer, 12
|
||||
default_param :refresh_period, Integer, 1560
|
||||
default_param :tFaw, Integer, 0
|
||||
default_param :mem_random_arbitrate, Integer, 0
|
||||
default_param :mem_fixed_delay, Integer, 0
|
||||
|
||||
end
|
||||
|
||||
class RubySystem
|
||||
|
||||
# Random seed used by the simulation. If set to "rand", the seed
|
||||
# will be set to the current wall clock at libruby
|
||||
# initialization. Otherwise, set this to an integer.
|
||||
default_param :random_seed, Object, "rand"
|
||||
|
||||
# When set to true, the simulation will insert random delays on
|
||||
# message enqueue times. Note that even if this is set to false,
|
||||
# you can still have a non-deterministic simulation if random seed
|
||||
# is set to "rand". This is because the Ruby swtiches use random
|
||||
# link priority elevation
|
||||
default_param :randomization, Boolean, false
|
||||
|
||||
# tech_nm is the device size used to calculate latency and area
|
||||
# information about system components
|
||||
default_param :tech_nm, Integer, 45
|
||||
|
||||
# default frequency for the system
|
||||
default_param :freq_mhz, Integer, 3000
|
||||
|
||||
# the default cache block size in the system
|
||||
# libruby does not currently support different block sizes
|
||||
# among different caches
|
||||
# Must be a power of two
|
||||
default_param :block_size_bytes, Integer, 64
|
||||
|
||||
# The default debug object. There shouldn't be a reason to ever
|
||||
# change this line. To adjust debug paramters statically, adjust
|
||||
# them in the Debug class above. To adjust these fields
|
||||
# dynamically, access this RubySystem object,
|
||||
# e.g. RubySystem.debug.protocol_trace = true
|
||||
default_param :debug, Debug, Debug.new("dbg0")
|
||||
default_param :tracer, Tracer, Tracer.new("tracer0")
|
||||
|
||||
default_param :profiler, Profiler, Profiler.new("profiler0")
|
||||
end
|
||||
|
14
src/mem/ruby/config/libruby_cfg_test.cc
Normal file
14
src/mem/ruby/config/libruby_cfg_test.cc
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../libruby.hh"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
assert(argc == 2);
|
||||
const char* cfg_file = argv[1];
|
||||
|
||||
libruby_init(cfg_file);
|
||||
libruby_print_config(std::cout);
|
||||
}
|
14
src/mem/ruby/config/print_cfg.rb
Normal file
14
src/mem/ruby/config/print_cfg.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
ruby_cfg_file = nil
|
||||
$stderr.puts $*.inspect
|
||||
for i in 0..$*.size-1 do
|
||||
if $*[i] == "-r" # ruby config file
|
||||
i += 1
|
||||
ruby_cfg_file = $*[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
require ruby_cfg_file
|
||||
|
||||
RubySystem.generateConfig
|
|
@ -43,10 +43,6 @@ g_DEADLOCK_THRESHOLD: 500000
|
|||
// (does not apply when running Opal)
|
||||
SIMICS_RUBY_MULTIPLIER: 4
|
||||
|
||||
// corresponding parameter when using Opal+Ruby+Simics
|
||||
OPAL_RUBY_MULTIPLIER: 1
|
||||
|
||||
|
||||
// Ruby cycles between when a sequencer issues a request and it arrives at
|
||||
// the L1 cache controller
|
||||
//
|
||||
|
@ -107,7 +103,7 @@ L2_CACHE_ASSOC: 4
|
|||
L2_CACHE_NUM_SETS_BITS: 16
|
||||
|
||||
// 32 bits = 4 GB address space
|
||||
g_MEMORY_SIZE_BYTES: 4294967296
|
||||
g_MEMORY_SIZE_BYTES: 1073741824 //4294967296
|
||||
g_DATA_BLOCK_BYTES: 64
|
||||
g_PAGE_SIZE_BYTES: 4096
|
||||
g_REPLACEMENT_POLICY: PSEDUO_LRU // currently, only other option is LRU
|
||||
|
@ -176,8 +172,6 @@ L1_REQUEST_LATENCY: 2
|
|||
L2_REQUEST_LATENCY: 4
|
||||
|
||||
|
||||
|
||||
|
||||
// Number of transitions each controller state machines can complete per cycle
|
||||
// i.e. the number of ports to each controller
|
||||
// L1cache is the sum of the L1I and L1D cache ports
|
||||
|
@ -186,6 +180,7 @@ L1CACHE_TRANSITIONS_PER_RUBY_CYCLE: 32
|
|||
// much greater constraint on the concurrency of a L2 cache bank
|
||||
L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 32
|
||||
DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 32
|
||||
DMA_TRANSITIONS_PER_RUBY_CYCLE: 1
|
||||
|
||||
|
||||
// Number of TBEs available for demand misses, ALL prefetches, and replacements
|
||||
|
@ -195,10 +190,6 @@ NUMBER_OF_TBES: 128
|
|||
NUMBER_OF_L1_TBES: 32
|
||||
NUMBER_OF_L2_TBES: 32
|
||||
|
||||
// TSO is deprecated
|
||||
TSO: false
|
||||
|
||||
|
||||
// ** INTERCONECT PARAMETERS **
|
||||
//
|
||||
g_PRINT_TOPOLOGY: true
|
||||
|
@ -207,7 +198,7 @@ g_CACHE_DESIGN: NUCA // specifies file prefix for FILE_SPECIFIED topology
|
|||
FAN_OUT_DEGREE: 4 // for HIERARCHICAL SWITCH topology
|
||||
|
||||
g_adaptive_routing: true
|
||||
NUMBER_OF_VIRTUAL_NETWORKS: 4
|
||||
NUMBER_OF_VIRTUAL_NETWORKS: 6
|
||||
|
||||
// bandwidth unit is 1/1000 byte per cycle. the following parameter is multiplied by
|
||||
// topology specific link weights
|
||||
|
@ -240,57 +231,6 @@ PROTOCOL_BUFFER_SIZE: 32
|
|||
SINGLE_ACCESS_L2_BANKS: true
|
||||
|
||||
|
||||
// constants used by TM protocols
|
||||
PROFILE_EXCEPTIONS: false
|
||||
PROFILE_XACT: true
|
||||
PROFILE_NONXACT: false
|
||||
XACT_DEBUG: true
|
||||
XACT_DEBUG_LEVEL: 1
|
||||
//XACT_MEMORY: true // set to true for TM protocols. set it HERE for lazy systems to register the proper SIMICS interfaces
|
||||
XACT_MEMORY: false
|
||||
XACT_ENABLE_TOURMALINE: false // perfect memory system
|
||||
XACT_NUM_CURRENT: 0 // must be 0
|
||||
XACT_LAST_UPDATE: 0 // must be 0
|
||||
XACT_ISOLATION_CHECK: false // Checks whether each memory access preserves transaction isolation
|
||||
PERFECT_FILTER: true // If true, use perfect physical read/write filters
|
||||
READ_WRITE_FILTER: Perfect_
|
||||
PERFECT_VIRTUAL_FILTER: true // If true, use perfect virtual read/write filters
|
||||
VIRTUAL_READ_WRITE_FILTER: Perfect_
|
||||
PERFECT_SUMMARY_FILTER: true // If true, use perfect summary read/write filters
|
||||
SUMMARY_READ_WRITE_FILTER: Perfect_
|
||||
XACT_EAGER_CD: true
|
||||
XACT_LAZY_VM: false
|
||||
XACT_CONFLICT_RES: BASE
|
||||
XACT_COMMIT_TOKEN_LATENCY: 0
|
||||
XACT_VISUALIZER: false
|
||||
XACT_NO_BACKOFF: false
|
||||
XACT_LOG_BUFFER_SIZE: 0
|
||||
XACT_STORE_PREDICTOR_ENTRIES: 256
|
||||
XACT_STORE_PREDICTOR_HISTORY: 256
|
||||
XACT_STORE_PREDICTOR_THRESHOLD: 4
|
||||
XACT_FIRST_ACCESS_COST: 0
|
||||
XACT_FIRST_PAGE_ACCESS_COST: 0
|
||||
ENABLE_MAGIC_WAITING: false
|
||||
ENABLE_WATCHPOINT: false
|
||||
XACT_ENABLE_VIRTUALIZATION_LOGTM_SE: false
|
||||
// g_NETWORK_TOPOLOGY: FILE_SPECIFIED
|
||||
// NUMBER_OF_VIRTUAL_NETWORKS: 5
|
||||
// L2_REQUEST_LATENCY: 15
|
||||
// SEQUENCER_TO_CONTROLLER_LATENCY: 3
|
||||
// L2_RESPONSE_LATENCY: 20
|
||||
// L2_TAG_LATENCY: 6
|
||||
// MEMORY_RESPONSE_LATENCY_MINUS_2: 448
|
||||
// RECYCLE_LATENCY: 1
|
||||
// g_MEMORY_SIZE_BYTES: 268435456
|
||||
// REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH: true
|
||||
|
||||
// ATMTP
|
||||
ATMTP_ENABLED: false
|
||||
ATMTP_ABORT_ON_NON_XACT_INST: false
|
||||
ATMTP_ALLOW_SAVE_RESTORE_IN_XACT: false
|
||||
ATMTP_XACT_MAX_STORES: 32
|
||||
ATMTP_DEBUG_LEVEL: 0
|
||||
|
||||
// MOESI_CMP_token parameters (some might be deprecated)
|
||||
g_FILTERING_ENABLED: false
|
||||
g_DISTRIBUTED_PERSISTENT_ENABLED: true
|
||||
|
@ -321,7 +261,7 @@ g_hold_time: 5
|
|||
g_wait_time: 5
|
||||
|
||||
// Princeton Network (Garnet)
|
||||
g_GARNET_NETWORK: false
|
||||
g_GARNET_NETWORK: true
|
||||
g_DETAIL_NETWORK: false
|
||||
g_NETWORK_TESTING: false
|
||||
g_FLIT_SIZE: 16
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
// Please: - Add new variables only to rubyconfig.defaults file.
|
||||
// - Change them here only when necessary.
|
||||
|
||||
g_SIMICS: false
|
||||
DATA_BLOCK: true
|
||||
RANDOMIZATION: true
|
||||
g_SYNTHETIC_DRIVER: true
|
||||
g_DETERMINISTIC_DRIVER: false
|
||||
g_SYNTHETIC_DRIVER: false
|
||||
g_DETERMINISTIC_DRIVER: true
|
||||
g_DEADLOCK_THRESHOLD: 500000
|
||||
g_SpecifiedGenerator: DetermGETXGenerator
|
||||
|
||||
|
@ -28,23 +29,13 @@ L2_CACHE_NUM_SETS_BITS: 5
|
|||
|
||||
g_MEMORY_SIZE_BYTES: 1048576
|
||||
|
||||
// XACT MEMORY
|
||||
XACT_LENGTH: 2000
|
||||
XACT_SIZE: 1000
|
||||
ABORT_RETRY_TIME: 400
|
||||
XACT_ISOLATION_CHECK: true
|
||||
L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 1000
|
||||
DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 1000
|
||||
PERFECT_FILTER: true // If true, use perfect read/write filters
|
||||
READ_WRITE_FILTER: Perfect_
|
||||
|
||||
//g_NETWORK_TOPOLOGY: FILE_SPECIFIED
|
||||
RECYCLE_LATENCY: 1
|
||||
//NUMBER_OF_VIRTUAL_NETWORKS: 5
|
||||
//g_NUM_MEMORIES: 16
|
||||
L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 1000
|
||||
DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 1000
|
||||
//g_PROCS_PER_CHIP: 16
|
||||
//g_PROCS_PER_CHIP: 2
|
||||
//g_NUM_L2_BANKS: 16
|
||||
//g_endpoint_bandwidth: 10000
|
||||
//g_NUM_PROCESSORS: 16
|
||||
|
|
|
@ -49,7 +49,7 @@ RubyEventQueue::RubyEventQueue()
|
|||
|
||||
RubyEventQueue::~RubyEventQueue()
|
||||
{
|
||||
// delete m_prio_heap_ptr;
|
||||
delete m_prio_heap_ptr;
|
||||
}
|
||||
|
||||
void RubyEventQueue::init()
|
||||
|
@ -91,7 +91,7 @@ void RubyEventQueue::triggerEvents(Time t)
|
|||
assert(thisNode.m_consumer_ptr != NULL);
|
||||
DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
|
||||
DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
|
||||
thisNode.m_consumer_ptr->triggerWakeup();
|
||||
thisNode.m_consumer_ptr->triggerWakeup(this);
|
||||
}
|
||||
m_globalTime = t;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void RubyEventQueue::triggerAllEvents()
|
|||
assert(thisNode.m_consumer_ptr != NULL);
|
||||
DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,*(thisNode.m_consumer_ptr));
|
||||
DEBUG_EXPR(EVENTQUEUE_COMP,MedPrio,thisNode.m_time);
|
||||
thisNode.m_consumer_ptr->triggerWakeup();
|
||||
thisNode.m_consumer_ptr->triggerWakeup(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
71
src/mem/ruby/filters/AbstractBloomFilter.hh
Normal file
71
src/mem/ruby/filters/AbstractBloomFilter.hh
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AbstractBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ABSTRACT_BLOOM_FILTER_H
|
||||
#define ABSTRACT_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
class AbstractBloomFilter {
|
||||
public:
|
||||
|
||||
virtual ~AbstractBloomFilter() {};
|
||||
virtual void clear() = 0;
|
||||
virtual void increment(const Address& addr) = 0;
|
||||
virtual void decrement(const Address& addr) = 0;
|
||||
virtual void merge(AbstractBloomFilter * other_filter) = 0;
|
||||
virtual void set(const Address& addr) = 0;
|
||||
virtual void unset(const Address& addr) = 0;
|
||||
|
||||
virtual bool isSet(const Address& addr) = 0;
|
||||
virtual int getCount(const Address& addr) = 0;
|
||||
virtual int getTotalCount() = 0;
|
||||
|
||||
virtual void print(ostream& out) const = 0;
|
||||
|
||||
virtual int getIndex(const Address& addr) = 0;
|
||||
virtual int readBit(const int index) = 0;
|
||||
virtual void writeBit(const int index, const int value) = 0;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
147
src/mem/ruby/filters/BlockBloomFilter.cc
Normal file
147
src/mem/ruby/filters/BlockBloomFilter.cc
Normal file
|
@ -0,0 +1,147 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BlockBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/BlockBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
BlockBloomFilter::BlockBloomFilter(string str)
|
||||
{
|
||||
string tail(str);
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
m_filter_size = atoi(head.c_str());
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
BlockBloomFilter::~BlockBloomFilter(){
|
||||
}
|
||||
|
||||
void BlockBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BlockBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void BlockBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void BlockBloomFilter::merge(AbstractBloomFilter * other_filter)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void BlockBloomFilter::set(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
m_filter[i] = 1;
|
||||
}
|
||||
|
||||
void BlockBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
|
||||
bool BlockBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
return (m_filter[i]);
|
||||
}
|
||||
|
||||
|
||||
int BlockBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return m_filter[get_index(addr)];
|
||||
}
|
||||
|
||||
int BlockBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
if (m_filter[i]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int BlockBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return get_index(addr);
|
||||
}
|
||||
|
||||
void BlockBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int BlockBloomFilter::readBit(const int index) {
|
||||
return m_filter[index];
|
||||
}
|
||||
|
||||
void BlockBloomFilter::writeBit(const int index, const int value) {
|
||||
m_filter[index] = value;
|
||||
}
|
||||
|
||||
int BlockBloomFilter::get_index(const Address& addr)
|
||||
{
|
||||
// Pull out some bit field ==> B1
|
||||
// Pull out additional bits, not the same as B1 ==> B2
|
||||
// XOR B1 and B2 to get hash index
|
||||
physical_address_t block_bits = addr.bitSelect( RubySystem::getBlockSizeBits(), 2*RubySystem::getBlockSizeBits() - 1);
|
||||
int offset = 5;
|
||||
physical_address_t other_bits = addr.bitSelect( 2*RubySystem::getBlockSizeBits() + offset, 2*RubySystem::getBlockSizeBits() + offset + m_filter_size_bits - 1);
|
||||
int index = block_bits ^ other_bits;
|
||||
assert(index < m_filter_size);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
82
src/mem/ruby/filters/BlockBloomFilter.hh
Normal file
82
src/mem/ruby/filters/BlockBloomFilter.hh
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BlockBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BLOCK_BLOOM_FILTER_H
|
||||
#define BLOCK_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
class BlockBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
|
||||
~BlockBloomFilter();
|
||||
BlockBloomFilter(string config);
|
||||
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
|
||||
int get_index(const Address& addr);
|
||||
|
||||
Vector<int> m_filter;
|
||||
int m_filter_size;
|
||||
int m_filter_size_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
232
src/mem/ruby/filters/BulkBloomFilter.cc
Normal file
232
src/mem/ruby/filters/BulkBloomFilter.cc
Normal file
|
@ -0,0 +1,232 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BulkBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/BulkBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
BulkBloomFilter::BulkBloomFilter(string str)
|
||||
{
|
||||
string tail(str);
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
m_filter_size = atoi(head.c_str());
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
// split the filter bits in half, c0 and c1
|
||||
m_sector_bits = m_filter_size_bits - 1;
|
||||
|
||||
m_temp_filter.setSize(m_filter_size);
|
||||
m_filter.setSize(m_filter_size);
|
||||
clear();
|
||||
|
||||
// clear temp filter
|
||||
for(int i=0; i < m_filter_size; ++i){
|
||||
m_temp_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BulkBloomFilter::~BulkBloomFilter(){
|
||||
|
||||
}
|
||||
|
||||
void BulkBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BulkBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void BulkBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void BulkBloomFilter::merge(AbstractBloomFilter * other_filter)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void BulkBloomFilter::set(const Address& addr)
|
||||
{
|
||||
// c0 contains the cache index bits
|
||||
int set_bits = m_sector_bits;
|
||||
int block_bits = RubySystem::getBlockSizeBits();
|
||||
int c0 = addr.bitSelect( block_bits, block_bits + set_bits - 1);
|
||||
// c1 contains the lower m_sector_bits permuted bits
|
||||
//Address permuted_bits = permute(addr);
|
||||
//int c1 = permuted_bits.bitSelect(0, set_bits-1);
|
||||
int c1 = addr.bitSelect( block_bits+set_bits, (block_bits+2*set_bits) - 1);
|
||||
//ASSERT(c0 < (m_filter_size/2));
|
||||
//ASSERT(c0 + (m_filter_size/2) < m_filter_size);
|
||||
//ASSERT(c1 < (m_filter_size/2));
|
||||
// set v0 bit
|
||||
m_filter[c0 + (m_filter_size/2)] = 1;
|
||||
// set v1 bit
|
||||
m_filter[c1] = 1;
|
||||
}
|
||||
|
||||
void BulkBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
// not used
|
||||
}
|
||||
|
||||
bool BulkBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
// c0 contains the cache index bits
|
||||
int set_bits = m_sector_bits;
|
||||
int block_bits = RubySystem::getBlockSizeBits();
|
||||
int c0 = addr.bitSelect( block_bits, block_bits + set_bits - 1);
|
||||
// c1 contains the lower 10 permuted bits
|
||||
//Address permuted_bits = permute(addr);
|
||||
//int c1 = permuted_bits.bitSelect(0, set_bits-1);
|
||||
int c1 = addr.bitSelect( block_bits+set_bits, (block_bits+2*set_bits) - 1);
|
||||
//ASSERT(c0 < (m_filter_size/2));
|
||||
//ASSERT(c0 + (m_filter_size/2) < m_filter_size);
|
||||
//ASSERT(c1 < (m_filter_size/2));
|
||||
// set v0 bit
|
||||
m_temp_filter[c0 + (m_filter_size/2)] = 1;
|
||||
// set v1 bit
|
||||
m_temp_filter[c1] = 1;
|
||||
|
||||
// perform filter intersection. If any c part is 0, no possibility of address being in signature.
|
||||
// get first c intersection part
|
||||
bool zero = false;
|
||||
for(int i=0; i < m_filter_size/2; ++i){
|
||||
// get intersection of signatures
|
||||
m_temp_filter[i] = m_temp_filter[i] && m_filter[i];
|
||||
zero = zero || m_temp_filter[i];
|
||||
}
|
||||
zero = !zero;
|
||||
if(zero){
|
||||
// one section is zero, no possiblility of address in signature
|
||||
// reset bits we just set
|
||||
m_temp_filter[c0 + (m_filter_size/2)] = 0;
|
||||
m_temp_filter[c1] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check second section
|
||||
zero = false;
|
||||
for(int i=m_filter_size/2; i < m_filter_size; ++i){
|
||||
// get intersection of signatures
|
||||
m_temp_filter[i] = m_temp_filter[i] && m_filter[i];
|
||||
zero = zero || m_temp_filter[i];
|
||||
}
|
||||
zero = !zero;
|
||||
if(zero){
|
||||
// one section is zero, no possiblility of address in signature
|
||||
m_temp_filter[c0 + (m_filter_size/2)] = 0;
|
||||
m_temp_filter[c1] = 0;
|
||||
return false;
|
||||
}
|
||||
// one section has at least one bit set
|
||||
m_temp_filter[c0 + (m_filter_size/2)] = 0;
|
||||
m_temp_filter[c1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int BulkBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
// not used
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BulkBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
if (m_filter[i]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int BulkBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return get_index(addr);
|
||||
}
|
||||
|
||||
int BulkBloomFilter::readBit(const int index) {
|
||||
return 0;
|
||||
// TODO
|
||||
}
|
||||
|
||||
void BulkBloomFilter::writeBit(const int index, const int value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void BulkBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int BulkBloomFilter::get_index(const Address& addr)
|
||||
{
|
||||
return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1);
|
||||
}
|
||||
|
||||
Address BulkBloomFilter::permute(const Address & addr){
|
||||
// permutes the original address bits according to Table 5
|
||||
int block_offset = RubySystem::getBlockSizeBits();
|
||||
physical_address_t part1 = addr.bitSelect( block_offset, block_offset + 6 );
|
||||
physical_address_t part2 = addr.bitSelect( block_offset + 9, block_offset + 9 );
|
||||
physical_address_t part3 = addr.bitSelect( block_offset + 11, block_offset + 11 );
|
||||
physical_address_t part4 = addr.bitSelect( block_offset + 17, block_offset + 17 );
|
||||
physical_address_t part5 = addr.bitSelect( block_offset + 7, block_offset + 8 );
|
||||
physical_address_t part6 = addr.bitSelect( block_offset + 10, block_offset + 10 );
|
||||
physical_address_t part7 = addr.bitSelect( block_offset + 12, block_offset + 12 );
|
||||
physical_address_t part8 = addr.bitSelect( block_offset + 13, block_offset + 13 );
|
||||
physical_address_t part9 = addr.bitSelect( block_offset + 15, block_offset + 16 );
|
||||
physical_address_t part10 = addr.bitSelect( block_offset + 18, block_offset + 20 );
|
||||
physical_address_t part11 = addr.bitSelect( block_offset + 14, block_offset + 14 );
|
||||
|
||||
physical_address_t result = (part1 << 14 ) | (part2 << 13 ) | (part3 << 12 ) | (part4 << 11 ) | (part5 << 9) | (part6 << 8)
|
||||
| (part7 << 7) | (part8 << 6) | (part9 << 4) | (part10 << 1) | (part11);
|
||||
// assume 32 bit addresses (both virtual and physical)
|
||||
// select the remaining high-order 11 bits
|
||||
physical_address_t remaining_bits = (addr.bitSelect( block_offset + 21, 31 )) << 21;
|
||||
result = result | remaining_bits;
|
||||
|
||||
return Address(result);
|
||||
}
|
|
@ -28,66 +28,60 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
* BulkBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TESTER_H
|
||||
#define TESTER_H
|
||||
#ifndef BULK_BLOOM_FILTER_H
|
||||
#define BULK_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/common/Driver.hh"
|
||||
#include "mem/ruby/tester/CheckTable.hh"
|
||||
#include "mem/protocol/CacheRequestType.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
class RubySystem;
|
||||
|
||||
class Tester : public Driver, public Consumer {
|
||||
class BulkBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
// Constructors
|
||||
Tester(RubySystem* sys_ptr);
|
||||
|
||||
// Destructor
|
||||
~Tester();
|
||||
~BulkBloomFilter();
|
||||
BulkBloomFilter(string config);
|
||||
|
||||
// Public Methods
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
|
||||
void wakeup();
|
||||
void printStats(ostream& out) const {}
|
||||
void clearStats() {}
|
||||
void printConfig(ostream& out) const {}
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
// Private Methods
|
||||
|
||||
void checkForDeadlock();
|
||||
int get_index(const Address& addr);
|
||||
Address permute(const Address & addr);
|
||||
|
||||
// Private copy constructor and assignment operator
|
||||
Tester(const Tester& obj);
|
||||
Tester& operator=(const Tester& obj);
|
||||
Vector<int> m_filter;
|
||||
Vector<int> m_temp_filter;
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
int m_filter_size;
|
||||
int m_filter_size_bits;
|
||||
|
||||
CheckTable m_checkTable;
|
||||
Vector<Time> m_last_progress_vector;
|
||||
int m_sector_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
ostream& operator<<(ostream& out, const Tester& obj);
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
// Output operator definition
|
||||
extern inline
|
||||
ostream& operator<<(ostream& out, const Tester& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //TESTER_H
|
||||
#endif
|
150
src/mem/ruby/filters/GenericBloomFilter.cc
Normal file
150
src/mem/ruby/filters/GenericBloomFilter.cc
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* GenericBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
#include "mem/ruby/filters/GenericBloomFilter.hh"
|
||||
#include "mem/ruby/filters/LSB_CountingBloomFilter.hh"
|
||||
#include "mem/ruby/filters/NonCountingBloomFilter.hh"
|
||||
#include "mem/ruby/filters/BulkBloomFilter.hh"
|
||||
#include "mem/ruby/filters/BlockBloomFilter.hh"
|
||||
#include "mem/ruby/filters/MultiGrainBloomFilter.hh"
|
||||
#include "mem/ruby/filters/MultiBitSelBloomFilter.hh"
|
||||
#include "mem/ruby/filters/H3BloomFilter.hh"
|
||||
|
||||
GenericBloomFilter::GenericBloomFilter(string config)
|
||||
{
|
||||
string tail(config);
|
||||
string head = string_split(tail,'_');
|
||||
|
||||
if (head == "LSB_Counting" ) {
|
||||
m_filter = new LSB_CountingBloomFilter(tail);
|
||||
}
|
||||
else if(head == "NonCounting" ) {
|
||||
m_filter = new NonCountingBloomFilter(tail);
|
||||
}
|
||||
else if(head == "Bulk" ) {
|
||||
m_filter = new BulkBloomFilter(tail);
|
||||
}
|
||||
else if(head == "Block") {
|
||||
m_filter = new BlockBloomFilter(tail);
|
||||
}
|
||||
else if(head == "Multigrain"){
|
||||
m_filter = new MultiGrainBloomFilter(tail);
|
||||
}
|
||||
else if(head == "MultiBitSel"){
|
||||
m_filter = new MultiBitSelBloomFilter(tail);
|
||||
}
|
||||
else if(head == "H3"){
|
||||
m_filter = new H3BloomFilter(tail);
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
GenericBloomFilter::~GenericBloomFilter()
|
||||
{
|
||||
delete m_filter;
|
||||
}
|
||||
|
||||
void GenericBloomFilter::clear()
|
||||
{
|
||||
m_filter->clear();
|
||||
}
|
||||
|
||||
void GenericBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
m_filter->increment(addr);
|
||||
}
|
||||
|
||||
void GenericBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
m_filter->decrement(addr);
|
||||
}
|
||||
|
||||
void GenericBloomFilter::merge(GenericBloomFilter * other_filter)
|
||||
{
|
||||
m_filter->merge(other_filter->getFilter());
|
||||
}
|
||||
|
||||
void GenericBloomFilter::set(const Address& addr)
|
||||
{
|
||||
m_filter->set(addr);
|
||||
}
|
||||
|
||||
void GenericBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
m_filter->unset(addr);
|
||||
}
|
||||
|
||||
bool GenericBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
return m_filter->isSet(addr);
|
||||
}
|
||||
|
||||
int GenericBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return m_filter->getCount(addr);
|
||||
}
|
||||
|
||||
int GenericBloomFilter::getTotalCount()
|
||||
{
|
||||
return m_filter->getTotalCount();
|
||||
}
|
||||
|
||||
int GenericBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return m_filter->getIndex(addr);
|
||||
}
|
||||
|
||||
int GenericBloomFilter::readBit(const int index) {
|
||||
return m_filter->readBit(index);
|
||||
}
|
||||
|
||||
void GenericBloomFilter::writeBit(const int index, const int value) {
|
||||
m_filter->writeBit(index, value);
|
||||
}
|
||||
|
||||
void GenericBloomFilter::print(ostream& out) const
|
||||
{
|
||||
return m_filter->print(out);
|
||||
}
|
||||
|
||||
|
|
@ -28,58 +28,67 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
* GenericBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef StoreCache_H
|
||||
#define StoreCache_H
|
||||
#ifndef GENERIC_BLOOM_FILTER_H
|
||||
#define GENERIC_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
|
||||
class DataBlock;
|
||||
class SubBlock;
|
||||
class StoreCacheEntry;
|
||||
|
||||
template <class KEY_TYPE, class VALUE_TYPE> class Map;
|
||||
|
||||
class StoreCache {
|
||||
class GenericBloomFilter {
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
StoreCache();
|
||||
GenericBloomFilter(string config);
|
||||
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(GenericBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
AbstractBloomFilter * getFilter(){
|
||||
return m_filter;
|
||||
}
|
||||
|
||||
bool isSet(const Address& addr);
|
||||
|
||||
int getCount(const Address& addr);
|
||||
|
||||
int getTotalCount();
|
||||
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
void printConfig(ostream& out) { out << "GenericBloomFilter" << endl; }
|
||||
|
||||
// Destructor
|
||||
~StoreCache();
|
||||
~GenericBloomFilter();
|
||||
|
||||
// Public Methods
|
||||
void add(const SubBlock& block);
|
||||
void remove(const SubBlock& block);
|
||||
bool check(const SubBlock& block) const;
|
||||
void update(SubBlock& block) const;
|
||||
bool isEmpty() const;
|
||||
int size() const;
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
Map<Address, StoreCacheEntry>* m_internal_cache_ptr;
|
||||
|
||||
AbstractBloomFilter* m_filter;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
ostream& operator<<(ostream& out, const StoreCache& obj);
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
// Output operator definition
|
||||
extern inline
|
||||
ostream& operator<<(ostream& out, const StoreCache& obj)
|
||||
ostream& operator<<(ostream& out, const GenericBloomFilter& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //StoreCache_H
|
||||
|
||||
#endif
|
210
src/mem/ruby/filters/H3BloomFilter.cc
Normal file
210
src/mem/ruby/filters/H3BloomFilter.cc
Normal file
|
@ -0,0 +1,210 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NonCountingBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/H3BloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
H3BloomFilter::H3BloomFilter(string str)
|
||||
{
|
||||
//TODO: change this ugly init code...
|
||||
primes_list[0] = 9323;
|
||||
primes_list[1] = 11279;
|
||||
primes_list[2] = 10247;
|
||||
primes_list[3] = 30637;
|
||||
primes_list[4] = 25717;
|
||||
primes_list[5] = 43711;
|
||||
|
||||
mults_list[0] = 255;
|
||||
mults_list[1] = 29;
|
||||
mults_list[2] = 51;
|
||||
mults_list[3] = 3;
|
||||
mults_list[4] = 77;
|
||||
mults_list[5] = 43;
|
||||
|
||||
adds_list[0] = 841;
|
||||
adds_list[1] = 627;
|
||||
adds_list[2] = 1555;
|
||||
adds_list[3] = 241;
|
||||
adds_list[4] = 7777;
|
||||
adds_list[5] = 65931;
|
||||
|
||||
|
||||
|
||||
string tail(str);
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
// head contains filter size, tail contains bit offset from block number
|
||||
m_filter_size = atoi(head.c_str());
|
||||
|
||||
head = string_split(tail, '_');
|
||||
m_num_hashes = atoi(head.c_str());
|
||||
|
||||
if(tail == "Regular") {
|
||||
isParallel = false;
|
||||
} else if (tail == "Parallel") {
|
||||
isParallel = true;
|
||||
} else {
|
||||
cout << "ERROR: Incorrect config string for MultiHash Bloom! :" << str << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
m_par_filter_size = m_filter_size/m_num_hashes;
|
||||
m_par_filter_size_bits = log_int(m_par_filter_size);
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
clear();
|
||||
}
|
||||
|
||||
H3BloomFilter::~H3BloomFilter(){
|
||||
}
|
||||
|
||||
void H3BloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void H3BloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void H3BloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void H3BloomFilter::merge(AbstractBloomFilter * other_filter){
|
||||
// assumes both filters are the same size!
|
||||
H3BloomFilter * temp = (H3BloomFilter*) other_filter;
|
||||
for(int i=0; i < m_filter_size; ++i){
|
||||
m_filter[i] |= (*temp)[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void H3BloomFilter::set(const Address& addr)
|
||||
{
|
||||
for (int i = 0; i < m_num_hashes; i++) {
|
||||
int idx = get_index(addr, i);
|
||||
m_filter[idx] = 1;
|
||||
|
||||
//Profile hash value distribution
|
||||
//g_system_ptr->getProfiler()->getXactProfiler()->profileHashValue(i, idx); // gem5:Arka decomissiong of log_tm
|
||||
}
|
||||
}
|
||||
|
||||
void H3BloomFilter::unset(const Address& addr)
|
||||
{
|
||||
cout << "ERROR: Unset should never be called in a Bloom filter";
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool H3BloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
for (int i=0; i < m_num_hashes; i++) {
|
||||
int idx = get_index(addr, i);
|
||||
res = res && m_filter[idx];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int H3BloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return isSet(addr)? 1: 0;
|
||||
}
|
||||
|
||||
int H3BloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int H3BloomFilter::readBit(const int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void H3BloomFilter::writeBit(const int index, const int value) {
|
||||
|
||||
}
|
||||
|
||||
int H3BloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
count += m_filter[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void H3BloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int H3BloomFilter::get_index(const Address& addr, int i)
|
||||
{
|
||||
uint64 x = addr.getLineAddress();
|
||||
//uint64 y = (x*mults_list[i] + adds_list[i]) % primes_list[i];
|
||||
int y = hash_H3(x,i);
|
||||
|
||||
if(isParallel) {
|
||||
return (y % m_par_filter_size) + i*m_par_filter_size;
|
||||
} else {
|
||||
return y % m_filter_size;
|
||||
}
|
||||
}
|
||||
|
||||
int H3BloomFilter::hash_H3(uint64 value, int index) {
|
||||
uint64 mask = 1;
|
||||
uint64 val = value;
|
||||
int result = 0;
|
||||
|
||||
for(int i = 0; i < 64; i++) {
|
||||
if(val&mask) result ^= H3[i][index];
|
||||
val = val >> 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
1258
src/mem/ruby/filters/H3BloomFilter.hh
Normal file
1258
src/mem/ruby/filters/H3BloomFilter.hh
Normal file
File diff suppressed because it is too large
Load diff
141
src/mem/ruby/filters/LSB_CountingBloomFilter.cc
Normal file
141
src/mem/ruby/filters/LSB_CountingBloomFilter.cc
Normal file
|
@ -0,0 +1,141 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LSB_CountingBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/LSB_CountingBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
LSB_CountingBloomFilter::LSB_CountingBloomFilter(string str)
|
||||
{
|
||||
string tail(str);
|
||||
string head = string_split(tail, ':');
|
||||
|
||||
m_filter_size = atoi(head.c_str());
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
m_count = atoi(tail.c_str());
|
||||
m_count_bits = log_int(m_count);
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
clear();
|
||||
}
|
||||
|
||||
LSB_CountingBloomFilter::~LSB_CountingBloomFilter(){
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
if (m_filter[i] < m_count);
|
||||
m_filter[i] += 1;
|
||||
}
|
||||
|
||||
|
||||
void LSB_CountingBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
if (m_filter[i] > 0)
|
||||
m_filter[i] -= 1;
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::merge(AbstractBloomFilter * other_filter)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::set(const Address& addr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
bool LSB_CountingBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
int LSB_CountingBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return m_filter[get_index(addr)];
|
||||
}
|
||||
|
||||
int LSB_CountingBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
count += m_filter[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int LSB_CountingBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return get_index(addr);
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int LSB_CountingBloomFilter::readBit(const int index) {
|
||||
return 0;
|
||||
// TODO
|
||||
}
|
||||
|
||||
void LSB_CountingBloomFilter::writeBit(const int index, const int value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int LSB_CountingBloomFilter::get_index(const Address& addr)
|
||||
{
|
||||
return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1);
|
||||
}
|
||||
|
||||
|
82
src/mem/ruby/filters/LSB_CountingBloomFilter.hh
Normal file
82
src/mem/ruby/filters/LSB_CountingBloomFilter.hh
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LSB_CountingBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LSB_COUNTING_BLOOM_FILTER_H
|
||||
#define LSB_COUNTING_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
class LSB_CountingBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
|
||||
~LSB_CountingBloomFilter();
|
||||
LSB_CountingBloomFilter(string config);
|
||||
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
|
||||
int get_index(const Address& addr);
|
||||
|
||||
Vector<int> m_filter;
|
||||
int m_filter_size;
|
||||
int m_filter_size_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
191
src/mem/ruby/filters/MultiBitSelBloomFilter.cc
Normal file
191
src/mem/ruby/filters/MultiBitSelBloomFilter.cc
Normal file
|
@ -0,0 +1,191 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NonCountingBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/MultiBitSelBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
MultiBitSelBloomFilter::MultiBitSelBloomFilter(string str)
|
||||
{
|
||||
|
||||
string tail(str);
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
// head contains filter size, tail contains bit offset from block number
|
||||
m_filter_size = atoi(head.c_str());
|
||||
|
||||
head = string_split(tail, '_');
|
||||
m_num_hashes = atoi(head.c_str());
|
||||
|
||||
head = string_split(tail, '_');
|
||||
m_skip_bits = atoi(head.c_str());
|
||||
|
||||
if(tail == "Regular") {
|
||||
isParallel = false;
|
||||
} else if (tail == "Parallel") {
|
||||
isParallel = true;
|
||||
} else {
|
||||
cout << "ERROR: Incorrect config string for MultiBitSel Bloom! :" << str << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
m_par_filter_size = m_filter_size/m_num_hashes;
|
||||
m_par_filter_size_bits = log_int(m_par_filter_size);
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
clear();
|
||||
}
|
||||
|
||||
MultiBitSelBloomFilter::~MultiBitSelBloomFilter(){
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void MultiBitSelBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::merge(AbstractBloomFilter * other_filter){
|
||||
// assumes both filters are the same size!
|
||||
MultiBitSelBloomFilter * temp = (MultiBitSelBloomFilter*) other_filter;
|
||||
for(int i=0; i < m_filter_size; ++i){
|
||||
m_filter[i] |= (*temp)[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::set(const Address& addr)
|
||||
{
|
||||
for (int i = 0; i < m_num_hashes; i++) {
|
||||
int idx = get_index(addr, i);
|
||||
m_filter[idx] = 1;
|
||||
|
||||
//Profile hash value distribution
|
||||
//g_system_ptr->getProfiler()->getXactProfiler()->profileHashValue(i, idx); //gem5:Arka for decomissioning of log_tm
|
||||
}
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
cout << "ERROR: Unset should never be called in a Bloom filter";
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool MultiBitSelBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
for (int i=0; i < m_num_hashes; i++) {
|
||||
int idx = get_index(addr, i);
|
||||
res = res && m_filter[idx];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int MultiBitSelBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return isSet(addr)? 1: 0;
|
||||
}
|
||||
|
||||
int MultiBitSelBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultiBitSelBloomFilter::readBit(const int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::writeBit(const int index, const int value) {
|
||||
|
||||
}
|
||||
|
||||
int MultiBitSelBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
count += m_filter[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void MultiBitSelBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int MultiBitSelBloomFilter::get_index(const Address& addr, int i)
|
||||
{
|
||||
// m_skip_bits is used to perform BitSelect after skipping some bits. Used to simulate BitSel hashing on larger than cache-line granularities
|
||||
uint64 x = (addr.getLineAddress()) >> m_skip_bits;
|
||||
int y = hash_bitsel(x, i, m_num_hashes, 30, m_filter_size_bits);
|
||||
//36-bit addresses, 6-bit cache lines
|
||||
|
||||
if(isParallel) {
|
||||
return (y % m_par_filter_size) + i*m_par_filter_size;
|
||||
} else {
|
||||
return y % m_filter_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MultiBitSelBloomFilter::hash_bitsel(uint64 value, int index, int jump, int maxBits, int numBits) {
|
||||
uint64 mask = 1;
|
||||
int result = 0;
|
||||
int bit, i;
|
||||
|
||||
for(i = 0; i < numBits; i++) {
|
||||
bit = (index + jump*i) % maxBits;
|
||||
if (value & (mask << bit)) result += mask << i;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -28,80 +28,70 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* PersistentArbiter.hh
|
||||
* MultiBitSelBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Used for hierarchical distributed persistent request scheme
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PERSISTENTARBITER_H
|
||||
#define PERSISTENTARBITER_H
|
||||
#ifndef MULTIBITSEL_BLOOM_FILTER_H
|
||||
#define MULTIBITSEL_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/gems_common/Vector.hh"
|
||||
#include "mem/ruby/slicc_interface/AbstractChip.hh"
|
||||
#include "mem/protocol/AccessPermission.hh"
|
||||
#include "mem/protocol/AccessType.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/profiler/Profiler.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
struct ArbiterEntry {
|
||||
bool valid;
|
||||
Address address;
|
||||
AccessType type;
|
||||
NodeID localId;
|
||||
};
|
||||
|
||||
class PersistentArbiter {
|
||||
class MultiBitSelBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
PersistentArbiter(AbstractChip* chip_ptr);
|
||||
~MultiBitSelBloomFilter();
|
||||
MultiBitSelBloomFilter(string config);
|
||||
|
||||
// Destructor
|
||||
~PersistentArbiter();
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
// Public Methods
|
||||
|
||||
void addLocker(NodeID id, Address addr, AccessType type);
|
||||
void removeLocker(NodeID id);
|
||||
bool successorRequestPresent(Address addr, NodeID id);
|
||||
bool lockersExist();
|
||||
void advanceActiveLock();
|
||||
Address getActiveLockAddress();
|
||||
NodeID getArbiterId();
|
||||
bool isBusy();
|
||||
|
||||
void setIssuedAddress(Address addr);
|
||||
bool isIssuedAddress(Address addr);
|
||||
|
||||
|
||||
Address getIssuedAddress() { return m_issued_address; }
|
||||
|
||||
static void printConfig(ostream& out) {}
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
void print(ostream& out) const;
|
||||
|
||||
NodeID getActiveLocalId();
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
int operator[](const int index) const{
|
||||
return this->m_filter[index];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Address m_issued_address;
|
||||
AbstractChip* m_chip_ptr;
|
||||
int m_locker;
|
||||
bool m_busy;
|
||||
Vector<ArbiterEntry> m_entries;
|
||||
int get_index(const Address& addr, int hashNumber);
|
||||
|
||||
int hash_bitsel(uint64 value, int index, int jump, int maxBits, int numBits);
|
||||
|
||||
Vector<int> m_filter;
|
||||
int m_filter_size;
|
||||
int m_num_hashes;
|
||||
int m_filter_size_bits;
|
||||
int m_skip_bits;
|
||||
|
||||
int m_par_filter_size;
|
||||
int m_par_filter_size_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
|
||||
bool isParallel;
|
||||
|
||||
};
|
||||
|
||||
// Output operator definition
|
||||
extern inline
|
||||
ostream& operator<<(ostream& out, const PersistentArbiter& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#endif //PERFECTCACHEMEMORY_H
|
||||
#endif
|
172
src/mem/ruby/filters/MultiGrainBloomFilter.cc
Normal file
172
src/mem/ruby/filters/MultiGrainBloomFilter.cc
Normal file
|
@ -0,0 +1,172 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MultiGrainBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/MultiGrainBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
MultiGrainBloomFilter::MultiGrainBloomFilter(string str)
|
||||
{
|
||||
string tail(str);
|
||||
|
||||
// split into the 2 filter sizes
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
// head contains size of 1st bloom filter, tail contains size of 2nd bloom filter
|
||||
|
||||
m_filter_size = atoi(head.c_str());
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
m_page_filter_size = atoi(tail.c_str());
|
||||
m_page_filter_size_bits = log_int(m_page_filter_size);
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
m_page_filter.setSize(m_page_filter_size);
|
||||
clear();
|
||||
}
|
||||
|
||||
MultiGrainBloomFilter::~MultiGrainBloomFilter(){
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
for(int i=0; i < m_page_filter_size; ++i){
|
||||
m_page_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void MultiGrainBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::merge(AbstractBloomFilter * other_filter)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::set(const Address& addr)
|
||||
{
|
||||
int i = get_block_index(addr);
|
||||
int j = get_page_index(addr);
|
||||
assert(i < m_filter_size);
|
||||
assert(j < m_page_filter_size);
|
||||
m_filter[i] = 1;
|
||||
m_page_filter[i] = 1;
|
||||
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
// not used
|
||||
}
|
||||
|
||||
bool MultiGrainBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
int i = get_block_index(addr);
|
||||
int j = get_page_index(addr);
|
||||
assert(i < m_filter_size);
|
||||
assert(j < m_page_filter_size);
|
||||
// we have to have both indices set
|
||||
return (m_filter[i] && m_page_filter[i]);
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
// not used
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
count += m_filter[i];
|
||||
}
|
||||
|
||||
for(int i=0; i < m_page_filter_size; ++i){
|
||||
count += m_page_filter[i] = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return 0;
|
||||
// TODO
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::readBit(const int index) {
|
||||
return 0;
|
||||
// TODO
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::writeBit(const int index, const int value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void MultiGrainBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::get_block_index(const Address& addr)
|
||||
{
|
||||
// grap a chunk of bits after byte offset
|
||||
return addr.bitSelect( RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_filter_size_bits - 1);
|
||||
}
|
||||
|
||||
int MultiGrainBloomFilter::get_page_index(const Address & addr)
|
||||
{
|
||||
// grap a chunk of bits after first chunk
|
||||
return addr.bitSelect( RubySystem::getBlockSizeBits() + m_filter_size_bits - 1,
|
||||
RubySystem::getBlockSizeBits() + m_filter_size_bits - 1 + m_page_filter_size_bits - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
88
src/mem/ruby/filters/MultiGrainBloomFilter.hh
Normal file
88
src/mem/ruby/filters/MultiGrainBloomFilter.hh
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MultiGrainBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MULTIGRAIN_BLOOM_FILTER_H
|
||||
#define MULTIGRAIN_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
class MultiGrainBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
|
||||
~MultiGrainBloomFilter();
|
||||
MultiGrainBloomFilter(string str);
|
||||
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
|
||||
private:
|
||||
|
||||
int get_block_index(const Address& addr);
|
||||
int get_page_index(const Address & addr);
|
||||
|
||||
// The block filter
|
||||
Vector<int> m_filter;
|
||||
int m_filter_size;
|
||||
int m_filter_size_bits;
|
||||
// The page number filter
|
||||
Vector<int> m_page_filter;
|
||||
int m_page_filter_size;
|
||||
int m_page_filter_size_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
144
src/mem/ruby/filters/NonCountingBloomFilter.cc
Normal file
144
src/mem/ruby/filters/NonCountingBloomFilter.cc
Normal file
|
@ -0,0 +1,144 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NonCountingBloomFilter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/filters/NonCountingBloomFilter.hh"
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
NonCountingBloomFilter::NonCountingBloomFilter(string str)
|
||||
{
|
||||
string tail(str);
|
||||
string head = string_split(tail, '_');
|
||||
|
||||
// head contains filter size, tail contains bit offset from block number
|
||||
m_filter_size = atoi(head.c_str());
|
||||
m_offset = atoi(tail.c_str());
|
||||
m_filter_size_bits = log_int(m_filter_size);
|
||||
|
||||
|
||||
m_filter.setSize(m_filter_size);
|
||||
clear();
|
||||
}
|
||||
|
||||
NonCountingBloomFilter::~NonCountingBloomFilter(){
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::clear()
|
||||
{
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::increment(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
|
||||
void NonCountingBloomFilter::decrement(const Address& addr)
|
||||
{
|
||||
// Not used
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::merge(AbstractBloomFilter * other_filter){
|
||||
// assumes both filters are the same size!
|
||||
NonCountingBloomFilter * temp = (NonCountingBloomFilter*) other_filter;
|
||||
for(int i=0; i < m_filter_size; ++i){
|
||||
m_filter[i] |= (*temp)[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::set(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
m_filter[i] = 1;
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::unset(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
m_filter[i] = 0;
|
||||
}
|
||||
|
||||
bool NonCountingBloomFilter::isSet(const Address& addr)
|
||||
{
|
||||
int i = get_index(addr);
|
||||
return (m_filter[i]);
|
||||
}
|
||||
|
||||
|
||||
int NonCountingBloomFilter::getCount(const Address& addr)
|
||||
{
|
||||
return m_filter[get_index(addr)];
|
||||
}
|
||||
|
||||
int NonCountingBloomFilter::getTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < m_filter_size; i++) {
|
||||
count += m_filter[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::print(ostream& out) const
|
||||
{
|
||||
}
|
||||
|
||||
int NonCountingBloomFilter::getIndex(const Address& addr)
|
||||
{
|
||||
return get_index(addr);
|
||||
}
|
||||
|
||||
int NonCountingBloomFilter::readBit(const int index) {
|
||||
return m_filter[index];
|
||||
}
|
||||
|
||||
void NonCountingBloomFilter::writeBit(const int index, const int value) {
|
||||
m_filter[index] = value;
|
||||
}
|
||||
|
||||
int NonCountingBloomFilter::get_index(const Address& addr)
|
||||
{
|
||||
return addr.bitSelect( RubySystem::getBlockSizeBits() + m_offset,
|
||||
RubySystem::getBlockSizeBits() + m_offset + m_filter_size_bits - 1);
|
||||
}
|
||||
|
||||
|
|
@ -28,66 +28,61 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
* NonCountingBloomFilter.hh
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHECKTABLE_H
|
||||
#define CHECKTABLE_H
|
||||
#ifndef NONCOUNTING_BLOOM_FILTER_H
|
||||
#define NONCOUNTING_BLOOM_FILTER_H
|
||||
|
||||
#include "mem/gems_common/Map.hh"
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/gems_common/Vector.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/filters/AbstractBloomFilter.hh"
|
||||
|
||||
class Address;
|
||||
class Check;
|
||||
template <class KEY_TYPE, class VALUE_TYPE> class Map;
|
||||
|
||||
class CheckTable {
|
||||
class NonCountingBloomFilter : public AbstractBloomFilter {
|
||||
public:
|
||||
// Constructors
|
||||
CheckTable();
|
||||
|
||||
// Destructor
|
||||
~CheckTable();
|
||||
~NonCountingBloomFilter();
|
||||
NonCountingBloomFilter(string config);
|
||||
|
||||
// Public Methods
|
||||
void clear();
|
||||
void increment(const Address& addr);
|
||||
void decrement(const Address& addr);
|
||||
void merge(AbstractBloomFilter * other_filter);
|
||||
void set(const Address& addr);
|
||||
void unset(const Address& addr);
|
||||
|
||||
Check* getRandomCheck();
|
||||
Check* getCheck(const Address& address);
|
||||
bool isSet(const Address& addr);
|
||||
int getCount(const Address& addr);
|
||||
int getTotalCount();
|
||||
|
||||
// bool isPresent(const Address& address) const;
|
||||
// void removeCheckFromTable(const Address& address);
|
||||
// bool isTableFull() const;
|
||||
// Need a method to select a check or retrieve a check
|
||||
int getIndex(const Address& addr);
|
||||
int readBit(const int index);
|
||||
void writeBit(const int index, const int value);
|
||||
|
||||
void print(ostream& out) const;
|
||||
|
||||
int operator[](const int index) const{
|
||||
return this->m_filter[index];
|
||||
}
|
||||
|
||||
private:
|
||||
// Private Methods
|
||||
void addCheck(const Address& address);
|
||||
|
||||
// Private copy constructor and assignment operator
|
||||
CheckTable(const CheckTable& obj);
|
||||
CheckTable& operator=(const CheckTable& obj);
|
||||
int get_index(const Address& addr);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
Vector<Check*> m_check_vector;
|
||||
Map<Address, Check*>* m_lookup_map_ptr;
|
||||
Vector<int> m_filter;
|
||||
int m_filter_size;
|
||||
int m_offset;
|
||||
int m_filter_size_bits;
|
||||
|
||||
int m_count_bits;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
ostream& operator<<(ostream& out, const CheckTable& obj);
|
||||
|
||||
// ******************* Definitions *******************
|
||||
|
||||
// Output operator definition
|
||||
extern inline
|
||||
ostream& operator<<(ostream& out, const CheckTable& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //CHECKTABLE_H
|
||||
#endif
|
|
@ -1,191 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* init.C
|
||||
*
|
||||
* Description: See init.hh
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/common/Debug.hh"
|
||||
#include "mem/ruby/common/Driver.hh"
|
||||
#include "mem/ruby/profiler/Profiler.hh"
|
||||
#include "mem/ruby/tester/Tester.hh"
|
||||
#include "mem/ruby/init.hh"
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mem/gems_common/ioutil/confio.hh"
|
||||
#include "mem/gems_common/ioutil/initvar.hh"
|
||||
|
||||
// A generated file containing the default parameters in string form
|
||||
// The defaults are stored in the variable global_default_param
|
||||
#include "mem/ruby/default_param.hh"
|
||||
|
||||
static initvar_t *ruby_initvar_obj = NULL;
|
||||
|
||||
//***************************************************************************
|
||||
static void init_generate_values( void )
|
||||
{
|
||||
/* update generated values, based on input configuration */
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
|
||||
void init_variables( void )
|
||||
{
|
||||
// allocate the "variable initialization" package
|
||||
ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
|
||||
global_default_param,
|
||||
&init_simulator,
|
||||
&init_generate_values);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void init_variables(const char* config_str )
|
||||
{
|
||||
// allocate the "variable initialization" package
|
||||
ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
|
||||
config_str,
|
||||
&init_simulator,
|
||||
&init_generate_values );
|
||||
}
|
||||
*/
|
||||
|
||||
void init_simulator()
|
||||
{
|
||||
// Set things to NULL to make sure we don't de-reference them
|
||||
// without a seg. fault.
|
||||
g_system_ptr = NULL;
|
||||
g_debug_ptr = NULL;
|
||||
g_eventQueue_ptr = NULL;
|
||||
|
||||
cout << "Ruby Timing Mode" << endl;
|
||||
|
||||
|
||||
g_debug_ptr = new Debug( DEBUG_FILTER_STRING,
|
||||
DEBUG_VERBOSITY_STRING,
|
||||
DEBUG_START_TIME,
|
||||
DEBUG_OUTPUT_FILENAME );
|
||||
RubyConfig::init();
|
||||
|
||||
cout << "Creating event queue..." << endl;
|
||||
g_eventQueue_ptr = new RubyEventQueue;
|
||||
cout << "Creating event queue done" << endl;
|
||||
|
||||
cout << "Creating system..." << endl;
|
||||
cout << " Processors: " << RubyConfig::numberOfProcessors() << endl;
|
||||
|
||||
g_system_ptr = new RubySystem;
|
||||
cout << "Creating system done" << endl;
|
||||
|
||||
cout << "Ruby initialization complete" << endl;
|
||||
}
|
||||
|
||||
void init_simulator(Driver* _driver)
|
||||
{
|
||||
// Set things to NULL to make sure we don't de-reference them
|
||||
// without a seg. fault.
|
||||
g_system_ptr = NULL;
|
||||
g_debug_ptr = NULL;
|
||||
g_eventQueue_ptr = NULL;
|
||||
|
||||
cout << "Ruby Timing Mode" << endl;
|
||||
|
||||
|
||||
g_debug_ptr = new Debug( DEBUG_FILTER_STRING,
|
||||
DEBUG_VERBOSITY_STRING,
|
||||
DEBUG_START_TIME,
|
||||
DEBUG_OUTPUT_FILENAME );
|
||||
RubyConfig::init();
|
||||
|
||||
cout << "Creating event queue..." << endl;
|
||||
g_eventQueue_ptr = new RubyEventQueue;
|
||||
cout << "Creating event queue done" << endl;
|
||||
|
||||
cout << "Creating system..." << endl;
|
||||
cout << " Processors: " << RubyConfig::numberOfProcessors() << endl;
|
||||
|
||||
g_system_ptr = new RubySystem(_driver);
|
||||
cout << "Creating system done" << endl;
|
||||
|
||||
cout << "Ruby initialization complete" << endl;
|
||||
}
|
||||
|
||||
void destroy_simulator()
|
||||
{
|
||||
cout << "Deleting system..." << endl;
|
||||
delete g_system_ptr;
|
||||
cout << "Deleting system done" << endl;
|
||||
|
||||
cout << "Deleting event queue..." << endl;
|
||||
delete g_eventQueue_ptr;
|
||||
cout << "Deleting event queue done" << endl;
|
||||
|
||||
delete g_debug_ptr;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| DG: These are the external load and unload hooks that will be called by |
|
||||
| M5 in phase 1 integration, and possibly afterwards, too. |
|
||||
+-------------------------------------------------------------------------*/
|
||||
|
||||
//dsm: superfluous
|
||||
/*extern "C"
|
||||
int OnLoadRuby() {
|
||||
init_variables();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int OnInitRuby() {
|
||||
init_simulator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int OnUnloadRuby() {
|
||||
destroy_simulator();
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
/* I have to put it somewhere for now */
|
||||
void tester_main(int argc, char **argv) {
|
||||
std::cout << __FILE__ << "(" << __LINE__ << "): Not implemented." << std::endl;
|
||||
}
|
206
src/mem/ruby/libruby.cc
Normal file
206
src/mem/ruby/libruby.cc
Normal file
|
@ -0,0 +1,206 @@
|
|||
|
||||
#include <sys/wait.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "mem/ruby/libruby_internal.hh"
|
||||
#include "mem/ruby/system/RubyPort.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||
#include "mem/ruby/system/MemoryVector.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
|
||||
string RubyRequestType_to_string(const RubyRequestType& obj)
|
||||
{
|
||||
switch(obj) {
|
||||
case RubyRequestType_IFETCH:
|
||||
return "IFETCH";
|
||||
case RubyRequestType_LD:
|
||||
return "LD";
|
||||
case RubyRequestType_ST:
|
||||
return "ST";
|
||||
case RubyRequestType_RMW:
|
||||
return "RMW";
|
||||
case RubyRequestType_NULL:
|
||||
default:
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
RubyRequestType string_to_RubyRequestType(std::string str)
|
||||
{
|
||||
if (str == "IFETCH")
|
||||
return RubyRequestType_IFETCH;
|
||||
else if (str == "LD")
|
||||
return RubyRequestType_LD;
|
||||
else if (str == "ST")
|
||||
return RubyRequestType_ST;
|
||||
else if (str == "RMW")
|
||||
return RubyRequestType_RMW;
|
||||
else
|
||||
assert(0);
|
||||
return RubyRequestType_NULL;
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream& out, const RubyRequestType& obj)
|
||||
{
|
||||
cerr << "in op" << endl;
|
||||
out << RubyRequestType_to_string(obj);
|
||||
cerr << "flushing" << endl;
|
||||
out << flush;
|
||||
cerr << "done" << endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
vector<string> tokenizeString(string str, string delims)
|
||||
{
|
||||
vector<string> tokens;
|
||||
char* pch;
|
||||
char* tmp;
|
||||
const char* c_delims = delims.c_str();
|
||||
tmp = new char[str.length()+1];
|
||||
strcpy(tmp, str.c_str());
|
||||
pch = strtok(tmp, c_delims);
|
||||
while (pch != NULL) {
|
||||
string tmp_str(pch);
|
||||
if (tmp_str == "null") tmp_str = "";
|
||||
tokens.push_back(tmp_str);
|
||||
|
||||
pch = strtok(NULL, c_delims);
|
||||
}
|
||||
delete [] tmp;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void libruby_init(const char* cfg_filename)
|
||||
{
|
||||
stringstream cfg_output;
|
||||
|
||||
// first we execute the Ruby-lang configuration script
|
||||
int fd[2];
|
||||
int pid;
|
||||
if (pipe(fd) == -1) {
|
||||
perror("Error Creating Pipe");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1){
|
||||
perror("Error forking");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
// child
|
||||
close(fd[0]); // close the read end of the pipe
|
||||
// replace stdout with the write pipe
|
||||
if (dup2(fd[1], STDOUT_FILENO) == -1) {
|
||||
perror("Error redirecting stdout");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#define QUOTE_MACRO(x, y) QUOTE_TXT(x,y)
|
||||
#define QUOTE_TXT(x, y) #x y
|
||||
if (execlp("ruby", "ruby", "-I", QUOTE_MACRO(GEMS_ROOT, "/ruby/config"), QUOTE_MACRO(GEMS_ROOT, "/ruby/config/print_cfg.rb"), "-r", cfg_filename, NULL)) {
|
||||
perror("execlp");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
close(fd[1]);
|
||||
|
||||
int child_status;
|
||||
if (wait(&child_status) == -1) {
|
||||
perror("wait");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (child_status != EXIT_SUCCESS) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char buf[100];
|
||||
int bytes_read;
|
||||
while( (bytes_read = read(fd[0], buf, 100)) > 0 ) {
|
||||
for (int i=0;i<bytes_read;i++) {
|
||||
// cout << buf[i];
|
||||
cfg_output << buf[i];
|
||||
}
|
||||
}
|
||||
assert(bytes_read == 0);
|
||||
close(fd[0]);
|
||||
}
|
||||
|
||||
vector<RubyObjConf> * sys_conf = new vector<RubyObjConf>;
|
||||
|
||||
string line;
|
||||
getline(cfg_output, line) ;
|
||||
while ( !cfg_output.eof() ) {
|
||||
vector<string> tokens = tokenizeString(line, " ");
|
||||
assert(tokens.size() >= 2);
|
||||
vector<string> argv;
|
||||
for (size_t i=2; i<tokens.size(); i++) {
|
||||
std::replace(tokens[i].begin(), tokens[i].end(), '%', ' ');
|
||||
std::replace(tokens[i].begin(), tokens[i].end(), '#', '\n');
|
||||
argv.push_back(tokens[i]);
|
||||
}
|
||||
sys_conf->push_back(RubyObjConf(tokens[0], tokens[1], argv));
|
||||
tokens.clear();
|
||||
argv.clear();
|
||||
getline(cfg_output, line);
|
||||
}
|
||||
|
||||
RubySystem::create(*sys_conf);
|
||||
delete sys_conf;
|
||||
}
|
||||
|
||||
RubyPortHandle libruby_get_port(const char* port_name, void (*hit_callback)(int64_t access_id))
|
||||
{
|
||||
return static_cast<RubyPortHandle>(RubySystem::getPort(port_name, hit_callback));
|
||||
}
|
||||
|
||||
RubyPortHandle libruby_get_port_by_name(const char* port_name)
|
||||
{
|
||||
return static_cast<RubyPortHandle>(RubySystem::getPortOnly(port_name));
|
||||
}
|
||||
|
||||
void libruby_write_ram(uint64_t paddr, uint8_t* data, int len)
|
||||
{
|
||||
RubySystem::getMemoryVector()->write(Address(paddr), data, len);
|
||||
}
|
||||
|
||||
void libruby_read_ram(uint64_t paddr, uint8_t* data, int len)
|
||||
{
|
||||
RubySystem::getMemoryVector()->read(Address(paddr), data, len);
|
||||
}
|
||||
|
||||
int64_t libruby_issue_request(RubyPortHandle p, struct RubyRequest request)
|
||||
{
|
||||
return static_cast<RubyPort*>(p)->makeRequest(request);
|
||||
}
|
||||
|
||||
int libruby_tick(int n)
|
||||
{
|
||||
RubySystem::getEventQueue()->triggerEvents(RubySystem::getEventQueue()->getTime() + n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void libruby_destroy()
|
||||
{
|
||||
}
|
||||
|
||||
const char* libruby_last_error()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void libruby_print_config(std::ostream & out)
|
||||
{
|
||||
RubySystem::printConfig(out);
|
||||
}
|
||||
|
||||
void libruby_print_stats(std::ostream & out)
|
||||
{
|
||||
RubySystem::printStats(out);
|
||||
}
|
||||
|
||||
uint64_t libruby_get_time() {
|
||||
return RubySystem::getCycleCount(0);
|
||||
}
|
109
src/mem/ruby/libruby.hh
Normal file
109
src/mem/ruby/libruby.hh
Normal file
|
@ -0,0 +1,109 @@
|
|||
|
||||
#ifndef LIBRUBY_H
|
||||
#define LIBRUBY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
|
||||
typedef void* RubyPortHandle;
|
||||
enum RubyRequestType {
|
||||
RubyRequestType_NULL,
|
||||
RubyRequestType_IFETCH,
|
||||
RubyRequestType_LD,
|
||||
RubyRequestType_ST,
|
||||
RubyRequestType_RMW
|
||||
};
|
||||
|
||||
enum RubyAccessMode {
|
||||
RubyAccessMode_User,
|
||||
RubyAccessMode_Supervisor,
|
||||
RubyAccessMode_Device
|
||||
};
|
||||
|
||||
struct RubyRequest {
|
||||
uint64_t paddr;
|
||||
uint8_t* data;
|
||||
int len;
|
||||
uint64_t pc;
|
||||
RubyRequestType type;
|
||||
RubyAccessMode access_mode;
|
||||
|
||||
RubyRequest() {}
|
||||
RubyRequest(uint64_t _paddr, uint8_t* _data, int _len, uint64_t _pc, RubyRequestType _type, RubyAccessMode _access_mode)
|
||||
: paddr(_paddr), data(_data), len(_len), pc(_pc), type(_type), access_mode(_access_mode)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the system. cfg_file is a Ruby-lang configuration script
|
||||
*/
|
||||
void libruby_init(const char* cfg_file);
|
||||
|
||||
/**
|
||||
* Tear down a configured system. Must be invoked after a call to libruby_init.
|
||||
*/
|
||||
void libruby_destroy();
|
||||
|
||||
/**
|
||||
* Print the last error encountered by ruby. Currently unimplemented.
|
||||
*/
|
||||
const char* libruby_last_error();
|
||||
|
||||
/**
|
||||
* Retrieve a handle to a RubyPort object, identified by name in the
|
||||
* configuration. You also pass in the callback function you want
|
||||
* this port to use when a request completes. Only one handle to a
|
||||
* port is allowed at a time.
|
||||
*/
|
||||
RubyPortHandle libruby_get_port(const char* name, void (*hit_callback)(int64_t access_id));
|
||||
|
||||
/**
|
||||
* Retrieve a handle to a RubyPort object, identified by name in the
|
||||
* configuration.
|
||||
*/
|
||||
RubyPortHandle libruby_get_port_by_name(const char* name);
|
||||
|
||||
|
||||
/**
|
||||
* issue_request returns a unique access_id to identify the ruby
|
||||
* transaction. This access_id is later returned to the caller via
|
||||
* hit_callback (passed to libruby_get_port)
|
||||
*/
|
||||
int64_t libruby_issue_request(RubyPortHandle p, struct RubyRequest request);
|
||||
|
||||
/**
|
||||
* writes data directly into Ruby's data array. Note that this
|
||||
* ignores caches, and should be considered incoherent after
|
||||
* simulation starts.
|
||||
*/
|
||||
void libruby_write_ram(uint64_t paddr, uint8_t * data, int len);
|
||||
|
||||
/**
|
||||
* reads data directory from Ruby's data array. Note that this
|
||||
* ignores caches, and should be considered incoherent after
|
||||
* simulation starts
|
||||
*/
|
||||
void libruby_read_ram(uint64_t paddr, uint8_t * data, int len);
|
||||
|
||||
/**
|
||||
* tick the system n cycles. Eventually, will return the number of
|
||||
* cycles until the next event, but for now it always returns 0
|
||||
*/
|
||||
int libruby_tick(int n);
|
||||
|
||||
/**
|
||||
* self explainitory
|
||||
*/
|
||||
void libruby_print_config(std::ostream & out);
|
||||
|
||||
/**
|
||||
* self explainitory
|
||||
*/
|
||||
void libruby_print_stats(std::ostream & out);
|
||||
|
||||
|
||||
/**
|
||||
* get time
|
||||
*/
|
||||
uint64_t libruby_get_time();
|
||||
#endif
|
13
src/mem/ruby/libruby_internal.hh
Normal file
13
src/mem/ruby/libruby_internal.hh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef LIBRUBY_INTERNAL_H
|
||||
#define LIBRUBY_INTERNAL_H
|
||||
|
||||
#include "mem/ruby/libruby.hh"
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
std::string RubyRequestType_to_string(const RubyRequestType& obj);
|
||||
RubyRequestType string_to_RubyRequestType(std::string);
|
||||
std::ostream& operator<<(std::ostream& out, const RubyRequestType& obj);
|
||||
|
||||
#endif
|
34
src/mem/ruby/network/Network.cc
Normal file
34
src/mem/ruby/network/Network.cc
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
#include "mem/protocol/MachineType.hh"
|
||||
#include "mem/ruby/network/Network.hh"
|
||||
|
||||
Network::Network(const string & name)
|
||||
: m_name(name)
|
||||
{
|
||||
m_virtual_networks = 0;
|
||||
m_topology_ptr = NULL;
|
||||
}
|
||||
|
||||
void Network::init(const vector<string> & argv)
|
||||
{
|
||||
m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network
|
||||
|
||||
for (size_t i=0; i<argv.size(); i+=2) {
|
||||
if (argv[i] == "number_of_virtual_networks")
|
||||
m_virtual_networks = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "topology")
|
||||
m_topology_ptr = RubySystem::getTopology(argv[i+1]);
|
||||
else if (argv[i] == "buffer_size")
|
||||
m_buffer_size = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "endpoint_bandwidth")
|
||||
m_endpoint_bandwidth = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "adaptive_routing")
|
||||
m_adaptive_routing = (argv[i+1]=="true");
|
||||
else if (argv[i] == "link_latency")
|
||||
m_link_latency = atoi(argv[i+1].c_str());
|
||||
|
||||
}
|
||||
assert(m_virtual_networks != 0);
|
||||
assert(m_topology_ptr != NULL);
|
||||
// printf ("HERE \n");
|
||||
}
|
|
@ -49,22 +49,29 @@
|
|||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/system/NodeID.hh"
|
||||
#include "mem/protocol/MessageSizeType.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
|
||||
class NetDest;
|
||||
class MessageBuffer;
|
||||
class Throttle;
|
||||
class Topology;
|
||||
|
||||
class Network {
|
||||
public:
|
||||
// Constructors
|
||||
Network() {}
|
||||
Network(const string & name);
|
||||
virtual void init(const vector<string> & argv);
|
||||
|
||||
// Destructor
|
||||
virtual ~Network() {}
|
||||
|
||||
// Public Methods
|
||||
|
||||
static Network* createNetwork(int nodes);
|
||||
int getBufferSize() { return m_buffer_size; }
|
||||
int getNumberOfVirtualNetworks() { return m_virtual_networks; }
|
||||
int getEndpointBandwidth() { return m_endpoint_bandwidth; }
|
||||
bool getAdaptiveRouting() {return m_adaptive_routing; }
|
||||
int getLinkLatency() { return m_link_latency; }
|
||||
|
||||
// returns the queue requested for the given component
|
||||
virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0;
|
||||
|
@ -84,7 +91,7 @@ public:
|
|||
virtual void printConfig(ostream& out) const = 0;
|
||||
virtual void print(ostream& out) const = 0;
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
// Private Methods
|
||||
// Private copy constructor and assignment operator
|
||||
|
@ -92,6 +99,15 @@ private:
|
|||
Network& operator=(const Network& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
protected:
|
||||
const string m_name;
|
||||
int m_nodes;
|
||||
int m_virtual_networks;
|
||||
int m_buffer_size;
|
||||
int m_endpoint_bandwidth;
|
||||
Topology* m_topology_ptr;
|
||||
bool m_adaptive_routing;
|
||||
int m_link_latency;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
|
@ -110,7 +126,7 @@ ostream& operator<<(ostream& out, const Network& obj)
|
|||
|
||||
// Code to map network message size types to an integer number of bytes
|
||||
const int CONTROL_MESSAGE_SIZE = 8;
|
||||
const int DATA_MESSAGE_SIZE = (64+8);
|
||||
const int DATA_MESSAGE_SIZE = (RubySystem::getBlockSizeBytes()+8);
|
||||
|
||||
extern inline
|
||||
int MessageSizeType_to_int(MessageSizeType size_type)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
class CreditLink_d : public NetworkLink_d {
|
||||
public:
|
||||
CreditLink_d(int id):NetworkLink_d(id) {}
|
||||
CreditLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr):NetworkLink_d(id, link_latency, net_ptr) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,10 +43,19 @@
|
|||
#include "mem/ruby/network/garnet-fixed-pipeline/CreditLink_d.hh"
|
||||
#include "mem/ruby/common/NetDest.hh"
|
||||
|
||||
GarnetNetwork_d::GarnetNetwork_d(int nodes)
|
||||
GarnetNetwork_d::GarnetNetwork_d(const string & name)
|
||||
: Network(name)
|
||||
{
|
||||
m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // Number of virtual networks = number of message classes in the coherence protocol
|
||||
}
|
||||
|
||||
void GarnetNetwork_d::init(const vector<string> & argv)
|
||||
{
|
||||
Network::init(argv);
|
||||
|
||||
//added by SS
|
||||
m_network_config_ptr = new NetworkConfig;
|
||||
m_network_config_ptr->init(argv);
|
||||
|
||||
m_ruby_start = 0;
|
||||
m_flits_recieved = 0;
|
||||
m_flits_injected = 0;
|
||||
|
@ -80,7 +89,7 @@ GarnetNetwork_d::GarnetNetwork_d(int nodes)
|
|||
}
|
||||
|
||||
// Setup the network switches
|
||||
m_topology_ptr = new Topology(this, m_nodes);
|
||||
m_topology_ptr->makeTopology();
|
||||
|
||||
int number_of_routers = m_topology_ptr->numSwitches();
|
||||
for (int i=0; i<number_of_routers; i++) {
|
||||
|
@ -138,7 +147,7 @@ void GarnetNetwork_d::makeInLink(NodeID src, SwitchID dest, const NetDest& routi
|
|||
if(!isReconfiguration)
|
||||
{
|
||||
NetworkLink_d *net_link = new NetworkLink_d(m_link_ptr_vector.size(), link_latency, this);
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size());
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size(), link_latency, this);
|
||||
m_link_ptr_vector.insertAtBottom(net_link);
|
||||
m_creditlink_ptr_vector.insertAtBottom(credit_link);
|
||||
|
||||
|
@ -167,7 +176,7 @@ void GarnetNetwork_d::makeOutLink(SwitchID src, NodeID dest, const NetDest& rout
|
|||
if(!isReconfiguration)
|
||||
{
|
||||
NetworkLink_d *net_link = new NetworkLink_d(m_link_ptr_vector.size(), link_latency, this);
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size());
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size(), link_latency, this);
|
||||
m_link_ptr_vector.insertAtBottom(net_link);
|
||||
m_creditlink_ptr_vector.insertAtBottom(credit_link);
|
||||
|
||||
|
@ -190,7 +199,7 @@ void GarnetNetwork_d::makeInternalLink(SwitchID src, SwitchID dest, const NetDes
|
|||
if(!isReconfiguration)
|
||||
{
|
||||
NetworkLink_d *net_link = new NetworkLink_d(m_link_ptr_vector.size(), link_latency, this);
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size());
|
||||
CreditLink_d *credit_link = new CreditLink_d(m_creditlink_ptr_vector.size(), link_latency, this);
|
||||
m_link_ptr_vector.insertAtBottom(net_link);
|
||||
m_creditlink_ptr_vector.insertAtBottom(credit_link);
|
||||
|
||||
|
@ -241,9 +250,9 @@ Time GarnetNetwork_d::getRubyStartTime()
|
|||
void GarnetNetwork_d::printStats(ostream& out) const
|
||||
{ double average_link_utilization = 0;
|
||||
Vector<double > average_vc_load;
|
||||
average_vc_load.setSize(m_virtual_networks*NetworkConfig::getVCsPerClass());
|
||||
average_vc_load.setSize(m_virtual_networks*m_network_config_ptr->getVCsPerClass());
|
||||
|
||||
for(int i = 0; i < m_virtual_networks*NetworkConfig::getVCsPerClass(); i++)
|
||||
for(int i = 0; i < m_virtual_networks*m_network_config_ptr->getVCsPerClass(); i++)
|
||||
{
|
||||
average_vc_load[i] = 0;
|
||||
}
|
||||
|
@ -259,7 +268,7 @@ void GarnetNetwork_d::printStats(ostream& out) const
|
|||
Vector<int > vc_load = m_link_ptr_vector[i]->getVcLoad();
|
||||
for(int j = 0; j < vc_load.size(); j++)
|
||||
{
|
||||
assert(vc_load.size() == NetworkConfig::getVCsPerClass()*m_virtual_networks);
|
||||
assert(vc_load.size() == m_network_config_ptr->getVCsPerClass()*m_virtual_networks);
|
||||
average_vc_load[j] += vc_load[j];
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +276,7 @@ void GarnetNetwork_d::printStats(ostream& out) const
|
|||
out << "Average Link Utilization :: " << average_link_utilization << " flits/cycle" << endl;
|
||||
out << "-------------" << endl;
|
||||
|
||||
for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < m_network_config_ptr->getVCsPerClass()*m_virtual_networks; i++)
|
||||
{
|
||||
average_vc_load[i] = (double(average_vc_load[i]) / (double(g_eventQueue_ptr->getTime()) - m_ruby_start));
|
||||
out << "Average VC Load [" << i << "] = " << average_vc_load[i] << " flits/cycle " << endl;
|
||||
|
@ -304,7 +313,7 @@ void GarnetNetwork_d::printConfig(ostream& out) const
|
|||
out << "Network Configuration" << endl;
|
||||
out << "---------------------" << endl;
|
||||
out << "network: GarnetNetwork_d" << endl;
|
||||
out << "topology: " << g_NETWORK_TOPOLOGY << endl;
|
||||
out << "topology: " << m_topology_ptr->getName() << endl;
|
||||
out << endl;
|
||||
|
||||
for (int i = 0; i < m_virtual_networks; i++)
|
||||
|
@ -337,10 +346,7 @@ void GarnetNetwork_d::printConfig(ostream& out) const
|
|||
{
|
||||
m_router_ptr_vector[i]->printConfig(out);
|
||||
}
|
||||
if (g_PRINT_TOPOLOGY)
|
||||
{
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
|
||||
void GarnetNetwork_d::print(ostream& out) const
|
||||
|
|
|
@ -51,10 +51,15 @@ class CreditLink_d;
|
|||
|
||||
class GarnetNetwork_d : public Network{
|
||||
public:
|
||||
GarnetNetwork_d(int nodes);
|
||||
GarnetNetwork_d(const string & name);
|
||||
|
||||
~GarnetNetwork_d();
|
||||
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
//added by SS
|
||||
NetworkConfig* getNetworkConfig() { return m_network_config_ptr; }
|
||||
|
||||
int getNumNodes(){ return m_nodes;}
|
||||
|
||||
// returns the queue requested for the given component
|
||||
|
@ -99,6 +104,8 @@ public:
|
|||
void makeInternalLink(SwitchID src, NodeID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration);
|
||||
|
||||
private:
|
||||
NetworkConfig* m_network_config_ptr;
|
||||
|
||||
void checkNetworkAllocation(NodeID id, bool ordered, int network_num);
|
||||
|
||||
// Private copy constructor and assignment operator
|
||||
|
@ -106,8 +113,8 @@ private:
|
|||
GarnetNetwork_d& operator=(const GarnetNetwork_d& obj);
|
||||
|
||||
/***********Data Members*************/
|
||||
int m_virtual_networks;
|
||||
int m_nodes;
|
||||
// int m_virtual_networks;
|
||||
// int m_nodes;
|
||||
int m_flits_recieved, m_flits_injected;
|
||||
double m_network_latency, m_queueing_latency;
|
||||
|
||||
|
@ -122,7 +129,7 @@ private:
|
|||
Vector<CreditLink_d *> m_creditlink_ptr_vector; // All links in the network
|
||||
Vector<NetworkInterface_d *> m_ni_ptr_vector; // All NI's in Network
|
||||
|
||||
Topology* m_topology_ptr;
|
||||
// Topology* m_topology_ptr;
|
||||
Time m_ruby_start;
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ NetworkInterface_d::NetworkInterface_d(int id, int virtual_networks, GarnetNetwo
|
|||
m_id = id;
|
||||
m_net_ptr = network_ptr;
|
||||
m_virtual_networks = virtual_networks;
|
||||
m_vc_per_vnet = NetworkConfig::getVCsPerClass();
|
||||
m_vc_per_vnet = m_net_ptr->getNetworkConfig()->getVCsPerClass();
|
||||
m_num_vcs = m_vc_per_vnet*m_virtual_networks;
|
||||
|
||||
m_vc_round_robin = 0;
|
||||
|
@ -66,7 +66,7 @@ NetworkInterface_d::NetworkInterface_d(int id, int virtual_networks, GarnetNetwo
|
|||
|
||||
for(int i = 0; i < m_num_vcs; i++)
|
||||
{
|
||||
m_out_vc_state.insertAtBottom(new OutVcState_d(i));
|
||||
m_out_vc_state.insertAtBottom(new OutVcState_d(i, m_net_ptr));
|
||||
m_out_vc_state[i]->setState(IDLE_, g_eventQueue_ptr->getTime());
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ bool NetworkInterface_d::flitisizeMessage(MsgPtr msg_ptr, int vnet)
|
|||
NetDest net_msg_dest = net_msg_ptr->getInternalDestination();
|
||||
Vector<NodeID> dest_nodes = net_msg_dest.getAllDest(); // gets all the destinations associated with this message.
|
||||
|
||||
int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/NetworkConfig::getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size
|
||||
int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size
|
||||
|
||||
for(int ctr = 0; ctr < dest_nodes.size(); ctr++) // loop because we will be converting all multicast messages into unicast messages
|
||||
{
|
||||
|
@ -221,7 +221,7 @@ void NetworkInterface_d::wakeup()
|
|||
if(t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_)
|
||||
{
|
||||
free_signal = true;
|
||||
if(!NetworkConfig::isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers
|
||||
if(!m_net_ptr->getNetworkConfig()->isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers
|
||||
{
|
||||
outNode_ptr[t_flit->get_vnet()]->enqueue(t_flit->get_msg_ptr(), 1); // enqueueing for protocol buffer. This is not required when doing network only testing
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ void NetworkInterface_d::scheduleOutputLink()
|
|||
|
||||
int NetworkInterface_d::get_vnet(int vc)
|
||||
{
|
||||
for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < m_net_ptr->getNumberOfVirtualNetworks(); i++)
|
||||
{
|
||||
if(vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet))
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh"
|
||||
#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh"
|
||||
|
||||
/*
|
||||
NetworkLink_d::NetworkLink_d(int id)
|
||||
{
|
||||
m_id = id;
|
||||
|
@ -45,12 +46,12 @@ NetworkLink_d::NetworkLink_d(int id)
|
|||
|
||||
linkBuffer = new flitBuffer_d();
|
||||
m_link_utilized = 0;
|
||||
m_vc_load.setSize(NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS);
|
||||
m_vc_load.setSize(NetworkConfig::getVCsPerClass()*RubySystem::getNetwork()->getNumberOfVirtualNetworks());
|
||||
|
||||
for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < NetworkConfig::getVCsPerClass()*RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++)
|
||||
m_vc_load[i] = 0;
|
||||
}
|
||||
|
||||
*/
|
||||
NetworkLink_d::NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr)
|
||||
{
|
||||
m_net_ptr = net_ptr;
|
||||
|
@ -58,9 +59,9 @@ NetworkLink_d::NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr)
|
|||
m_latency = link_latency;
|
||||
linkBuffer = new flitBuffer_d();
|
||||
m_link_utilized = 0;
|
||||
m_vc_load.setSize(NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS);
|
||||
m_vc_load.setSize(m_net_ptr->getNetworkConfig()->getVCsPerClass()*net_ptr->getNumberOfVirtualNetworks());
|
||||
|
||||
for(int i = 0; i < NetworkConfig::getVCsPerClass()*NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < m_net_ptr->getNetworkConfig()->getVCsPerClass()*net_ptr->getNumberOfVirtualNetworks(); i++)
|
||||
m_vc_load[i] = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class GarnetNetwork_d;
|
|||
|
||||
class NetworkLink_d : public Consumer {
|
||||
public:
|
||||
NetworkLink_d(int id);
|
||||
//NetworkLink_d(int id);
|
||||
~NetworkLink_d();
|
||||
|
||||
NetworkLink_d(int id, int link_latency, GarnetNetwork_d *net_ptr);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* OutVCState_d.C
|
||||
* OutVCState_d.cc
|
||||
*
|
||||
* Niket Agarwal, Princeton University
|
||||
*
|
||||
|
@ -37,10 +37,11 @@
|
|||
#include "mem/ruby/network/garnet-flexible-pipeline/NetworkConfig.hh"
|
||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||
|
||||
OutVcState_d::OutVcState_d(int id)
|
||||
OutVcState_d::OutVcState_d(int id, GarnetNetwork_d *network_ptr)
|
||||
{
|
||||
m_network_ptr = network_ptr;
|
||||
m_id = id;
|
||||
m_vc_state = IDLE_;
|
||||
m_time = g_eventQueue_ptr->getTime();
|
||||
m_credit_count = NetworkConfig::getBufferSize();
|
||||
m_credit_count = m_network_ptr->getNetworkConfig()->getBufferSize();
|
||||
}
|
||||
|
|
|
@ -37,10 +37,11 @@
|
|||
#define OUT_VC_STATE_D_H
|
||||
|
||||
#include "mem/ruby/network/garnet-fixed-pipeline/NetworkHeader.hh"
|
||||
#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh"
|
||||
|
||||
class OutVcState_d {
|
||||
public:
|
||||
OutVcState_d(int id);
|
||||
OutVcState_d(int id, GarnetNetwork_d *network_ptr);
|
||||
|
||||
int get_inport() {return m_in_port; }
|
||||
int get_invc() { return m_in_vc; }
|
||||
|
@ -75,6 +76,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
GarnetNetwork_d *m_network_ptr;
|
||||
int m_id ;
|
||||
Time m_time;
|
||||
VC_state_type m_vc_state;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* OutputUnit_d.C
|
||||
* OutputUnit_d.cc
|
||||
*
|
||||
* Niket Agarwal, Princeton University
|
||||
*
|
||||
|
@ -46,7 +46,7 @@ OutputUnit_d::OutputUnit_d(int id, Router_d *router)
|
|||
|
||||
for(int i = 0; i < m_num_vcs; i++)
|
||||
{
|
||||
m_outvc_state.insertAtBottom(new OutVcState_d(i));
|
||||
m_outvc_state.insertAtBottom(new OutVcState_d(i, m_router->get_net_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ Router_d::Router_d(int id, GarnetNetwork_d *network_ptr)
|
|||
{
|
||||
m_id = id;
|
||||
m_network_ptr = network_ptr;
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS;
|
||||
m_vc_per_vnet = NetworkConfig::getVCsPerClass();
|
||||
m_virtual_networks = network_ptr->getNumberOfVirtualNetworks();
|
||||
m_vc_per_vnet = m_network_ptr->getNetworkConfig()->getVCsPerClass();
|
||||
m_num_vcs = m_virtual_networks*m_vc_per_vnet;
|
||||
m_flit_width = NetworkConfig::getFlitSize();
|
||||
m_flit_width = m_network_ptr->getNetworkConfig()->getFlitSize();
|
||||
|
||||
m_routing_unit = new RoutingUnit_d(this);
|
||||
m_vc_alloc = new VCallocator_d(this);
|
||||
|
|
|
@ -207,7 +207,7 @@ void SWallocator_d::check_for_wakeup()
|
|||
|
||||
int SWallocator_d::get_vnet(int invc)
|
||||
{
|
||||
for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++)
|
||||
{
|
||||
if(invc >= (i*m_vc_per_vnet) && invc < ((i+1)*m_vc_per_vnet))
|
||||
{
|
||||
|
|
|
@ -244,7 +244,7 @@ void VCallocator_d::arbitrate_outvcs()
|
|||
|
||||
int VCallocator_d::get_vnet(int invc)
|
||||
{
|
||||
for(int i = 0; i < NUMBER_OF_VIRTUAL_NETWORKS; i++)
|
||||
for(int i = 0; i < RubySystem::getNetwork()->getNumberOfVirtualNetworks(); i++)
|
||||
{
|
||||
if(invc >= (i*m_vc_per_vnet) && invc < ((i+1)*m_vc_per_vnet))
|
||||
{
|
||||
|
|
|
@ -44,26 +44,22 @@
|
|||
#include "mem/ruby/network/garnet-flexible-pipeline/NetworkLink.hh"
|
||||
#include "mem/ruby/common/NetDest.hh"
|
||||
|
||||
// calls new to abstract away from the network
|
||||
Network* Network::createNetwork(int nodes)
|
||||
GarnetNetwork::GarnetNetwork(const string & name)
|
||||
: Network(name)
|
||||
{
|
||||
NetworkConfig::readNetConfig();
|
||||
// Instantiate a network depending on what kind of network is requested
|
||||
if(NetworkConfig::isGarnetNetwork())
|
||||
{
|
||||
if(NetworkConfig::isDetailNetwork())
|
||||
return new GarnetNetwork_d(nodes);
|
||||
else
|
||||
return new GarnetNetwork(nodes);
|
||||
}
|
||||
else
|
||||
return new SimpleNetwork(nodes);
|
||||
}
|
||||
|
||||
GarnetNetwork::GarnetNetwork(int nodes)
|
||||
void GarnetNetwork::init(const vector<string> & argv)
|
||||
{
|
||||
m_nodes = MachineType_base_number(MachineType_NUM); // Total nodes in network
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // Number of virtual networks = number of message classes in the coherence protocol
|
||||
// printf("hello\n");
|
||||
Network::init(argv);
|
||||
//added by SS
|
||||
// assert (m_topology_ptr!=NULL);
|
||||
|
||||
m_network_config_ptr = new NetworkConfig;
|
||||
|
||||
m_network_config_ptr->init(argv);
|
||||
|
||||
m_ruby_start = 0;
|
||||
|
||||
// Allocate to and from queues
|
||||
|
@ -91,7 +87,8 @@ GarnetNetwork::GarnetNetwork(int nodes)
|
|||
}
|
||||
|
||||
// Setup the network switches
|
||||
m_topology_ptr = new Topology(this, m_nodes);
|
||||
assert (m_topology_ptr!=NULL);
|
||||
m_topology_ptr->makeTopology();
|
||||
|
||||
int number_of_routers = m_topology_ptr->numSwitches();
|
||||
for (int i=0; i<number_of_routers; i++) {
|
||||
|
@ -188,6 +185,7 @@ void GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, const NetDest&
|
|||
|
||||
void GarnetNetwork::checkNetworkAllocation(NodeID id, bool ordered, int network_num)
|
||||
{
|
||||
printf ("id = %i, m_nodes = %i \n", id, m_nodes);
|
||||
ASSERT(id < m_nodes);
|
||||
ASSERT(network_num < m_virtual_networks);
|
||||
|
||||
|
@ -223,9 +221,9 @@ Time GarnetNetwork::getRubyStartTime()
|
|||
void GarnetNetwork::printStats(ostream& out) const
|
||||
{ double average_link_utilization = 0;
|
||||
Vector<double > average_vc_load;
|
||||
average_vc_load.setSize(m_virtual_networks*NetworkConfig::getVCsPerClass());
|
||||
average_vc_load.setSize(m_virtual_networks*m_network_config_ptr->getVCsPerClass());
|
||||
|
||||
for(int i = 0; i < m_virtual_networks*NetworkConfig::getVCsPerClass(); i++)
|
||||
for(int i = 0; i < m_virtual_networks*m_network_config_ptr->getVCsPerClass(); i++)
|
||||
{
|
||||
average_vc_load[i] = 0;
|
||||
}
|
||||
|
@ -240,7 +238,7 @@ void GarnetNetwork::printStats(ostream& out) const
|
|||
Vector<int > vc_load = m_link_ptr_vector[i]->getVcLoad();
|
||||
for(int j = 0; j < vc_load.size(); j++)
|
||||
{
|
||||
assert(vc_load.size() == NetworkConfig::getVCsPerClass()*m_virtual_networks);
|
||||
assert(vc_load.size() == m_network_config_ptr->getVCsPerClass()*m_virtual_networks);
|
||||
average_vc_load[j] += vc_load[j];
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +246,7 @@ void GarnetNetwork::printStats(ostream& out) const
|
|||
out << "Average Link Utilization :: " << average_link_utilization << " flits/cycle" <<endl;
|
||||
out << "-------------" << endl;
|
||||
|
||||
for(int i = 0; i < NetworkConfig::getVCsPerClass()*m_virtual_networks; i++)
|
||||
for(int i = 0; i < m_network_config_ptr->getVCsPerClass()*m_virtual_networks; i++)
|
||||
{
|
||||
average_vc_load[i] = (double(average_vc_load[i]) / (double(g_eventQueue_ptr->getTime()) - m_ruby_start));
|
||||
out << "Average VC Load [" << i << "] = " << average_vc_load[i] << " flits/cycle" << endl;
|
||||
|
@ -262,7 +260,7 @@ void GarnetNetwork::printConfig(ostream& out) const
|
|||
out << "Network Configuration" << endl;
|
||||
out << "---------------------" << endl;
|
||||
out << "network: GARNET_NETWORK" << endl;
|
||||
out << "topology: " << g_NETWORK_TOPOLOGY << endl;
|
||||
out << "topology: " << m_topology_ptr->getName() << endl;
|
||||
out << endl;
|
||||
|
||||
for (int i = 0; i < m_virtual_networks; i++)
|
||||
|
@ -295,10 +293,7 @@ void GarnetNetwork::printConfig(ostream& out) const
|
|||
{
|
||||
m_router_ptr_vector[i]->printConfig(out);
|
||||
}
|
||||
if (g_PRINT_TOPOLOGY)
|
||||
{
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
|
||||
void GarnetNetwork::print(ostream& out) const
|
||||
|
|
|
@ -50,10 +50,15 @@ class NetworkLink;
|
|||
|
||||
class GarnetNetwork : public Network{
|
||||
public:
|
||||
GarnetNetwork(int nodes);
|
||||
GarnetNetwork(const string & name);
|
||||
|
||||
~GarnetNetwork();
|
||||
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
//added by SS
|
||||
NetworkConfig* getNetworkConfig() { return m_network_config_ptr; }
|
||||
|
||||
// returns the queue requested for the given component
|
||||
MessageBuffer* getToNetQueue(NodeID id, bool ordered, int network_num);
|
||||
MessageBuffer* getFromNetQueue(NodeID id, bool ordered, int network_num);
|
||||
|
@ -83,9 +88,10 @@ private:
|
|||
GarnetNetwork(const GarnetNetwork& obj);
|
||||
GarnetNetwork& operator=(const GarnetNetwork& obj);
|
||||
|
||||
|
||||
/***********Data Members*************/
|
||||
int m_virtual_networks;
|
||||
int m_nodes;
|
||||
// int m_virtual_networks;
|
||||
// int m_nodes;
|
||||
|
||||
Vector<bool> m_in_use;
|
||||
Vector<bool> m_ordered;
|
||||
|
@ -97,8 +103,10 @@ private:
|
|||
Vector<NetworkLink *> m_link_ptr_vector; // All links in the network
|
||||
Vector<NetworkInterface *> m_ni_ptr_vector; // All NI's in Network
|
||||
|
||||
Topology* m_topology_ptr;
|
||||
// Topology* m_topology_ptr;
|
||||
Time m_ruby_start;
|
||||
|
||||
NetworkConfig* m_network_config_ptr;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
|
|
|
@ -43,14 +43,35 @@
|
|||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
|
||||
class NetworkConfig {
|
||||
private:
|
||||
int m_flit_size;
|
||||
int m_number_of_pipe_stages;
|
||||
int m_vcs_per_class;
|
||||
int m_buffer_size;
|
||||
bool m_using_network_testing;
|
||||
public:
|
||||
static bool isGarnetNetwork() {return g_GARNET_NETWORK; }
|
||||
static bool isDetailNetwork() {return g_DETAIL_NETWORK; }
|
||||
static int isNetworkTesting() {return g_NETWORK_TESTING; }
|
||||
static int getFlitSize() {return g_FLIT_SIZE; }
|
||||
static int getNumPipeStages() {return g_NUM_PIPE_STAGES; }
|
||||
static int getVCsPerClass() {return g_VCS_PER_CLASS; }
|
||||
static int getBufferSize() {return g_BUFFER_SIZE; }
|
||||
NetworkConfig(){}
|
||||
void init(const vector<string> & argv) {
|
||||
for (size_t i=0; i<argv.size(); i+=2) {
|
||||
if (argv[i] == "flit_size")
|
||||
m_flit_size = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "number_of_pipe_stages")
|
||||
m_number_of_pipe_stages = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "vcs_per_class")
|
||||
m_vcs_per_class = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "buffer_size")
|
||||
m_buffer_size = atoi(argv[i+1].c_str());
|
||||
else if (argv[i] == "using_network_testing")
|
||||
m_using_network_testing = atoi(argv[i+1].c_str());
|
||||
}
|
||||
}
|
||||
// static bool isGarnetNetwork() {return RubyConfig::getUsingGarnetNetwork(); }
|
||||
// static bool isDetailNetwork() {return RubyConfig::getUsingDetailNetwork(); }
|
||||
bool isNetworkTesting() {return m_using_network_testing; }
|
||||
int getFlitSize() {return m_flit_size; }
|
||||
int getNumPipeStages() {return m_number_of_pipe_stages; }
|
||||
int getVCsPerClass() {return m_vcs_per_class; }
|
||||
int getBufferSize() {return m_buffer_size; }
|
||||
// This is no longer used. See config/rubyconfig.defaults to set Garnet parameters.
|
||||
static void readNetConfig()
|
||||
{
|
||||
|
@ -58,6 +79,9 @@ class NetworkConfig {
|
|||
string filename = "network/garnet-flexible-pipeline/";
|
||||
filename += NETCONFIG_DEFAULTS;
|
||||
|
||||
if (g_SIMICS) {
|
||||
filename = "../../../ruby/"+filename;
|
||||
}
|
||||
ifstream NetconfigFile( filename.c_str(), ios::in);
|
||||
if(!NetconfigFile.is_open())
|
||||
{
|
||||
|
@ -73,19 +97,19 @@ class NetworkConfig {
|
|||
getline(NetconfigFile, line, '\n');
|
||||
string var = string_split(line, ':');
|
||||
|
||||
if(!var.compare("g_GARNET_NETWORK"))
|
||||
if(!var.compare("RubyConfig::getUsingGarnetNetwork()"))
|
||||
{
|
||||
if(!line.compare("true"))
|
||||
g_GARNET_NETWORK = true;
|
||||
RubyConfig::getUsingGarnetNetwork() = true;
|
||||
else
|
||||
g_GARNET_NETWORK = false;
|
||||
RubyConfig::getUsingGarnetNetwork() = false;
|
||||
}
|
||||
if(!var.compare("g_DETAIL_NETWORK"))
|
||||
if(!var.compare("RubyConfig::getUsingDetailNetwork()"))
|
||||
{
|
||||
if(!line.compare("true"))
|
||||
g_DETAIL_NETWORK = true;
|
||||
RubyConfig::getUsingDetailNetwork() = true;
|
||||
else
|
||||
g_DETAIL_NETWORK = false;
|
||||
RubyConfig::getUsingDetailNetwork() = false;
|
||||
}
|
||||
if(!var.compare("g_NETWORK_TESTING"))
|
||||
{
|
||||
|
@ -94,27 +118,28 @@ class NetworkConfig {
|
|||
else
|
||||
g_NETWORK_TESTING = false;
|
||||
}
|
||||
if(!var.compare("g_FLIT_SIZE"))
|
||||
g_FLIT_SIZE = atoi(line.c_str());
|
||||
if(!var.compare("g_NUM_PIPE_STAGES"))
|
||||
g_NUM_PIPE_STAGES = atoi(line.c_str());
|
||||
if(!var.compare("g_VCS_PER_CLASS"))
|
||||
g_VCS_PER_CLASS = atoi(line.c_str());
|
||||
if(!var.compare("g_BUFFER_SIZE"))
|
||||
g_BUFFER_SIZE = atoi(line.c_str());
|
||||
if(!var.compare("RubyConfig::getFlitSize()"))
|
||||
RubyConfig::getFlitSize() = atoi(line.c_str());
|
||||
if(!var.compare("RubyConfig::getNumberOfPipeStages()"))
|
||||
RubyConfig::getNumberOfPipeStages() = atoi(line.c_str());
|
||||
if(!var.compare("RubyConfig::getVCSPerClass()"))
|
||||
RubyConfig::getVCSPerClass() = atoi(line.c_str());
|
||||
if(!var.compare("RubyConfig::getBufferSize()"))
|
||||
RubyConfig::getBufferSize() = atoi(line.c_str());
|
||||
}
|
||||
NetconfigFile.close();
|
||||
*/
|
||||
/*
|
||||
cout << "g_GARNET_NETWORK = " << g_GARNET_NETWORK << endl;
|
||||
cout << "g_DETAIL_NETWORK = " << g_DETAIL_NETWORK << endl;
|
||||
cout << "RubyConfig::getUsingGarnetNetwork() = " << RubyConfig::getUsingGarnetNetwork() << endl;
|
||||
cout << "RubyConfig::getUsingDetailNetwork() = " << RubyConfig::getUsingDetailNetwork() << endl;
|
||||
cout << "g_NETWORK_TESTING = " << g_NETWORK_TESTING << endl;
|
||||
cout << "g_FLIT_SIZE = " << g_FLIT_SIZE << endl;
|
||||
cout << "g_NUM_PIPE_STAGES = " << g_NUM_PIPE_STAGES << endl;
|
||||
cout << "g_VCS_PER_CLASS= " << g_VCS_PER_CLASS << endl;
|
||||
cout << "g_BUFFER_SIZE = " << g_BUFFER_SIZE << endl;
|
||||
cout << "RubyConfig::getFlitSize() = " << RubyConfig::getFlitSize() << endl;
|
||||
cout << "RubyConfig::getNumberOfPipeStages() = " << RubyConfig::getNumberOfPipeStages() << endl;
|
||||
cout << "RubyConfig::getVCSPerClass()= " << RubyConfig::getVCSPerClass() << endl;
|
||||
cout << "RubyConfig::getBufferSize() = " << RubyConfig::getBufferSize() << endl;
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* NetworkInterface.C
|
||||
* NetworkInterface.cc
|
||||
*
|
||||
* Niket Agarwal, Princeton University
|
||||
*
|
||||
|
@ -43,7 +43,7 @@ NetworkInterface::NetworkInterface(int id, int virtual_networks, GarnetNetwork *
|
|||
m_id = id;
|
||||
m_net_ptr = network_ptr;
|
||||
m_virtual_networks = virtual_networks;
|
||||
m_vc_per_vnet = NetworkConfig::getVCsPerClass();
|
||||
m_vc_per_vnet = m_net_ptr->getNetworkConfig()->getVCsPerClass();
|
||||
m_num_vcs = m_vc_per_vnet*m_virtual_networks;
|
||||
|
||||
m_vc_round_robin = 0;
|
||||
|
@ -109,7 +109,7 @@ bool NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
|
|||
NetworkMessage *net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref());
|
||||
NetDest net_msg_dest = net_msg_ptr->getInternalDestination();
|
||||
Vector<NodeID> dest_nodes = net_msg_dest.getAllDest(); // gets all the destinations associated with this message.
|
||||
int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/NetworkConfig::getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size
|
||||
int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size
|
||||
|
||||
for(int ctr = 0; ctr < dest_nodes.size(); ctr++) // loop because we will be converting all multicast messages into unicast messages
|
||||
{
|
||||
|
@ -236,7 +236,7 @@ void NetworkInterface::wakeup()
|
|||
DEBUG_EXPR(NETWORK_COMP, HighPrio, m_id);
|
||||
DEBUG_MSG(NETWORK_COMP, HighPrio, "Message got delivered");
|
||||
DEBUG_EXPR(NETWORK_COMP, HighPrio, g_eventQueue_ptr->getTime());
|
||||
if(!NetworkConfig::isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers
|
||||
if(!m_net_ptr->getNetworkConfig()->isNetworkTesting()) // When we are doing network only testing, the messages do not have to be buffered into the message buffers
|
||||
{
|
||||
outNode_ptr[t_flit->get_vnet()]->enqueue(t_flit->get_msg_ptr(), 1); // enqueueing for protocol buffer. This is not required when doing network only testing
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ NetworkLink::NetworkLink(int id, int latency, GarnetNetwork *net_ptr)
|
|||
m_link_utilized = 0;
|
||||
m_net_ptr = net_ptr;
|
||||
m_latency = latency;
|
||||
int num_net = NUMBER_OF_VIRTUAL_NETWORKS;
|
||||
int num_vc = NetworkConfig::getVCsPerClass();
|
||||
int num_net = net_ptr->getNumberOfVirtualNetworks();
|
||||
int num_vc = m_net_ptr->getNetworkConfig()->getVCsPerClass();
|
||||
m_vc_load.setSize(num_net*num_vc);
|
||||
|
||||
for(int i = 0; i < num_net*num_vc; i++)
|
||||
|
|
|
@ -43,8 +43,8 @@ Router::Router(int id, GarnetNetwork *network_ptr)
|
|||
{
|
||||
m_id = id;
|
||||
m_net_ptr = network_ptr;
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS;
|
||||
m_vc_per_vnet = NetworkConfig::getVCsPerClass();
|
||||
m_virtual_networks = m_net_ptr->getNumberOfVirtualNetworks();
|
||||
m_vc_per_vnet = m_net_ptr->getNetworkConfig()->getVCsPerClass();
|
||||
m_round_robin_inport = 0;
|
||||
m_round_robin_start = 0;
|
||||
m_num_vcs = m_vc_per_vnet*m_virtual_networks;
|
||||
|
@ -103,7 +103,7 @@ void Router::addOutPort(NetworkLink *out_link, const NetDest& routing_table_entr
|
|||
Vector<flitBuffer *> intermediateQueues;
|
||||
for(int i = 0; i < m_num_vcs; i++)
|
||||
{
|
||||
intermediateQueues.insertAtBottom(new flitBuffer(NetworkConfig::getBufferSize()));
|
||||
intermediateQueues.insertAtBottom(new flitBuffer(m_net_ptr->getNetworkConfig()->getBufferSize()));
|
||||
}
|
||||
m_router_buffers.insertAtBottom(intermediateQueues);
|
||||
|
||||
|
@ -246,17 +246,17 @@ void Router::routeCompute(flit *m_flit, int inport)
|
|||
int outport = m_in_vc_state[inport][invc]->get_outport();
|
||||
int outvc = m_in_vc_state[inport][invc]->get_outvc();
|
||||
|
||||
assert(NetworkConfig::getNumPipeStages() >= 1);
|
||||
m_flit->set_time(g_eventQueue_ptr->getTime() + (NetworkConfig::getNumPipeStages() - 1)); // Becasuse 1 cycle will be consumed in scheduling the output link
|
||||
assert(m_net_ptr->getNetworkConfig()->getNumPipeStages() >= 1);
|
||||
m_flit->set_time(g_eventQueue_ptr->getTime() + (m_net_ptr->getNetworkConfig()->getNumPipeStages() - 1)); // Becasuse 1 cycle will be consumed in scheduling the output link
|
||||
m_flit->set_vc(outvc);
|
||||
m_router_buffers[outport][outvc]->insert(m_flit);
|
||||
|
||||
if(NetworkConfig::getNumPipeStages() > 1)
|
||||
g_eventQueue_ptr->scheduleEvent(this, NetworkConfig::getNumPipeStages() -1 );
|
||||
if(m_net_ptr->getNetworkConfig()->getNumPipeStages() > 1)
|
||||
g_eventQueue_ptr->scheduleEvent(this, m_net_ptr->getNetworkConfig()->getNumPipeStages() -1 );
|
||||
if((m_flit->get_type() == HEAD_) || (m_flit->get_type() == HEAD_TAIL_))
|
||||
{
|
||||
NetDest destination = dynamic_cast<NetworkMessage*>(m_flit->get_msg_ptr().ref())->getInternalDestination();
|
||||
if(NetworkConfig::getNumPipeStages() > 1)
|
||||
if(m_net_ptr->getNetworkConfig()->getNumPipeStages() > 1)
|
||||
{
|
||||
m_out_vc_state[outport][outvc]->setState(VC_AB_, g_eventQueue_ptr->getTime() + 1);
|
||||
m_out_link[outport]->request_vc_link(outvc, destination, g_eventQueue_ptr->getTime() + 1);
|
||||
|
|
140
src/mem/ruby/network/simple/CustomTopology.cc
Normal file
140
src/mem/ruby/network/simple/CustomTopology.cc
Normal file
|
@ -0,0 +1,140 @@
|
|||
|
||||
#include "mem/ruby/network/simple/CustomTopology.hh"
|
||||
#include "mem/protocol/MachineType.hh"
|
||||
|
||||
static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
|
||||
static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above :)
|
||||
|
||||
// make a network as described by the networkFile
|
||||
void CustomTopology::construct()
|
||||
{
|
||||
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
Vector<int> bw_multis; // bw multipliers for each link extracted
|
||||
Vector<int> weights; // link weights used to enfore e-cube deadlock free routing
|
||||
Vector< SwitchID > int_network_switches; // internal switches extracted from the file
|
||||
Vector<bool> endpointConnectionExist; // used to ensure all endpoints are connected to the network
|
||||
|
||||
endpointConnectionExist.setSize(m_nodes);
|
||||
|
||||
// initialize endpoint check vector
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
endpointConnectionExist[k] = false;
|
||||
}
|
||||
|
||||
stringstream networkFile( m_connections );
|
||||
|
||||
string line = "";
|
||||
|
||||
while (!networkFile.eof()) {
|
||||
|
||||
Vector < SwitchID > nodes;
|
||||
nodes.setSize(2);
|
||||
int latency = -1; // null latency
|
||||
int weight = -1; // null weight
|
||||
int bw_multiplier = DEFAULT_BW_MULTIPLIER; // default multiplier incase the network file doesn't define it
|
||||
int i = 0; // node pair index
|
||||
int varsFound = 0; // number of varsFound on the line
|
||||
int internalNodes = 0; // used to determine if the link is between 2 internal nodes
|
||||
std::getline(networkFile, line, '\n');
|
||||
string varStr = string_split(line, ' ');
|
||||
|
||||
// parse the current line in the file
|
||||
while (varStr != "") {
|
||||
string label = string_split(varStr, ':');
|
||||
|
||||
// valid node labels
|
||||
if (label == "ext_node" || label == "int_node") {
|
||||
ASSERT(i < 2); // one link between 2 switches per line
|
||||
varsFound++;
|
||||
bool isNewIntSwitch = true;
|
||||
if (label == "ext_node") { // input link to node
|
||||
MachineType machine = string_to_MachineType(string_split(varStr, ':'));
|
||||
string nodeStr = string_split(varStr, ':');
|
||||
nodes[i] = MachineType_base_number(machine)
|
||||
+ atoi(nodeStr.c_str());
|
||||
|
||||
// in nodes should be numbered 0 to m_nodes-1
|
||||
ASSERT(nodes[i] >= 0 && nodes[i] < m_nodes);
|
||||
isNewIntSwitch = false;
|
||||
endpointConnectionExist[nodes[i]] = true;
|
||||
}
|
||||
if (label == "int_node") { // interior node
|
||||
nodes[i] = atoi((string_split(varStr, ':')).c_str())+m_nodes*2;
|
||||
// in nodes should be numbered >= m_nodes*2
|
||||
ASSERT(nodes[i] >= m_nodes*2);
|
||||
for (int k = 0; k < int_network_switches.size(); k++) {
|
||||
if (int_network_switches[k] == nodes[i]) {
|
||||
isNewIntSwitch = false;
|
||||
}
|
||||
}
|
||||
if (isNewIntSwitch) { // if internal switch
|
||||
m_number_of_switches++;
|
||||
int_network_switches.insertAtBottom(nodes[i]);
|
||||
}
|
||||
internalNodes++;
|
||||
}
|
||||
i++;
|
||||
} else if (label == "link_latency") {
|
||||
latency = atoi((string_split(varStr, ':')).c_str());
|
||||
varsFound++;
|
||||
} else if (label == "bw_multiplier") { // not necessary, defaults to DEFAULT_BW_MULTIPLIER
|
||||
bw_multiplier = atoi((string_split(varStr, ':')).c_str());
|
||||
} else if (label == "link_weight") { // not necessary, defaults to link_latency
|
||||
weight = atoi((string_split(varStr, ':')).c_str());
|
||||
} else {
|
||||
cerr << "Error: Unexpected Identifier: " << label << endl;
|
||||
exit(1);
|
||||
}
|
||||
varStr = string_split(line, ' ');
|
||||
}
|
||||
if (varsFound == 3) { // all three necessary link variables where found so add the link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
if (weight != -1) {
|
||||
weights.insertAtBottom(weight);
|
||||
} else {
|
||||
weights.insertAtBottom(latency);
|
||||
}
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
if (internalNodes == 2) { // this is an internal link
|
||||
otherDirectionNodes[1] = nodes[0];
|
||||
} else {
|
||||
otherDirectionNodes[1] = nodes[0]+m_nodes;
|
||||
}
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
if (weight != -1) {
|
||||
weights.insertAtBottom(weight);
|
||||
} else {
|
||||
weights.insertAtBottom(latency);
|
||||
}
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
} else {
|
||||
if (varsFound != 0) { // if this is not a valid link, then no vars should have been found
|
||||
cerr << "Error in line: " << line << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} // end of file
|
||||
|
||||
// makes sure all enpoints are connected in the soon to be created network
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
if (endpointConnectionExist[k] == false) {
|
||||
cerr << "Error: Unconnected Endpoint: " << k << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size() && latencies.size() == weights.size())
|
||||
for (int k = 0; k < nodePairs.size(); k++) {
|
||||
ASSERT(nodePairs[k].size() == 2);
|
||||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k], weights[k]);
|
||||
}
|
||||
|
||||
// networkFile.close();
|
||||
}
|
17
src/mem/ruby/network/simple/CustomTopology.hh
Normal file
17
src/mem/ruby/network/simple/CustomTopology.hh
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#ifndef CUSTOMTOPOLOGY_H
|
||||
#define CUSTOMTOPOLOGY_H
|
||||
|
||||
#include "mem/ruby/network/simple/Topology.hh"
|
||||
|
||||
class CustomTopology : public Topology
|
||||
{
|
||||
public:
|
||||
CustomTopology(const string & name);
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
protected:
|
||||
void construct();
|
||||
};
|
||||
|
||||
#endif
|
66
src/mem/ruby/network/simple/HierarchicalSwitchTopology.cc
Normal file
66
src/mem/ruby/network/simple/HierarchicalSwitchTopology.cc
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
#include "mem/ruby/network/simple/HierarchicalSwitchTopology.hh"
|
||||
|
||||
// hierarchical switch topology
|
||||
void Topology::construct(int fan_out_degree)
|
||||
{
|
||||
// Make a row of switches with only one input. This extra row makes
|
||||
// sure the links out of the nodes have latency and limited
|
||||
// bandwidth.
|
||||
|
||||
// number of inter-chip switches, i.e. the last row of switches
|
||||
Vector<SwitchID> last_level;
|
||||
for (int i=0; i<m_nodes; i++) {
|
||||
SwitchID new_switch = newSwitchID(); // internal switch id #
|
||||
addLink(i, new_switch, m_network_ptr->getLinkLatency());
|
||||
last_level.insertAtBottom(new_switch);
|
||||
}
|
||||
|
||||
// Create Hierarchical Switches
|
||||
|
||||
// start from the bottom level and work up to root
|
||||
Vector<SwitchID> next_level;
|
||||
while(last_level.size() > 1) {
|
||||
for (int i=0; i<last_level.size(); i++) {
|
||||
if ((i % fan_out_degree) == 0) {
|
||||
next_level.insertAtBottom(newSwitchID());
|
||||
}
|
||||
// Add this link to the last switch we created
|
||||
addLink(last_level[i], next_level[next_level.size()-1], m_network_ptr->getLinkLatency());
|
||||
}
|
||||
|
||||
// Make the current level the last level to get ready for next
|
||||
// iteration
|
||||
last_level = next_level;
|
||||
next_level.clear();
|
||||
}
|
||||
|
||||
SwitchID root_switch = last_level[0];
|
||||
|
||||
Vector<SwitchID> out_level;
|
||||
for (int i=0; i<m_nodes; i++) {
|
||||
out_level.insertAtBottom(m_nodes+i);
|
||||
}
|
||||
|
||||
// Build the down network from the endpoints to the root
|
||||
while(out_level.size() != 1) {
|
||||
|
||||
// A level of switches
|
||||
for (int i=0; i<out_level.size(); i++) {
|
||||
if ((i % fan_out_degree) == 0) {
|
||||
if (out_level.size() > fan_out_degree) {
|
||||
next_level.insertAtBottom(newSwitchID());
|
||||
} else {
|
||||
next_level.insertAtBottom(root_switch);
|
||||
}
|
||||
}
|
||||
// Add this link to the last switch we created
|
||||
addLink(next_level[next_level.size()-1], out_level[i], m_network_ptr->getLinkLatency());
|
||||
}
|
||||
|
||||
// Make the current level the last level to get ready for next
|
||||
// iteration
|
||||
out_level = next_level;
|
||||
next_level.clear();
|
||||
}
|
||||
}
|
17
src/mem/ruby/network/simple/HierarchicalSwitchTopology.hh
Normal file
17
src/mem/ruby/network/simple/HierarchicalSwitchTopology.hh
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#ifndef HIERARCHICALSWITCHTOPOLOGY_H
|
||||
#define HIERARCHICALSWITCHTOPOLOGY_H
|
||||
|
||||
#include "mem/ruby/network/simple/Topology.hh"
|
||||
|
||||
class HierarchicalSwitchTopology : public Topology
|
||||
{
|
||||
public:
|
||||
HierarchicalSwitchTopology(const string & name);
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
protected:
|
||||
void construct();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -55,7 +55,7 @@ bool operator<(const LinkOrder& l1, const LinkOrder& l2) {
|
|||
|
||||
PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr)
|
||||
{
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS; // FIXME - pass me as a parameter?
|
||||
m_virtual_networks = network_ptr->getNumberOfVirtualNetworks();
|
||||
m_switch_id = sid;
|
||||
m_round_robin_start = 0;
|
||||
m_network_ptr = network_ptr;
|
||||
|
@ -88,9 +88,9 @@ void PerfectSwitch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest&
|
|||
m_out.insertAtBottom(out);
|
||||
m_routing_table.insertAtBottom(routing_table_entry);
|
||||
|
||||
if (g_PRINT_TOPOLOGY) {
|
||||
// if (RubyConfig::getPrintTopology()) {
|
||||
m_out_link_vec.insertAtBottom(out);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void PerfectSwitch::clearRoutingTables()
|
||||
|
@ -134,6 +134,7 @@ void PerfectSwitch::wakeup()
|
|||
int highest_prio_vnet = m_virtual_networks-1;
|
||||
int lowest_prio_vnet = 0;
|
||||
int decrementer = 1;
|
||||
bool schedule_wakeup = false;
|
||||
NetworkMessage* net_msg_ptr = NULL;
|
||||
|
||||
// invert priorities to avoid starvation seen in the component network
|
||||
|
@ -186,8 +187,9 @@ void PerfectSwitch::wakeup()
|
|||
|
||||
assert(m_link_order.size() == m_routing_table.size());
|
||||
assert(m_link_order.size() == m_out.size());
|
||||
|
||||
if (g_adaptive_routing) {
|
||||
//changed by SS
|
||||
// if (RubyConfig::getAdaptiveRouting()) {
|
||||
if (m_network_ptr->getAdaptiveRouting()) {
|
||||
if (m_network_ptr->isVNetOrdered(vnet)) {
|
||||
// Don't adaptively route
|
||||
for (int outlink=0; outlink<m_out.size(); outlink++) {
|
||||
|
|
82
src/mem/ruby/network/simple/PtToPtTopology.cc
Normal file
82
src/mem/ruby/network/simple/PtToPtTopology.cc
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
#include "mem/protocol/MachineType.hh"
|
||||
#include "mem/ruby/network/simple/PtToPtTopology.hh"
|
||||
|
||||
// one internal node per chip, point to point links between chips
|
||||
void PtToPtTopology::construct()
|
||||
{
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
Vector<int> bw_multis; // bw multipliers for each link extracted
|
||||
|
||||
Vector < SwitchID > nodes;
|
||||
nodes.setSize(2);
|
||||
|
||||
// number of inter-chip switches
|
||||
int numberOfChipSwitches = m_nodes/MachineType_base_level(MachineType_NUM);
|
||||
// two switches per machine node grouping
|
||||
// one intra-chip switch and one inter-chip switch per chip
|
||||
for(int i=0; i<numberOfChipSwitches; i++){
|
||||
SwitchID new_switch = newSwitchID();
|
||||
new_switch = newSwitchID();
|
||||
}
|
||||
|
||||
makeSwitchesPerChip(nodePairs, latencies, bw_multis, numberOfChipSwitches);
|
||||
|
||||
// connect intra-chip switch to inter-chip switch
|
||||
for (int chip = 0; chip < RubyConfig::getNumberOfChips(); chip++) {
|
||||
|
||||
int latency = m_network_ptr->getOnChipLinkLatency(); // internal link latency
|
||||
int bw_multiplier = 10; // external link bw multiplier of the global bandwidth
|
||||
|
||||
nodes[0] = chip+m_nodes*2;
|
||||
nodes[1] = chip+m_nodes*2+RubyConfig::getNumberOfChips();
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0];
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
}
|
||||
|
||||
// point-to-point network between chips
|
||||
for (int chip = 0; chip < RubyConfig::getNumberOfChips(); chip++) {
|
||||
for (int other_chip = chip+1; other_chip < RubyConfig::getNumberOfChips(); other_chip++) {
|
||||
|
||||
int latency = m_network_ptr->getOffChipLinkLatency(); // external link latency
|
||||
int bw_multiplier = 1; // external link bw multiplier of the global bandwidth
|
||||
|
||||
nodes[0] = chip+m_nodes*2+RubyConfig::getNumberOfChips();
|
||||
nodes[1] = other_chip+m_nodes*2+RubyConfig::getNumberOfChips();
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0];
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
// add links
|
||||
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size())
|
||||
for (int k = 0; k < nodePairs.size(); k++) {
|
||||
ASSERT(nodePairs[k].size() == 2);
|
||||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]);
|
||||
}
|
||||
}
|
17
src/mem/ruby/network/simple/PtToPtTopology.hh
Normal file
17
src/mem/ruby/network/simple/PtToPtTopology.hh
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#ifndef PTTOPTTOPOLOGY_H
|
||||
#define PTTOPTTOPOLOGY_H
|
||||
|
||||
#include "mem/ruby/network/simple/Topology.hh"
|
||||
|
||||
class PtToPtTopology : public Topology
|
||||
{
|
||||
public:
|
||||
PtToPtTopology(const string & name);
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
protected:
|
||||
void construct();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -59,11 +59,55 @@ Network* Network::createNetwork(int nodes)
|
|||
}
|
||||
*/
|
||||
|
||||
SimpleNetwork::SimpleNetwork(const string & name)
|
||||
: Network(name)
|
||||
{
|
||||
m_virtual_networks = 0;
|
||||
m_topology_ptr = NULL;
|
||||
}
|
||||
|
||||
void SimpleNetwork::init(const vector<string> & argv)
|
||||
{
|
||||
|
||||
Network::init(argv);
|
||||
|
||||
m_endpoint_switches.setSize(m_nodes);
|
||||
|
||||
m_in_use.setSize(m_virtual_networks);
|
||||
m_ordered.setSize(m_virtual_networks);
|
||||
for (int i = 0; i < m_virtual_networks; i++) {
|
||||
m_in_use[i] = false;
|
||||
m_ordered[i] = false;
|
||||
}
|
||||
|
||||
// Allocate to and from queues
|
||||
m_toNetQueues.setSize(m_nodes);
|
||||
m_fromNetQueues.setSize(m_nodes);
|
||||
for (int node = 0; node < m_nodes; node++) {
|
||||
m_toNetQueues[node].setSize(m_virtual_networks);
|
||||
m_fromNetQueues[node].setSize(m_virtual_networks);
|
||||
for (int j = 0; j < m_virtual_networks; j++) {
|
||||
cerr << "Creating new MessageBuffer for " << node << " " << j << endl;
|
||||
m_toNetQueues[node][j] = new MessageBuffer;
|
||||
m_fromNetQueues[node][j] = new MessageBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the network switches
|
||||
// m_topology_ptr = new Topology(this, m_nodes);
|
||||
m_topology_ptr->makeTopology();
|
||||
int number_of_switches = m_topology_ptr->numSwitches();
|
||||
for (int i=0; i<number_of_switches; i++) {
|
||||
m_switch_ptr_vector.insertAtBottom(new Switch(i, this));
|
||||
}
|
||||
m_topology_ptr->createLinks(false); // false because this isn't a reconfiguration
|
||||
}
|
||||
/*
|
||||
SimpleNetwork::SimpleNetwork(int nodes)
|
||||
{
|
||||
m_nodes = MachineType_base_number(MachineType_NUM);
|
||||
|
||||
m_virtual_networks = NUMBER_OF_VIRTUAL_NETWORKS;
|
||||
m_virtual_networks = RubyConfig::getNumberOfVirtualNetworks();
|
||||
m_endpoint_switches.setSize(m_nodes);
|
||||
|
||||
m_in_use.setSize(m_virtual_networks);
|
||||
|
@ -93,7 +137,7 @@ SimpleNetwork::SimpleNetwork(int nodes)
|
|||
}
|
||||
m_topology_ptr->createLinks(false); // false because this isn't a reconfiguration
|
||||
}
|
||||
|
||||
*/
|
||||
void SimpleNetwork::reset()
|
||||
{
|
||||
for (int node = 0; node < m_nodes; node++) {
|
||||
|
@ -154,8 +198,8 @@ void SimpleNetwork::makeInternalLink(SwitchID src, SwitchID dest, const NetDest&
|
|||
// allocate a buffer
|
||||
MessageBuffer* buffer_ptr = new MessageBuffer;
|
||||
buffer_ptr->setOrdering(true);
|
||||
if(FINITE_BUFFERING) {
|
||||
buffer_ptr->setSize(FINITE_BUFFER_SIZE);
|
||||
if (m_buffer_size > 0) {
|
||||
buffer_ptr->setSize(m_buffer_size);
|
||||
}
|
||||
queues.insertAtBottom(buffer_ptr);
|
||||
// remember to deallocate it
|
||||
|
@ -225,7 +269,7 @@ void SimpleNetwork::printConfig(ostream& out) const
|
|||
out << "Network Configuration" << endl;
|
||||
out << "---------------------" << endl;
|
||||
out << "network: SIMPLE_NETWORK" << endl;
|
||||
out << "topology: " << g_NETWORK_TOPOLOGY << endl;
|
||||
out << "topology: " << m_topology_ptr->getName() << endl;
|
||||
out << endl;
|
||||
|
||||
for (int i = 0; i < m_virtual_networks; i++) {
|
||||
|
@ -246,9 +290,7 @@ void SimpleNetwork::printConfig(ostream& out) const
|
|||
m_switch_ptr_vector[i]->printConfig(out);
|
||||
}
|
||||
|
||||
if (g_PRINT_TOPOLOGY) {
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
m_topology_ptr->printConfig(out);
|
||||
}
|
||||
|
||||
void SimpleNetwork::print(ostream& out) const
|
||||
|
|
|
@ -83,11 +83,14 @@ class Topology;
|
|||
class SimpleNetwork : public Network {
|
||||
public:
|
||||
// Constructors
|
||||
SimpleNetwork(int nodes);
|
||||
// SimpleNetwork(int nodes);
|
||||
SimpleNetwork(const string & name);
|
||||
|
||||
// Destructor
|
||||
~SimpleNetwork();
|
||||
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
// Public Methods
|
||||
void printStats(ostream& out) const;
|
||||
void clearStats();
|
||||
|
@ -130,14 +133,11 @@ private:
|
|||
Vector<Vector<MessageBuffer*> > m_toNetQueues;
|
||||
Vector<Vector<MessageBuffer*> > m_fromNetQueues;
|
||||
|
||||
int m_nodes;
|
||||
int m_virtual_networks;
|
||||
Vector<bool> m_in_use;
|
||||
Vector<bool> m_ordered;
|
||||
Vector<Switch*> m_switch_ptr_vector;
|
||||
Vector<MessageBuffer*> m_buffers_to_free;
|
||||
Vector<Switch*> m_endpoint_switches;
|
||||
Topology* m_topology_ptr;
|
||||
};
|
||||
|
||||
// Output operator declaration
|
||||
|
|
|
@ -82,8 +82,9 @@ void Switch::addOutPort(const Vector<MessageBuffer*>& out, const NetDest& routin
|
|||
MessageBuffer* buffer_ptr = new MessageBuffer;
|
||||
// Make these queues ordered
|
||||
buffer_ptr->setOrdering(true);
|
||||
if(FINITE_BUFFERING) {
|
||||
buffer_ptr->setSize(FINITE_BUFFER_SIZE);
|
||||
Network* net_ptr = RubySystem::getNetwork();
|
||||
if(net_ptr->getBufferSize() > 0) {
|
||||
buffer_ptr->setSize(net_ptr->getBufferSize());
|
||||
}
|
||||
intermediateBuffers.insertAtBottom(buffer_ptr);
|
||||
m_buffers_to_free.insertAtBottom(buffer_ptr);
|
||||
|
|
|
@ -52,6 +52,7 @@ class PerfectSwitch;
|
|||
class NetDest;
|
||||
class SimpleNetwork;
|
||||
class Throttle;
|
||||
class Network;
|
||||
|
||||
class Switch {
|
||||
public:
|
||||
|
@ -83,6 +84,7 @@ private:
|
|||
|
||||
// Data Members (m_ prefix)
|
||||
PerfectSwitch* m_perfect_switch_ptr;
|
||||
Network* m_network_ptr;
|
||||
Vector<Throttle*> m_throttles;
|
||||
Vector<MessageBuffer*> m_buffers_to_free;
|
||||
SwitchID m_switch_id;
|
||||
|
|
|
@ -103,9 +103,9 @@ void Throttle::addLinks(const Vector<MessageBuffer*>& in_vec, const Vector<Messa
|
|||
}
|
||||
}
|
||||
|
||||
if (g_PRINT_TOPOLOGY) {
|
||||
// if (RubyConfig::getPrintTopology()) {
|
||||
m_out_link_vec.insertAtBottom(out_vec);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void Throttle::addVirtualNetwork(MessageBuffer* in_ptr, MessageBuffer* out_ptr)
|
||||
|
@ -206,13 +206,8 @@ void Throttle::wakeup()
|
|||
while ((current_time - m_last_bandwidth_sample) > ADJUST_INTERVAL) {
|
||||
double utilization = m_bandwidth_since_sample/double(ADJUST_INTERVAL * getLinkBandwidth());
|
||||
|
||||
if (utilization > g_bash_bandwidth_adaptive_threshold) {
|
||||
// Used more bandwidth
|
||||
m_bash_counter++;
|
||||
} else {
|
||||
// Used less bandwidth
|
||||
m_bash_counter--;
|
||||
}
|
||||
// Used less bandwidth
|
||||
m_bash_counter--;
|
||||
|
||||
// Make sure we don't overflow
|
||||
m_bash_counter = min(HIGH_RANGE, m_bash_counter);
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
#include "mem/gems_common/Vector.hh"
|
||||
#include "mem/ruby/common/Consumer.hh"
|
||||
#include "mem/ruby/system/NodeID.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "mem/ruby/network/Network.hh"
|
||||
|
||||
class MessageBuffer;
|
||||
|
||||
|
@ -68,7 +69,7 @@ public:
|
|||
void clearStats();
|
||||
void printConfig(ostream& out) const;
|
||||
double getUtilization() const; // The average utilization (a percent) since last clearStats()
|
||||
int getLinkBandwidth() const { return g_endpoint_bandwidth * m_link_bandwidth_multiplier; }
|
||||
int getLinkBandwidth() const { return RubySystem::getNetwork()->getEndpointBandwidth() * m_link_bandwidth_multiplier; }
|
||||
int getLatency() const { return m_link_latency; }
|
||||
|
||||
const Vector<Vector<int> >& getCounters() const { return m_message_counters; }
|
||||
|
|
|
@ -40,10 +40,11 @@
|
|||
#include "mem/ruby/common/NetDest.hh"
|
||||
#include "mem/ruby/network/Network.hh"
|
||||
#include "mem/protocol/TopologyType.hh"
|
||||
#include "mem/ruby/config/RubyConfig.hh"
|
||||
//#include "mem/ruby/config/RubyConfig.hh"
|
||||
#include "mem/gems_common/util.hh"
|
||||
#include "mem/protocol/MachineType.hh"
|
||||
#include "mem/protocol/Protocol.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include <string>
|
||||
|
||||
static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
|
||||
|
@ -57,359 +58,45 @@ static const int DEFAULT_BW_MULTIPLIER = 1; // Just to be consistent with above
|
|||
// of the network.
|
||||
|
||||
// Helper functions based on chapter 29 of Cormen et al.
|
||||
static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches);
|
||||
static Matrix extend_shortest_path(const Matrix& current_dist, Matrix& latencies, Matrix& inter_switches);
|
||||
static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches);
|
||||
static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist);
|
||||
static NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist);
|
||||
|
||||
|
||||
Topology::Topology(Network* network_ptr, int number_of_nodes)
|
||||
Topology::Topology(const string & name)
|
||||
: m_name(name)
|
||||
{
|
||||
m_network_ptr = network_ptr;
|
||||
m_nodes = number_of_nodes;
|
||||
m_network_ptr = NULL;
|
||||
m_nodes = MachineType_base_number(MachineType_NUM);
|
||||
m_number_of_switches = 0;
|
||||
init();
|
||||
}
|
||||
|
||||
void Topology::init()
|
||||
void Topology::init(const vector<string> & argv)
|
||||
{
|
||||
for (size_t i=0; i<argv.size(); i+=2) {
|
||||
if (argv[i] == "network")
|
||||
m_network_ptr = RubySystem::getNetwork();
|
||||
else if (argv[i] == "connections")
|
||||
m_connections = argv[i+1];
|
||||
else if (argv[i] == "print_config") {
|
||||
m_print_config = string_to_bool(argv[i+1]);
|
||||
cerr << "print config: " << m_print_config << endl;
|
||||
}
|
||||
}
|
||||
assert(m_network_ptr != NULL);
|
||||
}
|
||||
|
||||
void Topology::makeTopology()
|
||||
{
|
||||
/*
|
||||
if (m_nodes == 1) {
|
||||
SwitchID id = newSwitchID();
|
||||
addLink(0, id, NETWORK_LINK_LATENCY);
|
||||
addLink(id, 1, NETWORK_LINK_LATENCY);
|
||||
addLink(0, id, m_network_ptr->getOffChipLinkLatency());
|
||||
addLink(id, 1, m_network_ptr->getOffChipLinkLatency());
|
||||
return;
|
||||
}
|
||||
|
||||
// topology-specific set-up
|
||||
TopologyType topology = string_to_TopologyType(g_NETWORK_TOPOLOGY);
|
||||
switch (topology) {
|
||||
case TopologyType_TORUS_2D:
|
||||
make2DTorus();
|
||||
break;
|
||||
case TopologyType_HIERARCHICAL_SWITCH:
|
||||
makeHierarchicalSwitch(FAN_OUT_DEGREE);
|
||||
break;
|
||||
case TopologyType_CROSSBAR:
|
||||
makeHierarchicalSwitch(1024);
|
||||
break;
|
||||
case TopologyType_PT_TO_PT:
|
||||
makePtToPt();
|
||||
break;
|
||||
case TopologyType_FILE_SPECIFIED:
|
||||
makeFileSpecified();
|
||||
break;
|
||||
default:
|
||||
ERROR_MSG("Unexpected typology type")
|
||||
}
|
||||
|
||||
// initialize component latencies record
|
||||
m_component_latencies.setSize(0);
|
||||
m_component_inter_switches.setSize(0);
|
||||
}
|
||||
|
||||
void Topology::makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChipSwitches)
|
||||
{
|
||||
|
||||
Vector < SwitchID > nodes; // temporary buffer
|
||||
nodes.setSize(2);
|
||||
|
||||
Vector<bool> endpointConnectionExist; // used to ensure all endpoints are connected to the network
|
||||
endpointConnectionExist.setSize(m_nodes);
|
||||
// initialize endpoint check vector
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
endpointConnectionExist[k] = false;
|
||||
}
|
||||
|
||||
Vector<int> componentCount;
|
||||
componentCount.setSize(MachineType_NUM);
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
componentCount[mType] = 0;
|
||||
}
|
||||
|
||||
// components to/from network links
|
||||
for (int chip = 0; chip < RubyConfig::numberOfChips(); chip++) {
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
for (int component = 0; component < MachineType_chip_count(mType, chip); component++) {
|
||||
|
||||
int latency = -1;
|
||||
int bw_multiplier = -1; // internal link bw multiplier of the global bandwidth
|
||||
if (mType != MachineType_Directory) {
|
||||
latency = ON_CHIP_LINK_LATENCY; // internal link latency
|
||||
bw_multiplier = 10; // internal link bw multiplier of the global bandwidth
|
||||
} else {
|
||||
latency = NETWORK_LINK_LATENCY; // local memory latency
|
||||
bw_multiplier = 1; // local memory link bw multiplier of the global bandwidth
|
||||
}
|
||||
nodes[0] = MachineType_base_number(mType)+componentCount[mType];
|
||||
nodes[1] = chip+m_nodes*2; // this is the chip's internal switch id #
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
//bw_multis.insertAtBottom(bw_multiplier);
|
||||
bw_multis.insertAtBottom(componentCount[mType]+MachineType_base_number((MachineType)mType));
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0]+m_nodes;
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
assert(!endpointConnectionExist[nodes[0]]);
|
||||
endpointConnectionExist[nodes[0]] = true;
|
||||
componentCount[mType]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure all enpoints are connected in the soon to be created network
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
if (endpointConnectionExist[k] == false) {
|
||||
cerr << "Error: Unconnected Endpoint: " << k << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// secondary check to ensure we saw the correct machine counts
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
assert(componentCount[mType] == MachineType_base_count((MachineType)mType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 2D torus topology
|
||||
|
||||
void Topology::make2DTorus()
|
||||
{
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
Vector<int> bw_multis; // bw multipliers for each link extracted
|
||||
|
||||
Vector < SwitchID > nodes; // temporary buffer
|
||||
nodes.setSize(2);
|
||||
|
||||
// number of inter-chip switches
|
||||
int numberOfTorusSwitches = m_nodes/MachineType_base_level(MachineType_NUM);
|
||||
// one switch per machine node grouping
|
||||
Vector<SwitchID> torusSwitches;
|
||||
for(int i=0; i<numberOfTorusSwitches; i++){
|
||||
SwitchID new_switch = newSwitchID();
|
||||
torusSwitches.insertAtBottom(new_switch);
|
||||
}
|
||||
|
||||
makeSwitchesPerChip(nodePairs, latencies, bw_multis, numberOfTorusSwitches);
|
||||
|
||||
int lengthOfSide = (int)sqrt((double)numberOfTorusSwitches);
|
||||
|
||||
// Now connect the inter-chip torus links
|
||||
|
||||
int latency = NETWORK_LINK_LATENCY; // external link latency
|
||||
int bw_multiplier = 1; // external link bw multiplier of the global bandwidth
|
||||
|
||||
for(int i=0; i<numberOfTorusSwitches; i++){
|
||||
nodes[0] = torusSwitches[i]; // current switch
|
||||
|
||||
// left
|
||||
if(nodes[0]%lengthOfSide == 0){ // determine left neighbor
|
||||
nodes[1] = nodes[0] - 1 + lengthOfSide;
|
||||
} else {
|
||||
nodes[1] = nodes[0] - 1;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// right
|
||||
if((nodes[0] + 1)%lengthOfSide == 0){ // determine right neighbor
|
||||
nodes[1] = nodes[0] + 1 - lengthOfSide;
|
||||
} else {
|
||||
nodes[1] = nodes[0] + 1;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// top
|
||||
if(nodes[0] - lengthOfSide < 2*m_nodes){ // determine if node is on the top
|
||||
nodes[1] = nodes[0] - lengthOfSide + (lengthOfSide*lengthOfSide);
|
||||
} else {
|
||||
nodes[1] = nodes[0] - lengthOfSide;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// bottom
|
||||
if(nodes[0] + lengthOfSide >= 2*m_nodes+numberOfTorusSwitches){ // determine if node is on the bottom
|
||||
// sorin: bad bug if this is a > instead of a >=
|
||||
nodes[1] = nodes[0] + lengthOfSide - (lengthOfSide*lengthOfSide);
|
||||
} else {
|
||||
nodes[1] = nodes[0] + lengthOfSide;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
}
|
||||
|
||||
// add links
|
||||
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size())
|
||||
for (int k = 0; k < nodePairs.size(); k++) {
|
||||
ASSERT(nodePairs[k].size() == 2);
|
||||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// hierarchical switch topology
|
||||
void Topology::makeHierarchicalSwitch(int fan_out_degree)
|
||||
{
|
||||
// Make a row of switches with only one input. This extra row makes
|
||||
// sure the links out of the nodes have latency and limited
|
||||
// bandwidth.
|
||||
|
||||
// number of inter-chip switches, i.e. the last row of switches
|
||||
Vector<SwitchID> last_level;
|
||||
for (int i=0; i<m_nodes; i++) {
|
||||
SwitchID new_switch = newSwitchID(); // internal switch id #
|
||||
addLink(i, new_switch, NETWORK_LINK_LATENCY);
|
||||
last_level.insertAtBottom(new_switch);
|
||||
}
|
||||
|
||||
// Create Hierarchical Switches
|
||||
|
||||
// start from the bottom level and work up to root
|
||||
Vector<SwitchID> next_level;
|
||||
while(last_level.size() > 1) {
|
||||
for (int i=0; i<last_level.size(); i++) {
|
||||
if ((i % fan_out_degree) == 0) {
|
||||
next_level.insertAtBottom(newSwitchID());
|
||||
}
|
||||
// Add this link to the last switch we created
|
||||
addLink(last_level[i], next_level[next_level.size()-1], NETWORK_LINK_LATENCY);
|
||||
}
|
||||
|
||||
// Make the current level the last level to get ready for next
|
||||
// iteration
|
||||
last_level = next_level;
|
||||
next_level.clear();
|
||||
}
|
||||
|
||||
SwitchID root_switch = last_level[0];
|
||||
|
||||
Vector<SwitchID> out_level;
|
||||
for (int i=0; i<m_nodes; i++) {
|
||||
out_level.insertAtBottom(m_nodes+i);
|
||||
}
|
||||
|
||||
// Build the down network from the endpoints to the root
|
||||
while(out_level.size() != 1) {
|
||||
|
||||
// A level of switches
|
||||
for (int i=0; i<out_level.size(); i++) {
|
||||
if ((i % fan_out_degree) == 0) {
|
||||
if (out_level.size() > fan_out_degree) {
|
||||
next_level.insertAtBottom(newSwitchID());
|
||||
} else {
|
||||
next_level.insertAtBottom(root_switch);
|
||||
}
|
||||
}
|
||||
// Add this link to the last switch we created
|
||||
addLink(next_level[next_level.size()-1], out_level[i], NETWORK_LINK_LATENCY);
|
||||
}
|
||||
|
||||
// Make the current level the last level to get ready for next
|
||||
// iteration
|
||||
out_level = next_level;
|
||||
next_level.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// one internal node per chip, point to point links between chips
|
||||
void Topology::makePtToPt()
|
||||
{
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
Vector<int> bw_multis; // bw multipliers for each link extracted
|
||||
|
||||
Vector < SwitchID > nodes;
|
||||
nodes.setSize(2);
|
||||
|
||||
// number of inter-chip switches
|
||||
int numberOfChipSwitches = m_nodes/MachineType_base_level(MachineType_NUM);
|
||||
// two switches per machine node grouping
|
||||
// one intra-chip switch and one inter-chip switch per chip
|
||||
for(int i=0; i<numberOfChipSwitches; i++){
|
||||
SwitchID new_switch = newSwitchID();
|
||||
new_switch = newSwitchID();
|
||||
}
|
||||
|
||||
makeSwitchesPerChip(nodePairs, latencies, bw_multis, numberOfChipSwitches);
|
||||
|
||||
// connect intra-chip switch to inter-chip switch
|
||||
for (int chip = 0; chip < RubyConfig::numberOfChips(); chip++) {
|
||||
|
||||
int latency = ON_CHIP_LINK_LATENCY; // internal link latency
|
||||
int bw_multiplier = 10; // external link bw multiplier of the global bandwidth
|
||||
|
||||
nodes[0] = chip+m_nodes*2;
|
||||
nodes[1] = chip+m_nodes*2+RubyConfig::numberOfChips();
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0];
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
}
|
||||
|
||||
// point-to-point network between chips
|
||||
for (int chip = 0; chip < RubyConfig::numberOfChips(); chip++) {
|
||||
for (int other_chip = chip+1; other_chip < RubyConfig::numberOfChips(); other_chip++) {
|
||||
|
||||
int latency = NETWORK_LINK_LATENCY; // external link latency
|
||||
int bw_multiplier = 1; // external link bw multiplier of the global bandwidth
|
||||
|
||||
nodes[0] = chip+m_nodes*2+RubyConfig::numberOfChips();
|
||||
nodes[1] = other_chip+m_nodes*2+RubyConfig::numberOfChips();
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0];
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
// add links
|
||||
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size())
|
||||
for (int k = 0; k < nodePairs.size(); k++) {
|
||||
ASSERT(nodePairs[k].size() == 2);
|
||||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// make a network as described by the networkFile
|
||||
void Topology::makeFileSpecified()
|
||||
{
|
||||
*/
|
||||
assert(m_nodes > 1);
|
||||
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
|
@ -425,21 +112,7 @@ void Topology::makeFileSpecified()
|
|||
endpointConnectionExist[k] = false;
|
||||
}
|
||||
|
||||
string filename = "network/simple/Network_Files/";
|
||||
filename = filename+g_CACHE_DESIGN
|
||||
+"_Procs-"+int_to_string(RubyConfig::numberOfProcessors())
|
||||
+"_ProcsPerChip-"+int_to_string(RubyConfig::numberOfProcsPerChip())
|
||||
+"_L2Banks-"+int_to_string(RubyConfig::numberOfL2Cache())
|
||||
+"_Memories-"+int_to_string(RubyConfig::numberOfMemories())
|
||||
+".txt";
|
||||
|
||||
ifstream networkFile( filename.c_str() , ios::in);
|
||||
if (!networkFile.is_open()) {
|
||||
cerr << "Error: Could not open network file: " << filename << endl;
|
||||
cerr << "Probably no network file exists for " << RubyConfig::numberOfProcessors()
|
||||
<< " processors and " << RubyConfig::numberOfProcsPerChip() << " procs per chip " << endl;
|
||||
exit(1);
|
||||
}
|
||||
stringstream networkFile( m_connections );
|
||||
|
||||
string line = "";
|
||||
|
||||
|
@ -468,14 +141,9 @@ void Topology::makeFileSpecified()
|
|||
if (label == "ext_node") { // input link to node
|
||||
MachineType machine = string_to_MachineType(string_split(varStr, ':'));
|
||||
string nodeStr = string_split(varStr, ':');
|
||||
if (string_split(varStr, ':') == "bank") {
|
||||
nodes[i] = MachineType_base_number(machine)
|
||||
+ atoi(nodeStr.c_str())
|
||||
+ atoi((string_split(varStr, ':')).c_str())*RubyConfig::numberOfChips();
|
||||
} else {
|
||||
nodes[i] = MachineType_base_number(machine)
|
||||
+ atoi(nodeStr.c_str());
|
||||
}
|
||||
nodes[i] = MachineType_base_number(machine)
|
||||
+ atoi(nodeStr.c_str());
|
||||
|
||||
// in nodes should be numbered 0 to m_nodes-1
|
||||
ASSERT(nodes[i] >= 0 && nodes[i] < m_nodes);
|
||||
isNewIntSwitch = false;
|
||||
|
@ -504,16 +172,6 @@ void Topology::makeFileSpecified()
|
|||
bw_multiplier = atoi((string_split(varStr, ':')).c_str());
|
||||
} else if (label == "link_weight") { // not necessary, defaults to link_latency
|
||||
weight = atoi((string_split(varStr, ':')).c_str());
|
||||
} else if (label == "processors") {
|
||||
ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfProcessors());
|
||||
} else if (label == "bw_unit") {
|
||||
ASSERT(atoi((string_split(varStr, ':')).c_str()) == g_endpoint_bandwidth);
|
||||
} else if (label == "procs_per_chip") {
|
||||
ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfProcsPerChip());
|
||||
} else if (label == "L2banks") {
|
||||
ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfL2Cache());
|
||||
} else if (label == "memories") {
|
||||
ASSERT(atoi((string_split(varStr, ':')).c_str()) == RubyConfig::numberOfMemories());
|
||||
} else {
|
||||
cerr << "Error: Unexpected Identifier: " << label << endl;
|
||||
exit(1);
|
||||
|
@ -567,9 +225,12 @@ void Topology::makeFileSpecified()
|
|||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k], weights[k]);
|
||||
}
|
||||
|
||||
networkFile.close();
|
||||
// initialize component latencies record
|
||||
m_component_latencies.setSize(0);
|
||||
m_component_inter_switches.setSize(0);
|
||||
}
|
||||
|
||||
|
||||
void Topology::createLinks(bool isReconfiguration)
|
||||
{
|
||||
// Find maximum switchID
|
||||
|
@ -633,6 +294,82 @@ void Topology::createLinks(bool isReconfiguration)
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
void Topology::makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChipSwitches)
|
||||
{
|
||||
|
||||
Vector < SwitchID > nodes; // temporary buffer
|
||||
nodes.setSize(2);
|
||||
|
||||
Vector<bool> endpointConnectionExist; // used to ensure all endpoints are connected to the network
|
||||
endpointConnectionExist.setSize(m_nodes);
|
||||
// initialize endpoint check vector
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
endpointConnectionExist[k] = false;
|
||||
}
|
||||
|
||||
Vector<int> componentCount;
|
||||
componentCount.setSize(MachineType_NUM);
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
componentCount[mType] = 0;
|
||||
}
|
||||
|
||||
// components to/from network links
|
||||
// TODO: drh5: bring back chips!!!
|
||||
for (int chip = 0; chip < RubyConfig::getNumberOfChips(); chip++) {
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
for (int component = 0; component < MachineType_base_count(mType); component++) {
|
||||
|
||||
int latency = -1;
|
||||
int bw_multiplier = -1; // internal link bw multiplier of the global bandwidth
|
||||
if (mType != MachineType_Directory) {
|
||||
latency = RubyConfig::getOnChipLinkLatency(); // internal link latency
|
||||
bw_multiplier = 10; // internal link bw multiplier of the global bandwidth
|
||||
} else {
|
||||
latency = RubyConfig::getNetworkLinkLatency(); // local memory latency
|
||||
bw_multiplier = 1; // local memory link bw multiplier of the global bandwidth
|
||||
}
|
||||
nodes[0] = MachineType_base_number(mType)+componentCount[mType];
|
||||
nodes[1] = chip+m_nodes*2; // this is the chip's internal switch id #
|
||||
|
||||
// insert link
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
//bw_multis.insertAtBottom(componentCount[mType]+MachineType_base_number((MachineType)mType));
|
||||
|
||||
// opposite direction link
|
||||
Vector < SwitchID > otherDirectionNodes;
|
||||
otherDirectionNodes.setSize(2);
|
||||
otherDirectionNodes[0] = nodes[1];
|
||||
otherDirectionNodes[1] = nodes[0]+m_nodes;
|
||||
nodePairs.insertAtBottom(otherDirectionNodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
assert(!endpointConnectionExist[nodes[0]]);
|
||||
endpointConnectionExist[nodes[0]] = true;
|
||||
componentCount[mType]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure all enpoints are connected in the soon to be created network
|
||||
for (int k = 0; k < endpointConnectionExist.size(); k++) {
|
||||
if (endpointConnectionExist[k] == false) {
|
||||
cerr << "Error: Unconnected Endpoint: " << k << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// secondary check to ensure we saw the correct machine counts
|
||||
for (MachineType mType = MachineType_FIRST; mType < MachineType_NUM; ++mType) {
|
||||
assert(componentCount[mType] == MachineType_base_count((MachineType)mType));
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
SwitchID Topology::newSwitchID()
|
||||
{
|
||||
|
@ -680,6 +417,8 @@ void Topology::makeLink(SwitchID src, SwitchID dest, const NetDest& routing_tabl
|
|||
|
||||
void Topology::printConfig(ostream& out) const
|
||||
{
|
||||
if (m_print_config == false) return;
|
||||
|
||||
assert(m_component_latencies.size() > 0);
|
||||
|
||||
out << "--- Begin Topology Print ---" << endl;
|
||||
|
|
|
@ -59,21 +59,26 @@ typedef Vector < Vector <int> > Matrix;
|
|||
class Topology {
|
||||
public:
|
||||
// Constructors
|
||||
Topology(Network* network_ptr, int number_of_nodes);
|
||||
// Topology(Network* network_ptr, int number_of_nodes);
|
||||
Topology(const string & name);
|
||||
|
||||
// Destructor
|
||||
~Topology() {}
|
||||
virtual ~Topology() {}
|
||||
|
||||
virtual void init(const vector<string> & argv);
|
||||
|
||||
// Public Methods
|
||||
void makeTopology();
|
||||
int numSwitches() const { return m_number_of_switches; }
|
||||
void createLinks(bool isReconfiguration);
|
||||
|
||||
const string getName() { return m_name; }
|
||||
void printStats(ostream& out) const {}
|
||||
void clearStats() {}
|
||||
void printConfig(ostream& out) const;
|
||||
void print(ostream& out) const { out << "[Topology]"; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
// Private Methods
|
||||
void init();
|
||||
SwitchID newSwitchID();
|
||||
|
@ -82,12 +87,7 @@ private:
|
|||
void addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight);
|
||||
void makeLink(SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int weight, int bw_multiplier, bool isReconfiguration);
|
||||
|
||||
void makeHierarchicalSwitch(int fan_out_degree);
|
||||
void make2DTorus();
|
||||
void makePtToPt();
|
||||
void makeFileSpecified();
|
||||
|
||||
void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
|
||||
// void makeSwitchesPerChip(Vector< Vector < SwitchID > > &nodePairs, Vector<int> &latencies, Vector<int> &bw_multis, int numberOfChips);
|
||||
|
||||
string getDesignStr();
|
||||
// Private copy constructor and assignment operator
|
||||
|
@ -95,7 +95,10 @@ private:
|
|||
Topology& operator=(const Topology& obj);
|
||||
|
||||
// Data Members (m_ prefix)
|
||||
string m_name;
|
||||
bool m_print_config;
|
||||
Network* m_network_ptr;
|
||||
string m_connections;
|
||||
NodeID m_nodes;
|
||||
int m_number_of_switches;
|
||||
|
||||
|
|
84
src/mem/ruby/network/simple/Torus2DTopology.cc
Normal file
84
src/mem/ruby/network/simple/Torus2DTopology.cc
Normal file
|
@ -0,0 +1,84 @@
|
|||
|
||||
// 2D torus topology
|
||||
|
||||
void Torus2DTopology::construct()
|
||||
{
|
||||
Vector< Vector < SwitchID > > nodePairs; // node pairs extracted from the file
|
||||
Vector<int> latencies; // link latencies for each link extracted
|
||||
Vector<int> bw_multis; // bw multipliers for each link extracted
|
||||
|
||||
Vector < SwitchID > nodes; // temporary buffer
|
||||
nodes.setSize(2);
|
||||
|
||||
// number of inter-chip switches
|
||||
int numberOfTorusSwitches = m_nodes/MachineType_base_level(MachineType_NUM);
|
||||
// one switch per machine node grouping
|
||||
Vector<SwitchID> torusSwitches;
|
||||
for(int i=0; i<numberOfTorusSwitches; i++){
|
||||
SwitchID new_switch = newSwitchID();
|
||||
torusSwitches.insertAtBottom(new_switch);
|
||||
}
|
||||
|
||||
makeSwitchesPerChip(nodePairs, latencies, bw_multis, numberOfTorusSwitches);
|
||||
|
||||
int lengthOfSide = (int)sqrt((double)numberOfTorusSwitches);
|
||||
|
||||
// Now connect the inter-chip torus links
|
||||
|
||||
int latency = m_network_ptr->getLinkLatency(); // external link latency
|
||||
int bw_multiplier = 1; // external link bw multiplier of the global bandwidth
|
||||
|
||||
for(int i=0; i<numberOfTorusSwitches; i++){
|
||||
nodes[0] = torusSwitches[i]; // current switch
|
||||
|
||||
// left
|
||||
if(nodes[0]%lengthOfSide == 0){ // determine left neighbor
|
||||
nodes[1] = nodes[0] - 1 + lengthOfSide;
|
||||
} else {
|
||||
nodes[1] = nodes[0] - 1;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// right
|
||||
if((nodes[0] + 1)%lengthOfSide == 0){ // determine right neighbor
|
||||
nodes[1] = nodes[0] + 1 - lengthOfSide;
|
||||
} else {
|
||||
nodes[1] = nodes[0] + 1;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// top
|
||||
if(nodes[0] - lengthOfSide < 2*m_nodes){ // determine if node is on the top
|
||||
nodes[1] = nodes[0] - lengthOfSide + (lengthOfSide*lengthOfSide);
|
||||
} else {
|
||||
nodes[1] = nodes[0] - lengthOfSide;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
// bottom
|
||||
if(nodes[0] + lengthOfSide >= 2*m_nodes+numberOfTorusSwitches){ // determine if node is on the bottom
|
||||
// sorin: bad bug if this is a > instead of a >=
|
||||
nodes[1] = nodes[0] + lengthOfSide - (lengthOfSide*lengthOfSide);
|
||||
} else {
|
||||
nodes[1] = nodes[0] + lengthOfSide;
|
||||
}
|
||||
nodePairs.insertAtBottom(nodes);
|
||||
latencies.insertAtBottom(latency);
|
||||
bw_multis.insertAtBottom(bw_multiplier);
|
||||
|
||||
}
|
||||
|
||||
// add links
|
||||
ASSERT(nodePairs.size() == latencies.size() && latencies.size() == bw_multis.size())
|
||||
for (int k = 0; k < nodePairs.size(); k++) {
|
||||
ASSERT(nodePairs[k].size() == 2);
|
||||
addLink(nodePairs[k][0], nodePairs[k][1], latencies[k], bw_multis[k]);
|
||||
}
|
||||
|
||||
}
|
17
src/mem/ruby/network/simple/Torus2DTopology.hh
Normal file
17
src/mem/ruby/network/simple/Torus2DTopology.hh
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#ifndef TORUS2DTOPOLOGY_H
|
||||
#define TORUS2DTOPOLOGY_H
|
||||
|
||||
#include "mem/ruby/network/simple/Topology.hh"
|
||||
|
||||
class Torus2DTopology : public Topology
|
||||
{
|
||||
public:
|
||||
Torus2DTopology(const string & name);
|
||||
void init(const vector<string> & argv);
|
||||
|
||||
protected:
|
||||
void construct();
|
||||
};
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue