external_slave.cc revision 10563:755b18321206
1/*
2 * Copyright (c) 2012-2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include <cctype>
41#include <iomanip>
42
43#include "debug/ExternalPort.hh"
44#include "mem/external_slave.hh"
45
46/** Implement a `stub' port which just responds to requests by printing
47 *  a message.  The stub port can be used to configure and test a system
48 *  where the external port is used for a peripheral before connecting
49 *  the external port */
50class StubSlavePort : public ExternalSlave::Port
51{
52  public:
53    class ResponseEvent : public Event
54    {
55      public:
56        StubSlavePort &owner;
57
58        ResponseEvent(StubSlavePort &owner_) : owner(owner_) { }
59
60        void process();
61    };
62
63    ResponseEvent responseEvent;
64
65    /** Stub can handle a single request at a time.  This will be
66     *  NULL when no packet is in flight */
67    PacketPtr responsePacket;
68
69    /** Received a new request while processing a first.  Need to ask for
70     *  a retry after completing this packet */
71    bool mustRetry;
72
73    StubSlavePort(const std::string &name_,
74        ExternalSlave &owner_) :
75        ExternalSlave::Port(name_, owner_),
76        responseEvent(*this), responsePacket(NULL), mustRetry(false)
77    { }
78
79    Tick recvAtomic(PacketPtr packet);
80    void recvFunctional(PacketPtr packet);
81    bool recvTimingReq(PacketPtr packet);
82    bool recvTimingSnoopResp(PacketPtr packet);
83    void recvRetry();
84    void recvFunctionalSnoop(PacketPtr packet);
85};
86
87class StubSlavePortHandler : public
88    ExternalSlave::Handler
89{
90  public:
91    ExternalSlave::Port *getExternalPort(
92        const std::string &name_,
93        ExternalSlave &owner,
94        const std::string &port_data)
95    {
96        StringWrap name(name_);
97
98        DPRINTF(ExternalPort, "finding stub port '%s'\n", port_data);
99        return new StubSlavePort(name_, owner);
100    }
101};
102
103Tick
104StubSlavePort::recvAtomic(PacketPtr packet)
105{
106    if (DTRACE(ExternalPort)) {
107        unsigned int M5_VAR_USED size = packet->getSize();
108
109        DPRINTF(ExternalPort, "StubSlavePort: recvAtomic a: 0x%x size: %d"
110            " data: ...\n", packet->getAddr(), size);
111        DDUMP(ExternalPort, packet->getConstPtr<uint8_t>(), size);
112    }
113
114    return 0;
115}
116
117void
118StubSlavePort::recvFunctional(PacketPtr packet)
119{
120    recvAtomic(packet);
121}
122
123void
124StubSlavePort::ResponseEvent::process()
125{
126    owner.responsePacket->makeResponse();
127    owner.responsePacket->firstWordDelay = 0;
128    owner.responsePacket->lastWordDelay = 0;
129
130    if (owner.sendTimingResp(owner.responsePacket)) {
131        owner.responsePacket = NULL;
132
133        if (owner.mustRetry)
134            owner.sendRetry();
135        owner.mustRetry = false;
136    }
137}
138
139bool
140StubSlavePort::recvTimingReq(PacketPtr packet)
141{
142    if (responsePacket) {
143        mustRetry = true;
144
145        return false;
146    } else {
147        recvAtomic(packet);
148
149        responsePacket = packet;
150        owner.schedule(responseEvent, curTick());
151
152        return true;
153    }
154}
155
156bool
157StubSlavePort::recvTimingSnoopResp(PacketPtr packet)
158{
159    fatal("StubSlavePort: function: %s\n", __func__);
160    return false;
161}
162
163void
164StubSlavePort::recvRetry()
165{
166    assert(responsePacket);
167    /* Stub handles only one response at a time so responseEvent should never
168     *  be scheduled at this point.  Retrys shouldn't need to schedule, we
169     *  can safely send the response here */
170    responseEvent.process();
171}
172
173void
174StubSlavePort::recvFunctionalSnoop(PacketPtr packet)
175{
176    fatal("StubSlavePort: unimplemented function: %s\n", __func__);
177}
178
179std::map<std::string, ExternalSlave::Handler *>
180    ExternalSlave::portHandlers;
181
182AddrRangeList
183ExternalSlave::Port::getAddrRanges() const
184{
185    return owner.addrRanges;
186}
187
188ExternalSlave::ExternalSlave(ExternalSlaveParams *params) :
189    MemObject(params),
190    externalPort(NULL),
191    portName(params->name + ".port"),
192    portType(params->port_type),
193    portData(params->port_data),
194    addrRanges(params->addr_ranges.begin(), params->addr_ranges.end())
195{
196    /* Register the stub handler if it hasn't already been registered */
197    if (portHandlers.find("stub") == portHandlers.end())
198        registerHandler("stub", new StubSlavePortHandler);
199}
200
201BaseSlavePort &
202ExternalSlave::getSlavePort(const std::string &if_name,
203    PortID idx)
204{
205    if (if_name == "port") {
206        DPRINTF(ExternalPort, "Trying to bind external port: %s %s\n",
207            portType, portName);
208
209        if (!externalPort) {
210            auto handlerIter = portHandlers.find(portType);
211
212            if (handlerIter == portHandlers.end())
213                fatal("Can't find port handler type '%s'\n", portType);
214
215            externalPort = portHandlers[portType]->getExternalPort(portName,
216                *this, portData);
217
218            if (!externalPort) {
219                fatal("%s: Can't find external port type: %s"
220                    " port_data: '%s'\n", portName, portType, portData);
221            }
222        }
223        return *externalPort;
224    } else {
225        return MemObject::getSlavePort(if_name, idx);
226    }
227}
228
229void
230ExternalSlave::init()
231{
232    if (!externalPort) {
233        fatal("ExternalSlave %s: externalPort not set!\n", name());
234    } else if (!externalPort->isConnected()) {
235        fatal("ExternalSlave %s is unconnected!\n", name());
236    } else {
237        externalPort->sendRangeChange();
238    }
239}
240
241ExternalSlave *
242ExternalSlaveParams::create()
243{
244    return new ExternalSlave(this);
245}
246
247void
248ExternalSlave::registerHandler(const std::string &handler_name,
249    Handler *handler)
250{
251    portHandlers[handler_name] = handler;
252}
253