io_device.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 304 行
HH
304 行
/* * Copyright (c) 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Ali G. Saidi * Nathan L. Binkert */#ifndef __DEV_IO_DEVICE_HH__#define __DEV_IO_DEVICE_HH__#include "mem/mem_object.hh"#include "mem/packet.hh"#include "mem/tport.hh"#include "params/BasicPioDevice.hh"#include "params/DmaDevice.hh"#include "params/PioDevice.hh"#include "sim/sim_object.hh"class Event;class Platform;class PioDevice;class DmaDevice;class System;/** * The PioPort class is a programmed i/o port that all devices that are * sensitive to an address range use. The port takes all the memory * access types and roles them into one read() and write() call that the device * must respond to. The device must also provide the addressRanges() function * with which it returns the address ranges it is interested in. */class PioPort : public SimpleTimingPort{ protected: /** The device that this port serves. */ PioDevice *device; virtual Tick recvAtomic(PacketPtr pkt); virtual void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop); public: PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");};class DmaPort : public Port{ protected: struct DmaReqState : public Packet::SenderState { /** Event to call on the device when this transaction (all packets) * complete. */ Event *completionEvent; /** Where we came from for some sanity checking. */ Port *outPort; /** Total number of bytes that this transaction involves. */ Addr totBytes; /** Number of bytes that have been acked for this transaction. */ Addr numBytes; DmaReqState(Event *ce, Port *p, Addr tb) : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0) {} }; DmaDevice *device; std::list<PacketPtr> transmitList; /** The system that device/port are in. This is used to select which mode * we are currently operating in. */ System *sys; /** Number of outstanding packets the dma port has. */ int pendingCount; /** If a dmaAction is in progress. */ int actionInProgress; /** If we need to drain, keep the drain event around until we're done * here.*/ Event *drainEvent; /** time to wait between sending another packet, increases as NACKs are * recived, decreases as responses are recived. */ Tick backoffTime; /** If the port is currently waiting for a retry before it can send whatever * it is that it's sending. */ bool inRetry; virtual bool recvTiming(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt) { panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN } virtual void recvFunctional(PacketPtr pkt) { panic("dma port shouldn't be used for pio access."); } virtual void recvStatusChange(Status status) { ; } virtual void recvRetry() ; virtual void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) { resp.clear(); snoop = false; } void queueDma(PacketPtr pkt, bool front = false); void sendDma(); /** event to give us a kick every time we backoff time is reached. */ EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent; public: DmaPort(DmaDevice *dev, System *s); void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, uint8_t *data = NULL); bool dmaPending() { return pendingCount > 0; } int cacheBlockSize() { return peerBlockSize(); } unsigned int drain(Event *de);};/** * This device is the base class which all devices senstive to an address range * inherit from. There are three pure virtual functions which all devices must * implement addressRanges(), read(), and write(). The magic do choose which * mode we are in, etc is handled by the PioPort so the device doesn't have to * bother. */class PioDevice : public MemObject{ protected: /** The platform we are in. This is used to decide what type of memory * transaction we should perform. */ Platform *platform; System *sys; /** The pioPort that handles the requests for us and provides us requests * that it sees. */ PioPort *pioPort; virtual void addressRanges(AddrRangeList &range_list) = 0; /** Pure virtual function that the device must implement. Called * when a read command is recieved by the port. * @param pkt Packet describing this request * @return number of ticks it took to complete */ virtual Tick read(PacketPtr pkt) = 0; /** Pure virtual function that the device must implement. Called when a * write command is recieved by the port. * @param pkt Packet describing this request * @return number of ticks it took to complete */ virtual Tick write(PacketPtr pkt) = 0; public: typedef PioDeviceParams Params; PioDevice(const Params *p); virtual ~PioDevice(); const Params * params() const { return dynamic_cast<const Params *>(_params); } virtual void init(); virtual unsigned int drain(Event *de); virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "pio") { if (pioPort != NULL) panic("pio port already connected to."); pioPort = new PioPort(this, sys); return pioPort; } else return NULL; } friend class PioPort;};class BasicPioDevice : public PioDevice{ protected: /** Address that the device listens to. */ Addr pioAddr; /** Size that the device's address range. */ Addr pioSize; /** Delay that the device experinces on an access. */ Tick pioDelay; public: typedef BasicPioDeviceParams Params; BasicPioDevice(const Params *p); const Params * params() const { return dynamic_cast<const Params *>(_params); } /** return the address ranges that this device responds to. * @param range_list range list to populate with ranges */ void addressRanges(AddrRangeList &range_list);};class DmaDevice : public PioDevice{ protected: DmaPort *dmaPort; Tick minBackoffDelay; Tick maxBackoffDelay; public: typedef DmaDeviceParams Params; DmaDevice(const Params *p); virtual ~DmaDevice(); const Params * params() const { return dynamic_cast<const Params *>(_params); } void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) { dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data); } void dmaRead(Addr addr, int size, Event *event, uint8_t *data) { dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data); } bool dmaPending() { return dmaPort->dmaPending(); } virtual unsigned int drain(Event *de); int cacheBlockSize() { return dmaPort->cacheBlockSize(); } virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "pio") { if (pioPort != NULL) panic("pio port already connected to."); pioPort = new PioPort(this, sys); return pioPort; } else if (if_name == "dma") { if (dmaPort != NULL) panic("dma port already connected to."); dmaPort = new DmaPort(this, sys); return dmaPort; } else return NULL; } friend class DmaPort;};#endif // __DEV_IO_DEVICE_HH__
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?