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:
Nathan Binkert 2009-07-06 15:49:47 -07:00
parent 05f6a4a6b9
commit 92de70b69a
203 changed files with 12366 additions and 8437 deletions

View file

@ -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

View file

@ -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)
{

View file

@ -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);

View file

@ -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;

View file

@ -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" {

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

@ -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;
}
}

View 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;
}
}

View file

@ -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";
}

View file

@ -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

View file

@ -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);

View file

@ -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";

View file

@ -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);
}

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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; }

View file

@ -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;
}
}

View file

@ -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 *******************

View file

@ -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;
}
}

View file

@ -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

View file

@ -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; }

View file

@ -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

View file

@ -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]);

View file

@ -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();

View file

@ -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

View 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

View 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)

View file

@ -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);

View file

@ -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
View 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"

View file

@ -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 );

View 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

View 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);
}

View 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

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View 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

View 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;
}

View 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

View 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);
}

View file

@ -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

View 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);
}

View file

@ -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

View 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;
}

File diff suppressed because it is too large Load diff

View 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);
}

View 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

View 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;
}

View file

@ -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

View 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);
}

View 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

View 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);
}

View file

@ -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

View file

@ -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
View 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
View 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

View 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

View 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");
}

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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;
};

View file

@ -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))
{

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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;

View file

@ -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()));
}
}

View file

@ -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);

View file

@ -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))
{

View file

@ -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))
{

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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++)

View file

@ -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);

View 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();
}

View 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

View 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();
}
}

View 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

View file

@ -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++) {

View 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]);
}
}

View 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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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; }

View file

@ -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;

View file

@ -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;

View 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]);
}
}

View 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