1/* 2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30machine(MachineType:DMA, "DMA Controller") 31 : DMASequencer * dma_sequencer; 32 Cycles request_latency := 6; 33 34 // Messsage Queues 35 MessageBuffer * responseFromDir, network="From", virtual_network="5", 36 vnet_type="response"; 37 MessageBuffer * reqToDirectory, network="To", virtual_network="0", 38 vnet_type="request"; 39 40 MessageBuffer * mandatoryQueue; 41{ 42 state_declaration(State, desc="DMA states", default="DMA_State_READY") { 43 READY, AccessPermission:Invalid, desc="Ready to accept a new request"; 44 BUSY_RD, AccessPermission:Busy, desc="Busy: currently processing a request"; 45 BUSY_WR, AccessPermission:Busy, desc="Busy: currently processing a request"; 46 } 47 48 enumeration(Event, desc="DMA events") { 49 ReadRequest, desc="A new read request"; 50 WriteRequest, desc="A new write request"; 51 Data, desc="Data from a DMA memory read"; 52 Ack, desc="DMA write to memory completed"; 53 } 54 55 structure(TBE, desc="...") { 56 State TBEState, desc="Transient state"; 57 DataBlock DataBlk, desc="Data"; 58 } 59 60 structure(TBETable, external = "yes") { 61 TBE lookup(Addr); 62 void allocate(Addr); 63 void deallocate(Addr); 64 bool isPresent(Addr); 65 } 66 67 void set_tbe(TBE b); 68 void unset_tbe(); 69 void wakeUpAllBuffers(); 70 71 TBETable TBEs, template="<DMA_TBE>", constructor="m_number_of_TBEs"; 72 73 Tick clockEdge(); 74 MachineID mapAddressToMachine(Addr addr, MachineType mtype); 75 76 State getState(TBE tbe, Addr addr) { 77 if (is_valid(tbe)) { 78 return tbe.TBEState; 79 } else { 80 return State:READY; 81 } 82 } 83 84 void setState(TBE tbe, Addr addr, State state) { 85 if (is_valid(tbe)) { 86 tbe.TBEState := state; 87 } 88 } 89 90 AccessPermission getAccessPermission(Addr addr) { 91 return AccessPermission:NotPresent; 92 } 93 94 void setAccessPermission(Addr addr, State state) { 95 } 96 97 void functionalRead(Addr addr, Packet *pkt) { 98 error("DMA does not support functional read."); 99 } 100 101 int functionalWrite(Addr addr, Packet *pkt) { 102 error("DMA does not support functional write."); 103 } 104 105 out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); 106 107 in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { 108 if (dmaRequestQueue_in.isReady(clockEdge())) { 109 peek(dmaRequestQueue_in, SequencerMsg) { 110 if (in_msg.Type == SequencerRequestType:LD ) { 111 trigger(Event:ReadRequest, in_msg.LineAddress, TBEs[in_msg.LineAddress]); 112 } else if (in_msg.Type == SequencerRequestType:ST) { 113 trigger(Event:WriteRequest, in_msg.LineAddress, TBEs[in_msg.LineAddress]); 114 } else { 115 error("Invalid request type"); 116 } 117 } 118 } 119 } 120 121 in_port(dmaResponseQueue_in, DMAResponseMsg, responseFromDir, desc="...") { 122 if (dmaResponseQueue_in.isReady(clockEdge())) { 123 peek( dmaResponseQueue_in, DMAResponseMsg) { 124 if (in_msg.Type == DMAResponseType:ACK) { 125 trigger(Event:Ack, in_msg.LineAddress, TBEs[in_msg.LineAddress]); 126 } else if (in_msg.Type == DMAResponseType:DATA) { 127 trigger(Event:Data, in_msg.LineAddress, TBEs[in_msg.LineAddress]); 128 } else { 129 error("Invalid response type"); 130 } 131 } 132 } 133 } 134 135 action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") { 136 peek(dmaRequestQueue_in, SequencerMsg) { 137 enqueue(reqToDirectory_out, DMARequestMsg, request_latency) { 138 out_msg.PhysicalAddress := in_msg.PhysicalAddress; 139 out_msg.LineAddress := in_msg.LineAddress; 140 out_msg.Type := DMARequestType:READ; 141 out_msg.Requestor := machineID; 142 out_msg.DataBlk := in_msg.DataBlk; 143 out_msg.Len := in_msg.Len; 144 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 145 out_msg.MessageSize := MessageSizeType:Writeback_Control; 146 } 147 } 148 } 149 150 action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") { 151 peek(dmaRequestQueue_in, SequencerMsg) { 152 enqueue(reqToDirectory_out, DMARequestMsg, request_latency) { 153 out_msg.PhysicalAddress := in_msg.PhysicalAddress; 154 out_msg.LineAddress := in_msg.LineAddress; 155 out_msg.Type := DMARequestType:WRITE; 156 out_msg.Requestor := machineID; 157 out_msg.DataBlk := in_msg.DataBlk; 158 out_msg.Len := in_msg.Len; 159 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 160 out_msg.MessageSize := MessageSizeType:Writeback_Control; 161 } 162 } 163 } 164 165 action(a_ackCallback, "a", desc="Notify dma controller that write request completed") { 166 dma_sequencer.ackCallback(address); 167 } 168 169 action(d_dataCallback, "d", desc="Write data to dma sequencer") { 170 dma_sequencer.dataCallback(tbe.DataBlk, address); 171 } 172 173 action(t_updateTBEData, "t", desc="Update TBE Data") { 174 assert(is_valid(tbe)); 175 peek(dmaResponseQueue_in, DMAResponseMsg) { 176 tbe.DataBlk := in_msg.DataBlk; 177 } 178 } 179 180 action(v_allocateTBE, "v", desc="Allocate TBE entry") { 181 TBEs.allocate(address); 182 set_tbe(TBEs[address]); 183 } 184 185 action(w_deallocateTBE, "w", desc="Deallocate TBE entry") { 186 TBEs.deallocate(address); 187 unset_tbe(); 188 } 189 190 action(p_popRequestQueue, "p", desc="Pop request queue") { 191 dmaRequestQueue_in.dequeue(clockEdge()); 192 } 193 194 action(p_popResponseQueue, "\p", desc="Pop request queue") { 195 dmaResponseQueue_in.dequeue(clockEdge()); 196 } 197 198 action(zz_stallAndWaitRequestQueue, "zz", desc="...") { 199 stall_and_wait(dmaRequestQueue_in, address); 200 } 201 202 action(wkad_wakeUpAllDependents, "wkad", desc="wake-up all dependents") { 203 wakeUpAllBuffers(); 204 } 205 206 transition(READY, ReadRequest, BUSY_RD) { 207 v_allocateTBE; 208 s_sendReadRequest; 209 p_popRequestQueue; 210 } 211 212 transition(READY, WriteRequest, BUSY_WR) { 213 v_allocateTBE; 214 s_sendWriteRequest; 215 p_popRequestQueue; 216 } 217 218 transition(BUSY_RD, Data, READY) { 219 t_updateTBEData; 220 d_dataCallback; 221 w_deallocateTBE; 222 p_popResponseQueue; 223 wkad_wakeUpAllDependents; 224 } 225 226 transition(BUSY_WR, Ack, READY) { 227 a_ackCallback; 228 w_deallocateTBE; 229 p_popResponseQueue; 230 wkad_wakeUpAllDependents; 231 } 232 233 transition({BUSY_RD,BUSY_WR}, {ReadRequest,WriteRequest}) { 234 zz_stallAndWaitRequestQueue; 235 } 236} 237