The patch started of with replacing Time with Cycles in the Consumer class. But to get ruby to compile, the rest of the changes had to be carried out. Subsequent patches will further this process, till we completely replace Time with Cycles.
279 lines
8.4 KiB
Plaintext
279 lines
8.4 KiB
Plaintext
|
|
machine(DMA, "DMA Controller")
|
|
: DMASequencer * dma_sequencer,
|
|
Cycles request_latency = 14,
|
|
Cycles 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;
|
|
}
|
|
}
|