io_device.hh revision 2512
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 &range_list, bool &owner); 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 &range_list, bool &owner) 135 { range_list.clear(); owner = true; } 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, bool &owner) = 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 protected: 212 Params *_params; 213 214 public: 215 const Params *params() const { return _params; } 216 217 PioDevice(Params *params) 218 : SimObject(params()->name), platform(params()->platform) 219 {} 220 221 virtual ~PioDevice(); 222 223 virtual Port *getPort(const std::string &if_name) 224 { 225 if (if_name == "pio") 226 if (pioPort != NULL) 227 panic("pio port already connected to."); 228 pioPort = new PioPort(this, params()->platform); 229 return pioPort; 230 else 231 return NULL; 232 } 233 friend class PioPort; 234 235}; 236 237class BasicPioDevice : public PioDevice 238{ 239 public: 240 struct Params 241 { 242 Addr pio_addr; 243 Tick pio_delay; 244 }; 245 246 protected: 247 /** Address that the device listens to. */ 248 Addr pioAddr; 249 250 /** Size that the device's address range. */ 251 Addr pioSize = 0; 252 253 /** Delay that the device experinces on an access. */ 254 Tick pioDelay; 255 256 public: 257 BasePioDevice(Params *p) 258 : PioDevice(p), pioAddr(p->pio_addr), pioDelay(p->pioDelay) 259 {} 260 261 virtual void addressRanges(AddrRangeList &range_list, bool &owner); 262}; 263 264class DmaDevice : public PioDevice 265{ 266 protected: 267 DmaPort *dmaPort; 268 269 public: 270 DmaDevice(const std::string &name, Platform *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