gem5/src/mem/protocol/MOESI_CMP_directory-dma.sm
Nilay Vaish 9b72a0f627 ruby: change slicc to allow for constructor args
The patch adds support to slicc for recognizing arguments that should be
passed to the constructor of a class. I did not like the fact that an explicit
check was being carried on the type 'TBETable' to figure out the arguments to
be passed to the constructor.
The patch also moves some of the member variables that are declared for all
the controllers to the base class AbstractController.
2012-12-11 10:05:55 -06:00

278 lines
8.4 KiB
Text

machine(DMA, "DMA Controller")
: DMASequencer * dma_sequencer,
int request_latency = 14,
int response_latency = 14
{
MessageBuffer responseFromDir, network="From", virtual_network="2", ordered="false", vnet_type="response";
MessageBuffer reqToDir, network="To", virtual_network="1", ordered="false", vnet_type="request";
MessageBuffer respToDir, network="To", virtual_network="2", ordered="false", vnet_type="dmaresponse";
state_declaration(State, desc="DMA states", default="DMA_State_READY") {
READY, AccessPermission:Invalid, desc="Ready to accept a new request";
BUSY_RD, AccessPermission:Busy, desc="Busy: currently processing a request";
BUSY_WR, AccessPermission:Busy, 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";
DMA_Ack, desc="DMA write to memory completed";
Inv_Ack, desc="Invalidation Ack from a sharer";
All_Acks, desc="All acks received";
}
structure(TBE, desc="...") {
Address address, desc="Physical address";
int NumAcks, default="0", desc="Number of Acks pending";
DataBlock DataBlk, desc="Data";
}
structure(DMASequencer, external = "yes") {
void ackCallback();
void dataCallback(DataBlock);
}
structure(TBETable, external = "yes") {
TBE lookup(Address);
void allocate(Address);
void deallocate(Address);
bool isPresent(Address);
}
MessageBuffer mandatoryQueue, ordered="false";
MessageBuffer triggerQueue, ordered="true";
TBETable TBEs, template="<DMA_TBE>", constructor="m_number_of_TBEs";
State cur_state;
void set_tbe(TBE b);
void unset_tbe();
State getState(TBE tbe, Address addr) {
return cur_state;
}
void setState(TBE tbe, Address addr, State state) {
cur_state := state;
}
AccessPermission getAccessPermission(Address addr) {
return AccessPermission:NotPresent;
}
void setAccessPermission(Address addr, State state) {
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA Controller does not support getDataBlock().\n");
}
out_port(reqToDirectory_out, RequestMsg, reqToDir, desc="...");
out_port(respToDirectory_out, ResponseMsg, respToDir, desc="...");
out_port(triggerQueue_out, TriggerMsg, triggerQueue, desc="...");
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {
if (dmaRequestQueue_in.isReady()) {
peek(dmaRequestQueue_in, SequencerMsg) {
if (in_msg.Type == SequencerRequestType:LD ) {
trigger(Event:ReadRequest, in_msg.LineAddress,
TBEs[in_msg.LineAddress]);
} else if (in_msg.Type == SequencerRequestType:ST) {
trigger(Event:WriteRequest, in_msg.LineAddress,
TBEs[in_msg.LineAddress]);
} else {
error("Invalid request type");
}
}
}
}
in_port(dmaResponseQueue_in, ResponseMsg, responseFromDir, desc="...") {
if (dmaResponseQueue_in.isReady()) {
peek( dmaResponseQueue_in, ResponseMsg) {
if (in_msg.Type == CoherenceResponseType:DMA_ACK) {
trigger(Event:DMA_Ack, makeLineAddress(in_msg.Address),
TBEs[makeLineAddress(in_msg.Address)]);
} else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE ||
in_msg.Type == CoherenceResponseType:DATA) {
trigger(Event:Data, makeLineAddress(in_msg.Address),
TBEs[makeLineAddress(in_msg.Address)]);
} else if (in_msg.Type == CoherenceResponseType:ACK) {
trigger(Event:Inv_Ack, makeLineAddress(in_msg.Address),
TBEs[makeLineAddress(in_msg.Address)]);
} else {
error("Invalid response type");
}
}
}
}
// Trigger Queue
in_port(triggerQueue_in, TriggerMsg, triggerQueue) {
if (triggerQueue_in.isReady()) {
peek(triggerQueue_in, TriggerMsg) {
if (in_msg.Type == TriggerType:ALL_ACKS) {
trigger(Event:All_Acks, in_msg.Address, TBEs[in_msg.Address]);
} else {
error("Unexpected message");
}
}
}
}
action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") {
peek(dmaRequestQueue_in, SequencerMsg) {
enqueue(reqToDirectory_out, RequestMsg, latency=request_latency) {
out_msg.Address := in_msg.PhysicalAddress;
out_msg.Type := CoherenceRequestType:DMA_READ;
out_msg.DataBlk := in_msg.DataBlk;
out_msg.Len := in_msg.Len;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:DMA;
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") {
peek(dmaRequestQueue_in, SequencerMsg) {
enqueue(reqToDirectory_out, RequestMsg, latency=request_latency) {
out_msg.Address := in_msg.PhysicalAddress;
out_msg.Type := CoherenceRequestType:DMA_WRITE;
out_msg.DataBlk := in_msg.DataBlk;
out_msg.Len := in_msg.Len;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.Requestor := machineID;
out_msg.RequestorMachine := MachineType:DMA;
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
}
action(a_ackCallback, "a", desc="Notify dma controller that write request completed") {
dma_sequencer.ackCallback();
}
action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") {
assert(is_valid(tbe));
if (tbe.NumAcks == 0) {
enqueue(triggerQueue_out, TriggerMsg) {
out_msg.Address := address;
out_msg.Type := TriggerType:ALL_ACKS;
}
}
}
action(u_updateAckCount, "u", desc="Update ack count") {
peek(dmaResponseQueue_in, ResponseMsg) {
assert(is_valid(tbe));
tbe.NumAcks := tbe.NumAcks - in_msg.Acks;
}
}
action( u_sendExclusiveUnblockToDir, "\u", desc="send exclusive unblock to directory") {
enqueue(respToDirectory_out, ResponseMsg, latency=response_latency) {
out_msg.Address := address;
out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE;
out_msg.Destination.add(map_Address_to_Directory(address));
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:DMA;
out_msg.MessageSize := MessageSizeType:Writeback_Control;
}
}
action(p_popRequestQueue, "p", desc="Pop request queue") {
dmaRequestQueue_in.dequeue();
}
action(p_popResponseQueue, "\p", desc="Pop request queue") {
dmaResponseQueue_in.dequeue();
}
action(p_popTriggerQueue, "pp", desc="Pop trigger queue") {
triggerQueue_in.dequeue();
}
action(t_updateTBEData, "t", desc="Update TBE Data") {
peek(dmaResponseQueue_in, ResponseMsg) {
assert(is_valid(tbe));
tbe.DataBlk := in_msg.DataBlk;
}
}
action(d_dataCallbackFromTBE, "/d", desc="data callback with data from TBE") {
assert(is_valid(tbe));
dma_sequencer.dataCallback(tbe.DataBlk);
}
action(v_allocateTBE, "v", desc="Allocate TBE entry") {
TBEs.allocate(address);
set_tbe(TBEs[address]);
}
action(w_deallocateTBE, "w", desc="Deallocate TBE entry") {
TBEs.deallocate(address);
unset_tbe();
}
action(z_stall, "z", desc="dma is busy..stall") {
// do nothing
}
transition(READY, ReadRequest, BUSY_RD) {
s_sendReadRequest;
v_allocateTBE;
p_popRequestQueue;
}
transition(BUSY_RD, Inv_Ack) {
u_updateAckCount;
o_checkForCompletion;
p_popResponseQueue;
}
transition(BUSY_RD, Data, READY) {
t_updateTBEData;
d_dataCallbackFromTBE;
w_deallocateTBE;
//u_updateAckCount;
//o_checkForCompletion;
p_popResponseQueue;
}
transition(BUSY_RD, All_Acks, READY) {
d_dataCallbackFromTBE;
//u_sendExclusiveUnblockToDir;
w_deallocateTBE;
p_popTriggerQueue;
}
transition(READY, WriteRequest, BUSY_WR) {
s_sendWriteRequest;
v_allocateTBE;
p_popRequestQueue;
}
transition(BUSY_WR, Inv_Ack) {
u_updateAckCount;
o_checkForCompletion;
p_popResponseQueue;
}
transition(BUSY_WR, DMA_Ack) {
u_updateAckCount; // actually increases
o_checkForCompletion;
p_popResponseQueue;
}
transition(BUSY_WR, All_Acks, READY) {
a_ackCallback;
u_sendExclusiveUnblockToDir;
w_deallocateTBE;
p_popTriggerQueue;
}
}