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