1/* 2 * Copyright (c) 2019 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2009-2013 Mark D. Hill and David A. Wood 15 * Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42machine(MachineType:DMA, "DMA Controller") 43 : DMASequencer * dma_sequencer; 44 Cycles request_latency := 14; 45 Cycles response_latency := 14; 46 47 MessageBuffer * responseFromDir, network="From", virtual_network="2", 48 vnet_type="response"; 49 50 MessageBuffer * reqToDir, network="To", virtual_network="1", 51 vnet_type="request"; 52 MessageBuffer * respToDir, network="To", virtual_network="2", 53 vnet_type="dmaresponse"; 54 55 MessageBuffer * mandatoryQueue; 56 MessageBuffer * triggerQueue; 57{ 58 state_declaration(State, desc="DMA states", default="DMA_State_READY") { 59 READY, AccessPermission:Invalid, desc="Ready to accept a new request"; 60 BUSY_RD, AccessPermission:Busy, desc="Busy: currently processing a request"; 61 BUSY_WR, AccessPermission:Busy, desc="Busy: currently processing a request"; 62 } 63 64 enumeration(Event, desc="DMA events") { 65 ReadRequest, desc="A new read request"; 66 WriteRequest, desc="A new write request"; 67 Data, desc="Data from a DMA memory read"; 68 DMA_Ack, desc="DMA write to memory completed"; 69 Inv_Ack, desc="Invalidation Ack from a sharer"; 70 All_Acks, desc="All acks received"; 71 } 72 73 structure(TBE, desc="...") { 74 Addr address, desc="Physical address"; 75 int NumAcks, default="0", desc="Number of Acks pending"; 76 DataBlock DataBlk, desc="Data"; 77 } 78 79 structure(TBETable, external = "yes") { 80 TBE lookup(Addr); 81 void allocate(Addr); 82 void deallocate(Addr); 83 bool isPresent(Addr); 84 } 85 86 TBETable TBEs, template="<DMA_TBE>", constructor="m_number_of_TBEs"; 87 State cur_state; 88 89 Tick clockEdge(); 90 void set_tbe(TBE b); 91 void unset_tbe(); 92 void wakeUpAllBuffers(); 93 MachineID mapAddressToMachine(Addr addr, MachineType mtype); 94 95 State getState(TBE tbe, Addr addr) { 96 return cur_state; 97 } 98 void setState(TBE tbe, Addr addr, State state) { 99 cur_state := state; 100 } 101 102 AccessPermission getAccessPermission(Addr addr) { 103 return AccessPermission:NotPresent; 104 } 105 106 void setAccessPermission(Addr addr, State state) { 107 } 108 109 void functionalRead(Addr addr, Packet *pkt) { 110 error("DMA does not support functional read."); 111 } 112 113 int functionalWrite(Addr addr, Packet *pkt) { 114 error("DMA does not support functional write."); 115 } 116 117 out_port(reqToDirectory_out, RequestMsg, reqToDir, desc="..."); 118 out_port(respToDirectory_out, ResponseMsg, respToDir, desc="..."); 119 out_port(triggerQueue_out, TriggerMsg, triggerQueue, desc="..."); 120 121 in_port(dmaResponseQueue_in, ResponseMsg, responseFromDir, rank=2) { 122 if (dmaResponseQueue_in.isReady(clockEdge())) { 123 peek( dmaResponseQueue_in, ResponseMsg) { 124 if (in_msg.Type == CoherenceResponseType:DMA_ACK) { 125 trigger(Event:DMA_Ack, makeLineAddress(in_msg.addr), 126 TBEs[makeLineAddress(in_msg.addr)]); 127 } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE || 128 in_msg.Type == CoherenceResponseType:DATA) { 129 trigger(Event:Data, makeLineAddress(in_msg.addr), 130 TBEs[makeLineAddress(in_msg.addr)]); 131 } else if (in_msg.Type == CoherenceResponseType:ACK) { 132 trigger(Event:Inv_Ack, makeLineAddress(in_msg.addr), 133 TBEs[makeLineAddress(in_msg.addr)]); 134 } else { 135 error("Invalid response type"); 136 } 137 } 138 } 139 } 140 141 // Trigger Queue 142 in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=1) { 143 if (triggerQueue_in.isReady(clockEdge())) { 144 peek(triggerQueue_in, TriggerMsg) { 145 if (in_msg.Type == TriggerType:ALL_ACKS) { 146 trigger(Event:All_Acks, in_msg.addr, TBEs[in_msg.addr]); 147 } else { 148 error("Unexpected message"); 149 } 150 } 151 } 152 } 153 154 in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, rank=0) { 155 if (dmaRequestQueue_in.isReady(clockEdge())) { 156 peek(dmaRequestQueue_in, SequencerMsg) { 157 if (in_msg.Type == SequencerRequestType:LD ) { 158 trigger(Event:ReadRequest, in_msg.LineAddress, 159 TBEs[in_msg.LineAddress]); 160 } else if (in_msg.Type == SequencerRequestType:ST) { 161 trigger(Event:WriteRequest, in_msg.LineAddress, 162 TBEs[in_msg.LineAddress]); 163 } else { 164 error("Invalid request type"); 165 } 166 } 167 } 168 } 169 170 action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") { 171 peek(dmaRequestQueue_in, SequencerMsg) { 172 enqueue(reqToDirectory_out, RequestMsg, request_latency) { 173 out_msg.addr := in_msg.PhysicalAddress; 174 out_msg.Type := CoherenceRequestType:DMA_READ; 175 out_msg.DataBlk := in_msg.DataBlk; 176 out_msg.Len := in_msg.Len; 177 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 178 out_msg.Requestor := machineID; 179 out_msg.RequestorMachine := MachineType:DMA; 180 out_msg.MessageSize := MessageSizeType:Writeback_Control; 181 } 182 } 183 } 184 185 action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") { 186 peek(dmaRequestQueue_in, SequencerMsg) { 187 enqueue(reqToDirectory_out, RequestMsg, request_latency) { 188 out_msg.addr := in_msg.PhysicalAddress; 189 out_msg.Type := CoherenceRequestType:DMA_WRITE; 190 out_msg.DataBlk := in_msg.DataBlk; 191 out_msg.Len := in_msg.Len; 192 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 193 out_msg.Requestor := machineID; 194 out_msg.RequestorMachine := MachineType:DMA; 195 out_msg.MessageSize := MessageSizeType:Writeback_Control; 196 } 197 } 198 } 199 200 action(a_ackCallback, "a", desc="Notify dma controller that write request completed") { 201 dma_sequencer.ackCallback(address); 202 } 203 204 action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") { 205 assert(is_valid(tbe)); 206 if (tbe.NumAcks == 0) { 207 enqueue(triggerQueue_out, TriggerMsg) { 208 out_msg.addr := address; 209 out_msg.Type := TriggerType:ALL_ACKS; 210 } 211 } 212 } 213 214 action(u_updateAckCount, "u", desc="Update ack count") { 215 peek(dmaResponseQueue_in, ResponseMsg) { 216 assert(is_valid(tbe)); 217 tbe.NumAcks := tbe.NumAcks - in_msg.Acks; 218 } 219 } 220 221 action( u_sendExclusiveUnblockToDir, "\u", desc="send exclusive unblock to directory") { 222 enqueue(respToDirectory_out, ResponseMsg, response_latency) { 223 out_msg.addr := address; 224 out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE; 225 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 226 out_msg.Sender := machineID; 227 out_msg.SenderMachine := MachineType:DMA; 228 out_msg.MessageSize := MessageSizeType:Writeback_Control; 229 } 230 } 231 232 action(p_popRequestQueue, "p", desc="Pop request queue") { 233 dmaRequestQueue_in.dequeue(clockEdge()); 234 } 235 236 action(p_popResponseQueue, "\p", desc="Pop request queue") { 237 dmaResponseQueue_in.dequeue(clockEdge()); 238 } 239 240 action(p_popTriggerQueue, "pp", desc="Pop trigger queue") { 241 triggerQueue_in.dequeue(clockEdge()); 242 } 243 244 action(t_updateTBEData, "t", desc="Update TBE Data") { 245 peek(dmaResponseQueue_in, ResponseMsg) { 246 assert(is_valid(tbe)); 247 tbe.DataBlk := in_msg.DataBlk; 248 } 249 } 250 251 action(d_dataCallbackFromTBE, "/d", desc="data callback with data from TBE") { 252 assert(is_valid(tbe)); 253 dma_sequencer.dataCallback(tbe.DataBlk, address); 254 } 255 256 action(v_allocateTBE, "v", desc="Allocate TBE entry") { 257 TBEs.allocate(address); 258 set_tbe(TBEs[address]); 259 } 260 261 action(w_deallocateTBE, "w", desc="Deallocate TBE entry") { 262 TBEs.deallocate(address); 263 unset_tbe(); 264 } 265 266 action(zz_stallAndWaitRequestQueue, "zz", desc="...") { 267 stall_and_wait(dmaRequestQueue_in, address); 268 } 269 270 action(wkad_wakeUpAllDependents, "wkad", desc="wake-up all dependents") { 271 wakeUpAllBuffers(); 272 } 273 274 transition(READY, ReadRequest, BUSY_RD) { 275 s_sendReadRequest; 276 v_allocateTBE; 277 p_popRequestQueue; 278 } 279 280 transition(BUSY_RD, Inv_Ack) { 281 u_updateAckCount; 282 o_checkForCompletion; 283 p_popResponseQueue; 284 } 285 286 transition(BUSY_RD, Data, READY) { 287 t_updateTBEData; 288 d_dataCallbackFromTBE; 289 w_deallocateTBE; 290 //u_updateAckCount; 291 //o_checkForCompletion; 292 p_popResponseQueue; 293 wkad_wakeUpAllDependents; 294 } 295 296 transition(BUSY_RD, All_Acks, READY) { 297 d_dataCallbackFromTBE; 298 //u_sendExclusiveUnblockToDir; 299 w_deallocateTBE; 300 p_popTriggerQueue; 301 wkad_wakeUpAllDependents; 302 } 303 304 transition(READY, WriteRequest, BUSY_WR) { 305 s_sendWriteRequest; 306 v_allocateTBE; 307 p_popRequestQueue; 308 } 309 310 transition(BUSY_WR, Inv_Ack) { 311 u_updateAckCount; 312 o_checkForCompletion; 313 p_popResponseQueue; 314 } 315 316 transition(BUSY_WR, DMA_Ack) { 317 u_updateAckCount; // actually increases 318 o_checkForCompletion; 319 p_popResponseQueue; 320 } 321 322 transition(BUSY_WR, All_Acks, READY) { 323 a_ackCallback; 324 u_sendExclusiveUnblockToDir; 325 w_deallocateTBE; 326 p_popTriggerQueue; 327 wkad_wakeUpAllDependents; 328 } 329 330 transition({BUSY_RD,BUSY_WR}, {ReadRequest,WriteRequest}) { 331 zz_stallAndWaitRequestQueue; 332 } 333} 334