io_device.hh revision 2522
1754SN/A/* 21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 3754SN/A * All rights reserved. 4754SN/A * 5754SN/A * Redistribution and use in source and binary forms, with or without 6754SN/A * modification, are permitted provided that the following conditions are 7754SN/A * met: redistributions of source code must retain the above copyright 8754SN/A * notice, this list of conditions and the following disclaimer; 9754SN/A * redistributions in binary form must reproduce the above copyright 10754SN/A * notice, this list of conditions and the following disclaimer in the 11754SN/A * documentation and/or other materials provided with the distribution; 12754SN/A * neither the name of the copyright holders nor the names of its 13754SN/A * contributors may be used to endorse or promote products derived from 14754SN/A * this software without specific prior written permission. 15754SN/A * 16754SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17754SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18754SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19754SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20754SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21754SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22754SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23754SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24754SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25754SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26754SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu#ifndef __DEV_IO_DEVICE_HH__ 30754SN/A#define __DEV_IO_DEVICE_HH__ 31754SN/A 32754SN/A#include "base/chunk_generator.hh" 33754SN/A#include "mem/port.hh" 341070SN/A#include "sim/eventq.hh" 352680Sktlim@umich.edu#include "sim/sim_object.hh" 363565Sgblack@eecs.umich.edu 371108SN/Aclass Platform; 382235SN/Aclass PioDevice; 39754SN/Aclass DmaDevice; 40754SN/Aclass System; 41754SN/A 42754SN/A/** 431070SN/A * The PioPort class is a programmed i/o port that all devices that are 441070SN/A * sensitive to an address range use. The port takes all the memory 452190SN/A * access types and roles them into one read() and write() call that the device 463548SN/A * must respond to. The device must also provide the addressRanges() function 47754SN/A * with which it returns the address ranges it is interested in. An extra 481070SN/A * sendTiming() function is implemented which takes an delay. In this way the 49754SN/A * device can immediatly call sendTiming(pkt, time) after processing a request 50754SN/A * and the request will be handled by the port even if the port bus the device 511070SN/A * connects to is blocked. 52754SN/A */ 531070SN/Aclass PioPort : public Port 54754SN/A{ 55754SN/A protected: 561070SN/A /** The device that this port serves. */ 57754SN/A PioDevice *device; 58754SN/A 59754SN/A /** The platform that device/port are in. This is used to select which mode 60754SN/A * we are currently operating in. */ 611070SN/A Platform *platform; 62754SN/A 63754SN/A /** A list of outgoing timing response packets that haven't been serviced 64754SN/A * yet. */ 65754SN/A std::list<Packet*> transmitList; 66754SN/A 671070SN/A /** The current status of the peer(bus) that we are connected to. */ 68754SN/A Status peerStatus; 69754SN/A 70754SN/A virtual bool recvTiming(Packet &pkt); 71754SN/A 72754SN/A virtual Tick recvAtomic(Packet &pkt); 73754SN/A 741070SN/A virtual void recvFunctional(Packet &pkt) ; 75754SN/A 76754SN/A virtual void recvStatusChange(Status status) 77754SN/A { peerStatus = status; } 78754SN/A 79754SN/A virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); 80754SN/A 811070SN/A /** 82754SN/A * This class is used to implemented sendTiming() with a delay. When a delay 83754SN/A * is requested a new event is created. When the event time expires it 84754SN/A * attempts to send the packet. If it cannot, the packet is pushed onto the 85754SN/A * transmit list to be sent when recvRetry() is called. */ 86754SN/A class SendEvent : public Event 871070SN/A { 88754SN/A PioPort *port; 89754SN/A Packet packet; 90754SN/A 91754SN/A SendEvent(PioPort *p, Packet &pkt, Tick t) 92754SN/A : Event(&mainEventQueue), packet(pkt) 93754SN/A { schedule(curTick + t); } 94754SN/A 95754SN/A virtual void process(); 961070SN/A 97754SN/A virtual const char *description() 98754SN/A { return "Future scheduled sendTiming event"; } 99754SN/A 100754SN/A friend class PioPort; 1013563SN/A }; 1023563SN/A 103754SN/A /** Schedule a sendTiming() event to be called in the future. */ 1043563SN/A void sendTiming(Packet &pkt, Tick time) 105754SN/A { new PioPort::SendEvent(this, pkt, time); } 106754SN/A 107754SN/A /** This function pops the last element off the transmit list and sends it.*/ 108754SN/A virtual Packet *recvRetry(); 1093563SN/A 1101070SN/A public: 111754SN/A PioPort(PioDevice *dev, Platform *p); 112754SN/A 1131070SN/A friend class PioPort::SendEvent; 114754SN/A}; 115754SN/A 116754SN/Aclass DmaPort : public Port 117754SN/A{ 118754SN/A protected: 119754SN/A PioDevice *device; 120754SN/A std::list<Packet*> transmitList; 121754SN/A Event *completionEvent; 122754SN/A 1237823Ssteve.reinhardt@amd.com 1247823Ssteve.reinhardt@amd.com virtual bool recvTiming(Packet &pkt); 125754SN/A virtual Tick recvAtomic(Packet &pkt) 126754SN/A { panic("dma port shouldn't be used for pio access."); } 127754SN/A virtual void recvFunctional(Packet &pkt) 128754SN/A { panic("dma port shouldn't be used for pio access."); } 1291070SN/A 1301070SN/A virtual void recvStatusChange(Status status) 1311097SN/A { ; } 1321097SN/A 1331070SN/A virtual Packet *recvRetry() ; 134754SN/A 1351070SN/A virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 1361070SN/A { resp.clear(); snoop.clear(); } 1371070SN/A 1381097SN/A class SendEvent : public Event 1391097SN/A { 1401070SN/A DmaPort *port; 141754SN/A Packet packet; 1427811Ssteve.reinhardt@amd.com 143 SendEvent(PioPort *p, Packet &pkt, Tick t) 144 : Event(&mainEventQueue), packet(pkt) 145 { schedule(curTick + t); } 146 147 virtual void process(); 148 149 virtual const char *description() 150 { return "Future scheduled sendTiming event"; } 151 152 friend class DmaPort; 153 }; 154 155 void dmaAction(Command cmd, DmaPort port, Addr addr, int size, 156 Event *event, uint8_t *data = NULL); 157 158 void sendDma(Packet &pkt); 159 160 public: 161 DmaPort(DmaDevice *dev); 162 163 friend class DmaPort::SendEvent; 164 165}; 166 167/** 168 * This device is the base class which all devices senstive to an address range 169 * inherit from. There are three pure virtual functions which all devices must 170 * implement addressRanges(), read(), and write(). The magic do choose which 171 * mode we are in, etc is handled by the PioPort so the device doesn't have to 172 * bother. 173 */ 174 175class PioDevice : public SimObject 176{ 177 protected: 178 179 /** The platform we are in. This is used to decide what type of memory 180 * transaction we should perform. */ 181 Platform *platform; 182 183 /** The pioPort that handles the requests for us and provides us requests 184 * that it sees. */ 185 PioPort *pioPort; 186 187 virtual void addressRanges(AddrRangeList &range_list) = 0; 188 189 /** As far as the devices are concerned they only accept atomic transactions 190 * which are converted to either a write or a read. */ 191 Tick recvAtomic(Packet &pkt) 192 { return pkt.cmd == Read ? this->read(pkt) : this->write(pkt); } 193 194 /** Pure virtual function that the device must implement. Called when a read 195 * command is recieved by the port. */ 196 virtual Tick read(Packet &pkt) = 0; 197 198 /** Pure virtual function that the device must implement. Called when a 199 * write command is recieved by the port. */ 200 virtual Tick write(Packet &pkt) = 0; 201 202 public: 203 /** Params struct which is extended through each device based on the 204 * parameters it needs. Since we are re-writing everything, we might as well 205 * start from the bottom this time. */ 206 207 struct Params 208 { 209 std::string name; 210 Platform *platform; 211 System *system; 212 }; 213 214 protected: 215 Params *_params; 216 217 public: 218 const Params *params() const { return _params; } 219 220 PioDevice(Params *p) 221 : SimObject(params()->name), platform(p->platform), _params(p) 222 {} 223 224 virtual ~PioDevice(); 225 226 virtual Port *getPort(const std::string &if_name) 227 { 228 if (if_name == "pio") { 229 if (pioPort != NULL) 230 panic("pio port already connected to."); 231 pioPort = new PioPort(this, params()->platform); 232 return pioPort; 233 } else 234 return NULL; 235 } 236 friend class PioPort; 237 238}; 239 240class BasicPioDevice : public PioDevice 241{ 242 public: 243 struct Params : public PioDevice::Params 244 { 245 Addr pio_addr; 246 Tick pio_delay; 247 }; 248 249 protected: 250 /** Address that the device listens to. */ 251 Addr pioAddr; 252 253 /** Size that the device's address range. */ 254 Addr pioSize; 255 256 /** Delay that the device experinces on an access. */ 257 Tick pioDelay; 258 259 public: 260 BasicPioDevice(Params *p) 261 : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) 262 {} 263 264}; 265 266class DmaDevice : public PioDevice 267{ 268 protected: 269 DmaPort *dmaPort; 270 271 public: 272 DmaDevice(Params *p); 273 virtual ~DmaDevice(); 274 275 virtual Port *getPort(const std::string &if_name) 276 { 277 if (if_name == "pio") 278 return pioPort; 279 else if (if_name == "dma") 280 return dmaPort; 281 else 282 return NULL; 283 } 284 285 friend class DmaPort; 286}; 287 288 289#endif // __DEV_IO_DEVICE_HH__ 290