summaryrefslogtreecommitdiff
path: root/src/mem/protocol/MI_example-dma.sm
blob: 1f929cf9bf203140fda980820b972d044ad274db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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;
  }
}