io_device.hh revision 2512
12023SN/A/* 22023SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 32023SN/A * All rights reserved. 42023SN/A * 52023SN/A * Redistribution and use in source and binary forms, with or without 62023SN/A * modification, are permitted provided that the following conditions are 72023SN/A * met: redistributions of source code must retain the above copyright 82023SN/A * notice, this list of conditions and the following disclaimer; 92023SN/A * redistributions in binary form must reproduce the above copyright 102023SN/A * notice, this list of conditions and the following disclaimer in the 112023SN/A * documentation and/or other materials provided with the distribution; 122023SN/A * neither the name of the copyright holders nor the names of its 132023SN/A * contributors may be used to endorse or promote products derived from 142023SN/A * this software without specific prior written permission. 152023SN/A * 162023SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172023SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182023SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192023SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202023SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212023SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222023SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232023SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242023SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252023SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262023SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272023SN/A */ 282023SN/A 292023SN/A#ifndef __DEV_IO_DEVICE_HH__ 302023SN/A#define __DEV_IO_DEVICE_HH__ 312023SN/A 322225SN/A#include "base/chunk_generator.hh" 332225SN/A#include "mem/port.hh" 342225SN/A#include "sim/eventq.hh" 352225SN/A#include "sim/sim_object.hh" 362225SN/A 372023SN/Aclass Platform; 382023SN/Aclass PioDevice; 392225SN/Aclass DmaDevice; 402023SN/A 412225SN/A/** 422225SN/A * The PioPort class is a programmed i/o port that all devices that are 432023SN/A * sensitive to an address range use. The port takes all the memory 442458SN/A * access types and roles them into one read() and write() call that the device 452023SN/A * must respond to. The device must also provide the addressRanges() function 462225SN/A * with which it returns the address ranges it is interested in. An extra 472225SN/A * sendTiming() function is implemented which takes an delay. In this way the 482225SN/A * device can immediatly call sendTiming(pkt, time) after processing a request 492225SN/A * and the request will be handled by the port even if the port bus the device 502225SN/A * connects to is blocked. 512225SN/A */ 522225SN/Aclass PioPort : public Port 532225SN/A{ 542225SN/A protected: 552225SN/A /** The device that this port serves. */ 562023SN/A PioDevice *device; 572225SN/A 582225SN/A /** The platform that device/port are in. This is used to select which mode 592225SN/A * we are currently operating in. */ 602225SN/A Platform *platform; 612225SN/A 622225SN/A /** A list of outgoing timing response packets that haven't been serviced 632023SN/A * yet. */ 642225SN/A std::list<Packet*> transmitList; 652023SN/A 662225SN/A /** The current status of the peer(bus) that we are connected to. */ 672225SN/A Status peerStatus; 682225SN/A 692225SN/A virtual bool recvTiming(Packet &pkt); 702225SN/A 712225SN/A virtual Tick recvAtomic(Packet &pkt); 722023SN/A 732225SN/A virtual void recvFunctional(Packet &pkt) ; 742225SN/A 752023SN/A virtual void recvStatusChange(Status status) 762225SN/A { peerStatus = status; } 772225SN/A 782225SN/A virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner); 792023SN/A 802023SN/A /** 812023SN/A * This class is used to implemented sendTiming() with a delay. When a delay 822023SN/A * is requested a new event is created. When the event time expires it 832023SN/A * attempts to send the packet. If it cannot, the packet is pushed onto the 842458SN/A * transmit list to be sent when recvRetry() is called. */ 852458SN/A class SendEvent : public Event 862469SN/A { 872469SN/A PioPort *port; 882469SN/A Packet packet; 892469SN/A 902469SN/A SendEvent(PioPort *p, Packet &pkt, Tick t) 912469SN/A : Event(&mainEventQueue), packet(pkt) 922469SN/A { schedule(curTick + t); } 932501SN/A 942501SN/A virtual void process(); 952501SN/A 962469SN/A virtual const char *description() 972469SN/A { return "Future scheduled sendTiming event"; } 982458SN/A 992458SN/A friend class PioPort; 1002023SN/A }; 1012458SN/A 1022458SN/A /** Schedule a sendTiming() event to be called in the future. */ 1032458SN/A void sendTiming(Packet &pkt, Tick time) 1042458SN/A { new PioPort::SendEvent(this, pkt, time); } 1052458SN/A 1062458SN/A /** This function pops the last element off the transmit list and sends it.*/ 1072458SN/A virtual Packet *recvRetry(); 1082458SN/A 1092458SN/A public: 1102458SN/A PioPort(PioDevice *dev, Platform *p); 1112458SN/A 1122458SN/A friend class PioPort::SendEvent; 1132458SN/A}; 1142458SN/A 1152458SN/Aclass DmaPort : public Port 1162458SN/A{ 1172458SN/A protected: 1182458SN/A PioDevice *device; 1192458SN/A std::list<Packet*> transmitList; 1202458SN/A Event *completionEvent; 1212510SN/A 1222458SN/A 1232458SN/A virtual bool recvTiming(Packet &pkt); 1242458SN/A virtual Tick recvAtomic(Packet &pkt) 1252525SN/A { panic("dma port shouldn't be used for pio access."); } 1262561SN/A virtual void recvFunctional(Packet &pkt) 1272458SN/A { panic("dma port shouldn't be used for pio access."); } 1282458SN/A 1292458SN/A virtual void recvStatusChange(Status status) 1302458SN/A { ; } 1312458SN/A 1322458SN/A virtual Packet *recvRetry() ; 1332458SN/A 1342458SN/A virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner) 1352458SN/A { range_list.clear(); owner = true; } 1362458SN/A 1372458SN/A class SendEvent : public Event 1382458SN/A { 1392458SN/A DmaPort *port; 1402458SN/A Packet packet; 1412458SN/A 1422458SN/A SendEvent(PioPort *p, Packet &pkt, Tick t) 1432458SN/A : Event(&mainEventQueue), packet(pkt) 1442458SN/A { schedule(curTick + t); } 1452458SN/A 1462458SN/A virtual void process(); 1472474SN/A 1482458SN/A virtual const char *description() 1492458SN/A { return "Future scheduled sendTiming event"; } 1502458SN/A 1512458SN/A friend class DmaPort; 1522458SN/A }; 1532458SN/A 1542458SN/A void dmaAction(Command cmd, DmaPort port, Addr addr, int size, 1552458SN/A Event *event, uint8_t *data = NULL); 1562469SN/A 1572458SN/A void sendDma(Packet &pkt); 1582458SN/A 1592458SN/A public: 1602458SN/A DmaPort(DmaDevice *dev); 1612458SN/A 1622458SN/A friend class DmaPort::SendEvent; 1632458SN/A 1642458SN/A}; 1652458SN/A 1662458SN/A/** 1672458SN/A * This device is the base class which all devices senstive to an address range 1682458SN/A * inherit from. There are three pure virtual functions which all devices must 1692458SN/A * implement addressRanges(), read(), and write(). The magic do choose which 1702458SN/A * mode we are in, etc is handled by the PioPort so the device doesn't have to 1712458SN/A * bother. 1722458SN/A */ 1732458SN/A 1742458SN/Aclass PioDevice : public SimObject 1752646Ssaidi@eecs.umich.edu{ 1762646Ssaidi@eecs.umich.edu protected: 1772525SN/A 1782458SN/A /** The platform we are in. This is used to decide what type of memory 1792646Ssaidi@eecs.umich.edu * transaction we should perform. */ 1802646Ssaidi@eecs.umich.edu Platform *platform; 1812525SN/A 1822458SN/A /** The pioPort that handles the requests for us and provides us requests 1832458SN/A * that it sees. */ 1842023SN/A PioPort *pioPort; 1852458SN/A 1862023SN/A virtual void addressRanges(AddrRangeList &range_list, bool &owner) = 0; 1872023SN/A 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