io_device.hh revision 2569
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 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#ifndef __DEV_IO_DEVICE_HH__ 30#define __DEV_IO_DEVICE_HH__ 31 32#include "base/chunk_generator.hh" 33#include "mem/mem_object.hh" 34#include "sim/eventq.hh" 35#include "sim/sim_object.hh" 36 37class Platform; 38class PioDevice; 39class DmaDevice; 40class System; 41 42/** 43 * The PioPort class is a programmed i/o port that all devices that are 44 * sensitive to an address range use. The port takes all the memory 45 * access types and roles them into one read() and write() call that the device 46 * must respond to. The device must also provide the addressRanges() function 47 * with which it returns the address ranges it is interested in. An extra 48 * sendTiming() function is implemented which takes an delay. In this way the 49 * device can immediatly call sendTiming(pkt, time) after processing a request 50 * and the request will be handled by the port even if the port bus the device 51 * connects to is blocked. 52 */ 53class PioPort : public Port 54{ 55 protected: 56 /** The device that this port serves. */ 57 PioDevice *device; 58 59 /** The platform that device/port are in. This is used to select which mode 60 * we are currently operating in. */ 61 Platform *platform; 62 63 /** A list of outgoing timing response packets that haven't been serviced 64 * yet. */ 65 std::list<Packet*> transmitList; 66 67 /** The current status of the peer(bus) that we are connected to. */ 68 Status peerStatus; 69 70 virtual bool recvTiming(Packet &pkt); 71 72 virtual Tick recvAtomic(Packet &pkt); 73 74 virtual void recvFunctional(Packet &pkt) ; 75 76 virtual void recvStatusChange(Status status) 77 { peerStatus = status; } 78 79 virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); 80 81 /** 82 * This class is used to implemented sendTiming() with a delay. When a delay 83 * is requested a new event is created. When the event time expires it 84 * attempts to send the packet. If it cannot, the packet is pushed onto the 85 * transmit list to be sent when recvRetry() is called. */ 86 class SendEvent : public Event 87 { 88 PioPort *port; 89 Packet packet; 90 91 SendEvent(PioPort *p, Packet &pkt, Tick t) 92 : Event(&mainEventQueue), packet(pkt) 93 { schedule(curTick + t); } 94 95 virtual void process(); 96 97 virtual const char *description() 98 { return "Future scheduled sendTiming event"; } 99 100 friend class PioPort; 101 }; 102 103 /** Schedule a sendTiming() event to be called in the future. */ 104 void sendTiming(Packet &pkt, Tick time) 105 { new PioPort::SendEvent(this, pkt, time); } 106 107 /** This function pops the last element off the transmit list and sends it.*/ 108 virtual Packet *recvRetry(); 109 110 public: 111 PioPort(PioDevice *dev, Platform *p); 112 113 friend class PioPort::SendEvent; 114}; 115 116 117struct DmaReqState 118{ 119 Event *completionEvent; 120 bool final; 121 DmaReqState(Event *ce, bool f) 122 : completionEvent(ce), final(f) 123 {} 124}; 125 126class DmaPort : public Port 127{ 128 protected: 129 DmaDevice *device; 130 std::list<Packet*> transmitList; 131 132 /** The platform that device/port are in. This is used to select which mode 133 * we are currently operating in. */ 134 Platform *platform; 135 136 /** Number of outstanding packets the dma port has. */ 137 int pendingCount; 138 139 virtual bool recvTiming(Packet &pkt); 140 virtual Tick recvAtomic(Packet &pkt) 141 { panic("dma port shouldn't be used for pio access."); } 142 virtual void recvFunctional(Packet &pkt) 143 { panic("dma port shouldn't be used for pio access."); } 144 145 virtual void recvStatusChange(Status status) 146 { ; } 147 148 virtual Packet *recvRetry() ; 149 150 virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 151 { resp.clear(); snoop.clear(); } 152 153 class SendEvent : public Event 154 { 155 DmaPort *port; 156 Packet packet; 157 158 SendEvent(PioPort *p, Packet &pkt, Tick t) 159 : Event(&mainEventQueue), packet(pkt) 160 { schedule(curTick + t); } 161 162 virtual void process(); 163 164 virtual const char *description() 165 { return "Future scheduled sendTiming event"; } 166 167 friend class DmaPort; 168 }; 169 170 void sendDma(Packet *pkt); 171 172 public: 173 DmaPort(DmaDevice *dev, Platform *p); 174 175 void dmaAction(Command cmd, Addr addr, int size, Event *event, 176 uint8_t *data = NULL); 177 178 bool dmaPending() { return pendingCount > 0; } 179 180 friend class DmaPort::SendEvent; 181 182}; 183 184/** 185 * This device is the base class which all devices senstive to an address range 186 * inherit from. There are three pure virtual functions which all devices must 187 * implement addressRanges(), read(), and write(). The magic do choose which 188 * mode we are in, etc is handled by the PioPort so the device doesn't have to 189 * bother. 190 */ 191 192class PioDevice : public MemObject 193{ 194 protected: 195 196 /** The platform we are in. This is used to decide what type of memory 197 * transaction we should perform. */ 198 Platform *platform; 199 200 /** The pioPort that handles the requests for us and provides us requests 201 * that it sees. */ 202 PioPort *pioPort; 203 204 virtual void addressRanges(AddrRangeList &range_list) = 0; 205 206 /** As far as the devices are concerned they only accept atomic transactions 207 * which are converted to either a write or a read. */ 208 Tick recvAtomic(Packet &pkt) 209 { return pkt.cmd == Read ? this->read(pkt) : this->write(pkt); } 210 211 /** Pure virtual function that the device must implement. Called when a read 212 * command is recieved by the port. 213 * @param pkt Packet describing this request 214 * @return number of ticks it took to complete 215 */ 216 virtual Tick read(Packet &pkt) = 0; 217 218 /** Pure virtual function that the device must implement. Called when a 219 * write command is recieved by the port. 220 * @param pkt Packet describing this request 221 * @return number of ticks it took to complete 222 */ 223 virtual Tick write(Packet &pkt) = 0; 224 225 public: 226 /** Params struct which is extended through each device based on the 227 * parameters it needs. Since we are re-writing everything, we might as well 228 * start from the bottom this time. */ 229 230 struct Params 231 { 232 std::string name; 233 Platform *platform; 234 System *system; 235 }; 236 237 protected: 238 Params *_params; 239 240 public: 241 const Params *params() const { return _params; } 242 243 PioDevice(Params *p) 244 : MemObject(p->name), platform(p->platform), pioPort(NULL), 245 _params(p) 246 {} 247 248 virtual ~PioDevice(); 249 250 virtual void init(); 251 252 virtual Port *getPort(const std::string &if_name) 253 { 254 if (if_name == "pio") { 255 if (pioPort != NULL) 256 panic("pio port already connected to."); 257 pioPort = new PioPort(this, params()->platform); 258 return pioPort; 259 } else 260 return NULL; 261 } 262 friend class PioPort; 263 264}; 265 266class BasicPioDevice : public PioDevice 267{ 268 public: 269 struct Params : public PioDevice::Params 270 { 271 Addr pio_addr; 272 Tick pio_delay; 273 }; 274 275 protected: 276 /** Address that the device listens to. */ 277 Addr pioAddr; 278 279 /** Size that the device's address range. */ 280 Addr pioSize; 281 282 /** Delay that the device experinces on an access. */ 283 Tick pioDelay; 284 285 public: 286 BasicPioDevice(Params *p) 287 : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) 288 {} 289 290 /** return the address ranges that this device responds to. 291 * @params range_list range list to populate with ranges 292 */ 293 void addressRanges(AddrRangeList &range_list); 294 295}; 296 297class DmaDevice : public PioDevice 298{ 299 protected: 300 DmaPort *dmaPort; 301 302 public: 303 DmaDevice(Params *p); 304 virtual ~DmaDevice(); 305 306 void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) 307 { dmaPort->dmaAction(Write, addr, size, event, data) ; } 308 309 void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL) 310 { dmaPort->dmaAction(Read, addr, size, event, data); } 311 312 bool dmaPending() { return dmaPort->dmaPending(); } 313 314 virtual Port *getPort(const std::string &if_name) 315 { 316 if (if_name == "pio") { 317 if (pioPort != NULL) 318 panic("pio port already connected to."); 319 pioPort = new PioPort(this, params()->platform); 320 return pioPort; 321 } else if (if_name == "dma") { 322 if (dmaPort != NULL) 323 panic("dma port already connected to."); 324 dmaPort = new DmaPort(this, params()->platform); 325 return dmaPort; 326 } else 327 return NULL; 328 } 329 330 friend class DmaPort; 331}; 332 333 334#endif // __DEV_IO_DEVICE_HH__ 335