io_device.hh revision 2541
14202Sbinkertn@umich.edu/* 24202Sbinkertn@umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 34202Sbinkertn@umich.edu * All rights reserved. 44202Sbinkertn@umich.edu * 54202Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 64202Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are 74202Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright 84202Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer; 94202Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright 104202Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 114202Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution; 124202Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its 134202Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from 144202Sbinkertn@umich.edu * this software without specific prior written permission. 154202Sbinkertn@umich.edu * 164202Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 174202Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 184202Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 194202Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 204202Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 214202Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 224202Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234202Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244202Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254202Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 264202Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274202Sbinkertn@umich.edu */ 284202Sbinkertn@umich.edu 294202Sbinkertn@umich.edu#ifndef __DEV_IO_DEVICE_HH__ 304202Sbinkertn@umich.edu#define __DEV_IO_DEVICE_HH__ 314202Sbinkertn@umich.edu 324202Sbinkertn@umich.edu#include "base/chunk_generator.hh" 335952Ssaidi@eecs.umich.edu#include "mem/port.hh" 345952Ssaidi@eecs.umich.edu#include "sim/eventq.hh" 355952Ssaidi@eecs.umich.edu#include "sim/sim_object.hh" 365548Snate@binkert.org 374202Sbinkertn@umich.educlass Platform; 384202Sbinkertn@umich.educlass PioDevice; 394202Sbinkertn@umich.educlass DmaDevice; 404202Sbinkertn@umich.educlass System; 415882Snate@binkert.org 424202Sbinkertn@umich.edu/** 434550Sbinkertn@umich.edu * The PioPort class is a programmed i/o port that all devices that are 444550Sbinkertn@umich.edu * sensitive to an address range use. The port takes all the memory 454202Sbinkertn@umich.edu * access types and roles them into one read() and write() call that the device 464202Sbinkertn@umich.edu * must respond to. The device must also provide the addressRanges() function 474202Sbinkertn@umich.edu * with which it returns the address ranges it is interested in. An extra 484202Sbinkertn@umich.edu * sendTiming() function is implemented which takes an delay. In this way the 494202Sbinkertn@umich.edu * device can immediatly call sendTiming(pkt, time) after processing a request 504202Sbinkertn@umich.edu * and the request will be handled by the port even if the port bus the device 514202Sbinkertn@umich.edu * connects to is blocked. 524202Sbinkertn@umich.edu */ 534202Sbinkertn@umich.educlass PioPort : public Port 544202Sbinkertn@umich.edu{ 554202Sbinkertn@umich.edu protected: 565190Ssaidi@eecs.umich.edu /** The device that this port serves. */ 574202Sbinkertn@umich.edu PioDevice *device; 584202Sbinkertn@umich.edu 594202Sbinkertn@umich.edu /** The platform that device/port are in. This is used to select which mode 604202Sbinkertn@umich.edu * we are currently operating in. */ 614202Sbinkertn@umich.edu Platform *platform; 624202Sbinkertn@umich.edu 634202Sbinkertn@umich.edu /** A list of outgoing timing response packets that haven't been serviced 644202Sbinkertn@umich.edu * yet. */ 654202Sbinkertn@umich.edu std::list<Packet*> transmitList; 664202Sbinkertn@umich.edu 674202Sbinkertn@umich.edu /** The current status of the peer(bus) that we are connected to. */ 684202Sbinkertn@umich.edu Status peerStatus; 694202Sbinkertn@umich.edu 704202Sbinkertn@umich.edu virtual bool recvTiming(Packet &pkt); 714202Sbinkertn@umich.edu 725222Sksewell@umich.edu virtual Tick recvAtomic(Packet &pkt); 734202Sbinkertn@umich.edu 744202Sbinkertn@umich.edu virtual void recvFunctional(Packet &pkt) ; 754202Sbinkertn@umich.edu 764202Sbinkertn@umich.edu virtual void recvStatusChange(Status status) 774202Sbinkertn@umich.edu { peerStatus = status; } 784202Sbinkertn@umich.edu 794202Sbinkertn@umich.edu virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); 804202Sbinkertn@umich.edu 814202Sbinkertn@umich.edu /** 824202Sbinkertn@umich.edu * This class is used to implemented sendTiming() with a delay. When a delay 834202Sbinkertn@umich.edu * is requested a new event is created. When the event time expires it 844202Sbinkertn@umich.edu * attempts to send the packet. If it cannot, the packet is pushed onto the 854382Sbinkertn@umich.edu * transmit list to be sent when recvRetry() is called. */ 865800Snate@binkert.org class SendEvent : public Event 875952Ssaidi@eecs.umich.edu { 885952Ssaidi@eecs.umich.edu PioPort *port; 895800Snate@binkert.org Packet packet; 905800Snate@binkert.org 915800Snate@binkert.org SendEvent(PioPort *p, Packet &pkt, Tick t) 925800Snate@binkert.org : Event(&mainEventQueue), packet(pkt) 935800Snate@binkert.org { schedule(curTick + t); } 945800Snate@binkert.org 955800Snate@binkert.org virtual void process(); 965800Snate@binkert.org 975800Snate@binkert.org virtual const char *description() 985192Ssaidi@eecs.umich.edu { return "Future scheduled sendTiming event"; } 995800Snate@binkert.org 1005800Snate@binkert.org friend class PioPort; 1015800Snate@binkert.org }; 1025800Snate@binkert.org 1035952Ssaidi@eecs.umich.edu /** Schedule a sendTiming() event to be called in the future. */ 1045952Ssaidi@eecs.umich.edu void sendTiming(Packet &pkt, Tick time) 1055952Ssaidi@eecs.umich.edu { new PioPort::SendEvent(this, pkt, time); } 106 107 /** This function pops the last element off the transmit list and sends it.*/ 108 virtual Packet *recvRetry(); 109 110 public: 111 PioPort(PioDevice *dev, Platform *p); 112 113 friend class PioPort::SendEvent; 114}; 115 116class DmaPort : public Port 117{ 118 protected: 119 PioDevice *device; 120 std::list<Packet*> transmitList; 121 Event *completionEvent; 122 123 124 virtual bool recvTiming(Packet &pkt); 125 virtual Tick recvAtomic(Packet &pkt) 126 { panic("dma port shouldn't be used for pio access."); } 127 virtual void recvFunctional(Packet &pkt) 128 { panic("dma port shouldn't be used for pio access."); } 129 130 virtual void recvStatusChange(Status status) 131 { ; } 132 133 virtual Packet *recvRetry() ; 134 135 virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 136 { resp.clear(); snoop.clear(); } 137 138 class SendEvent : public Event 139 { 140 DmaPort *port; 141 Packet packet; 142 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 * @param pkt Packet describing this request 197 * @return number of ticks it took to complete 198 */ 199 virtual Tick read(Packet &pkt) = 0; 200 201 /** Pure virtual function that the device must implement. Called when a 202 * write command is recieved by the port. 203 * @param pkt Packet describing this request 204 * @return number of ticks it took to complete 205 */ 206 virtual Tick write(Packet &pkt) = 0; 207 208 public: 209 /** Params struct which is extended through each device based on the 210 * parameters it needs. Since we are re-writing everything, we might as well 211 * start from the bottom this time. */ 212 213 struct Params 214 { 215 std::string name; 216 Platform *platform; 217 System *system; 218 }; 219 220 protected: 221 Params *_params; 222 223 public: 224 const Params *params() const { return _params; } 225 226 PioDevice(Params *p) 227 : SimObject(params()->name), platform(p->platform), _params(p) 228 {} 229 230 virtual ~PioDevice(); 231 232 virtual void init(); 233 234 virtual Port *getPort(const std::string &if_name) 235 { 236 if (if_name == "pio") { 237 if (pioPort != NULL) 238 panic("pio port already connected to."); 239 pioPort = new PioPort(this, params()->platform); 240 return pioPort; 241 } else 242 return NULL; 243 } 244 friend class PioPort; 245 246}; 247 248class BasicPioDevice : public PioDevice 249{ 250 public: 251 struct Params : public PioDevice::Params 252 { 253 Addr pio_addr; 254 Tick pio_delay; 255 }; 256 257 protected: 258 /** Address that the device listens to. */ 259 Addr pioAddr; 260 261 /** Size that the device's address range. */ 262 Addr pioSize; 263 264 /** Delay that the device experinces on an access. */ 265 Tick pioDelay; 266 267 public: 268 BasicPioDevice(Params *p) 269 : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) 270 {} 271 272 /** return the address ranges that this device responds to. 273 * @params range_list range list to populate with ranges 274 */ 275 addressRanges(AddrRangeList &range_list); 276 277}; 278 279class DmaDevice : public PioDevice 280{ 281 protected: 282 DmaPort *dmaPort; 283 284 public: 285 DmaDevice(Params *p); 286 virtual ~DmaDevice(); 287 288 virtual Port *getPort(const std::string &if_name) 289 { 290 if (if_name == "pio") 291 return pioPort; 292 else if (if_name == "dma") 293 return dmaPort; 294 else 295 return NULL; 296 } 297 298 friend class DmaPort; 299}; 300 301 302#endif // __DEV_IO_DEVICE_HH__ 303