io_device.hh revision 2512
16145SN/A/* 28683SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 38683SN/A * All rights reserved. 46145SN/A * 56145SN/A * Redistribution and use in source and binary forms, with or without 66145SN/A * modification, are permitted provided that the following conditions are 76145SN/A * met: redistributions of source code must retain the above copyright 86145SN/A * notice, this list of conditions and the following disclaimer; 96145SN/A * redistributions in binary form must reproduce the above copyright 106145SN/A * notice, this list of conditions and the following disclaimer in the 116145SN/A * documentation and/or other materials provided with the distribution; 126145SN/A * neither the name of the copyright holders nor the names of its 136145SN/A * contributors may be used to endorse or promote products derived from 146145SN/A * this software without specific prior written permission. 156145SN/A * 166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276145SN/A */ 286145SN/A 296145SN/A#ifndef __DEV_IO_DEVICE_HH__ 3011793Sbrandon.potter@amd.com#define __DEV_IO_DEVICE_HH__ 3111793Sbrandon.potter@amd.com 328683SN/A#include "base/chunk_generator.hh" 3311108Sdavid.hashe@amd.com#include "mem/port.hh" 348683SN/A#include "sim/eventq.hh" 356145SN/A#include "sim/sim_object.hh" 367055SN/A 377055SN/Aclass Platform; 387054SN/Aclass PioDevice; 398683SN/Aclass DmaDevice; 406145SN/A 418683SN/A/** 428683SN/A * The PioPort class is a programmed i/o port that all devices that are 438683SN/A * sensitive to an address range use. The port takes all the memory 448683SN/A * access types and roles them into one read() and write() call that the device 458683SN/A * must respond to. The device must also provide the addressRanges() function 468683SN/A * with which it returns the address ranges it is interested in. An extra 478683SN/A * sendTiming() function is implemented which takes an delay. In this way the 4810163SN/A * device can immediatly call sendTiming(pkt, time) after processing a request 4910163SN/A * and the request will be handled by the port even if the port bus the device 508683SN/A * connects to is blocked. 518683SN/A */ 528683SN/Aclass PioPort : public Port 538683SN/A{ 548683SN/A protected: 5510163SN/A /** The device that this port serves. */ 5610163SN/A PioDevice *device; 578683SN/A 588683SN/A /** The platform that device/port are in. This is used to select which mode 598683SN/A * we are currently operating in. */ 6010163SN/A Platform *platform; 618683SN/A 6211049Snilay@cs.wisc.edu /** A list of outgoing timing response packets that haven't been serviced 6311049Snilay@cs.wisc.edu * yet. */ 6411049Snilay@cs.wisc.edu std::list<Packet*> transmitList; 6511049Snilay@cs.wisc.edu 6611049Snilay@cs.wisc.edu /** The current status of the peer(bus) that we are connected to. */ 6711049Snilay@cs.wisc.edu Status peerStatus; 6811049Snilay@cs.wisc.edu 6911049Snilay@cs.wisc.edu virtual bool recvTiming(Packet &pkt); 7011049Snilay@cs.wisc.edu 718683SN/A virtual Tick recvAtomic(Packet &pkt); 728683SN/A 738683SN/A virtual void recvFunctional(Packet &pkt) ; 748683SN/A 758683SN/A virtual void recvStatusChange(Status status) 769627SN/A { peerStatus = status; } 778683SN/A 788683SN/A virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner); 798683SN/A 808683SN/A /** 818683SN/A * This class is used to implemented sendTiming() with a delay. When a delay 828683SN/A * is requested a new event is created. When the event time expires it 838683SN/A * attempts to send the packet. If it cannot, the packet is pushed onto the 848683SN/A * transmit list to be sent when recvRetry() is called. */ 858683SN/A class SendEvent : public Event 868683SN/A { 878683SN/A PioPort *port; 8812749Sgiacomo.travaglini@arm.com Packet packet; 8912749Sgiacomo.travaglini@arm.com 9012749Sgiacomo.travaglini@arm.com SendEvent(PioPort *p, Packet &pkt, Tick t) 918683SN/A : Event(&mainEventQueue), packet(pkt) 928949SN/A { schedule(curTick + t); } 938683SN/A 948683SN/A virtual void process(); 958683SN/A 968683SN/A virtual const char *description() 978683SN/A { return "Future scheduled sendTiming event"; } 988683SN/A 9910991Stimothy.jones@cl.cam.ac.uk friend class PioPort; 10010991Stimothy.jones@cl.cam.ac.uk }; 1018683SN/A 1028683SN/A /** Schedule a sendTiming() event to be called in the future. */ 1038683SN/A void sendTiming(Packet &pkt, Tick time) 1048683SN/A { new PioPort::SendEvent(this, pkt, time); } 1058683SN/A 1068683SN/A /** This function pops the last element off the transmit list and sends it.*/ 1078683SN/A virtual Packet *recvRetry(); 1088683SN/A 1098683SN/A public: 1108683SN/A PioPort(PioDevice *dev, Platform *p); 1118683SN/A 1128683SN/A friend class PioPort::SendEvent; 11310163SN/A}; 11410163SN/A 11512749Sgiacomo.travaglini@arm.comclass DmaPort : public Port 11610163SN/A{ 11710163SN/A protected: 11810163SN/A PioDevice *device; 11910163SN/A std::list<Packet*> transmitList; 12012749Sgiacomo.travaglini@arm.com Event *completionEvent; 12112749Sgiacomo.travaglini@arm.com 12210163SN/A 12310163SN/A virtual bool recvTiming(Packet &pkt); 12410163SN/A virtual Tick recvAtomic(Packet &pkt) 12512749Sgiacomo.travaglini@arm.com { panic("dma port shouldn't be used for pio access."); } 12612749Sgiacomo.travaglini@arm.com virtual void recvFunctional(Packet &pkt) 12710163SN/A { panic("dma port shouldn't be used for pio access."); } 12810163SN/A 12910163SN/A virtual void recvStatusChange(Status status) 13010163SN/A { ; } 13112749Sgiacomo.travaglini@arm.com 13212749Sgiacomo.travaglini@arm.com virtual Packet *recvRetry() ; 13310163SN/A 13410163SN/A virtual void getDeviceAddressRanges(AddrRangeList &range_list, bool &owner) 13510163SN/A { range_list.clear(); owner = true; } 13610163SN/A 13710163SN/A class SendEvent : public Event 13810163SN/A { 13910163SN/A DmaPort *port; 14010163SN/A Packet packet; 14110163SN/A 1428683SN/A SendEvent(PioPort *p, Packet &pkt, Tick t) 1438683SN/A : Event(&mainEventQueue), packet(pkt) 14410163SN/A { schedule(curTick + t); } 1458683SN/A 14610991Stimothy.jones@cl.cam.ac.uk virtual void process(); 14710991Stimothy.jones@cl.cam.ac.uk 1488683SN/A virtual const char *description() 1498683SN/A { return "Future scheduled sendTiming event"; } 1508683SN/A 1518683SN/A friend class DmaPort; 15211025Snilay@cs.wisc.edu }; 15310302Snilay@cs.wisc.edu 1548683SN/A void dmaAction(Command cmd, DmaPort port, Addr addr, int size, 1558683SN/A Event *event, uint8_t *data = NULL); 15610163SN/A 1578683SN/A void sendDma(Packet &pkt); 1588683SN/A 1598683SN/A public: 1608683SN/A DmaPort(DmaDevice *dev); 1618683SN/A 16210163SN/A friend class DmaPort::SendEvent; 16310163SN/A 1648683SN/A}; 1657456SN/A 1666145SN/A/** 1676145SN/A * This device is the base class which all devices senstive to an address range 16811061Snilay@cs.wisc.edu * inherit from. There are three pure virtual functions which all devices must 16911061Snilay@cs.wisc.edu * implement addressRanges(), read(), and write(). The magic do choose which 1706145SN/A * mode we are in, etc is handled by the PioPort so the device doesn't have to 1718683SN/A * bother. 1728683SN/A */ 1738683SN/A 17411061Snilay@cs.wisc.educlass PioDevice : public SimObject 17510163SN/A{ 1768683SN/A protected: 1778683SN/A 1788683SN/A /** The platform we are in. This is used to decide what type of memory 1798683SN/A * transaction we should perform. */ 1808683SN/A Platform *platform; 1818683SN/A 1828683SN/A /** The pioPort that handles the requests for us and provides us requests 1838683SN/A * that it sees. */ 1848683SN/A PioPort *pioPort; 1858683SN/A 1868683SN/A virtual void addressRanges(AddrRangeList &range_list, bool &owner) = 0; 1878683SN/A 1888683SN/A /** As far as the devices are concerned they only accept atomic transactions 1898683SN/A * which are converted to either a write or a read. */ 1908683SN/A Tick recvAtomic(Packet &pkt) 1918683SN/A { return pkt.cmd == Read ? this->read(pkt) : this->write(pkt); } 1928683SN/A 1938683SN/A /** Pure virtual function that the device must implement. Called when a read 1948683SN/A * command is recieved by the port. */ 1958683SN/A virtual Tick read(Packet &pkt) = 0; 1968683SN/A 1978683SN/A /** Pure virtual function that the device must implement. Called when a 1987054SN/A * write command is recieved by the port. */ 1996145SN/A virtual Tick write(Packet &pkt) = 0; 2007456SN/A 2018683SN/A public: 2026145SN/A /** 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