2 * Copyright (c) 2012-2014 ARM Limited
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.
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.
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.
37 * Authors: Andrew Bardsley
40 #include "mem/external_slave.hh"
45 #include "base/trace.hh"
46 #include "debug/ExternalPort.hh"
48 /** Implement a `stub' port which just responds to requests by printing
49 * a message. The stub port can be used to configure and test a system
50 * where the external port is used for a peripheral before connecting
51 * the external port */
52 class StubSlavePort
: public ExternalSlave::Port
55 void processResponseEvent();
57 EventFunctionWrapper responseEvent
;
59 /** Stub can handle a single request at a time. This will be
60 * NULL when no packet is in flight */
61 PacketPtr responsePacket
;
63 /** Received a new request while processing a first. Need to ask for
64 * a retry after completing this packet */
67 StubSlavePort(const std::string
&name_
,
68 ExternalSlave
&owner_
) :
69 ExternalSlave::Port(name_
, owner_
),
70 responseEvent([this]{ processResponseEvent(); }, name()),
71 responsePacket(NULL
), mustRetry(false)
74 Tick
recvAtomic(PacketPtr packet
);
75 void recvFunctional(PacketPtr packet
);
76 bool recvTimingReq(PacketPtr packet
);
77 bool recvTimingSnoopResp(PacketPtr packet
);
79 void recvFunctionalSnoop(PacketPtr packet
);
82 class StubSlavePortHandler
: public
83 ExternalSlave::Handler
86 ExternalSlave::Port
*getExternalPort(
87 const std::string
&name_
,
89 const std::string
&port_data
)
91 StringWrap
name(name_
);
93 DPRINTF(ExternalPort
, "finding stub port '%s'\n", port_data
);
94 return new StubSlavePort(name_
, owner
);
99 StubSlavePort::recvAtomic(PacketPtr packet
)
101 if (DTRACE(ExternalPort
)) {
102 unsigned int M5_VAR_USED size
= packet
->getSize();
104 DPRINTF(ExternalPort
, "StubSlavePort: recvAtomic a: 0x%x size: %d"
105 " data: ...\n", packet
->getAddr(), size
);
106 DDUMP(ExternalPort
, packet
->getConstPtr
<uint8_t>(), size
);
113 StubSlavePort::recvFunctional(PacketPtr packet
)
119 StubSlavePort::processResponseEvent()
121 responsePacket
->makeResponse();
122 responsePacket
->headerDelay
= 0;
123 responsePacket
->payloadDelay
= 0;
125 if (sendTimingResp(responsePacket
)) {
126 responsePacket
= NULL
;
135 StubSlavePort::recvTimingReq(PacketPtr packet
)
137 if (responsePacket
) {
144 responsePacket
= packet
;
145 owner
.schedule(responseEvent
, curTick());
152 StubSlavePort::recvTimingSnoopResp(PacketPtr packet
)
154 fatal("StubSlavePort: function: %s\n", __func__
);
159 StubSlavePort::recvRespRetry()
161 assert(responsePacket
);
162 /* Stub handles only one response at a time so responseEvent should never
163 * be scheduled at this point. Retrys shouldn't need to schedule, we
164 * can safely send the response here */
165 responseEvent
.process();
169 StubSlavePort::recvFunctionalSnoop(PacketPtr packet
)
171 fatal("StubSlavePort: unimplemented function: %s\n", __func__
);
174 std::map
<std::string
, ExternalSlave::Handler
*>
175 ExternalSlave::portHandlers
;
178 ExternalSlave::Port::getAddrRanges() const
180 return owner
.addrRanges
;
183 ExternalSlave::ExternalSlave(ExternalSlaveParams
*params
) :
186 portName(params
->name
+ ".port"),
187 portType(params
->port_type
),
188 portData(params
->port_data
),
189 addrRanges(params
->addr_ranges
.begin(), params
->addr_ranges
.end())
191 /* Register the stub handler if it hasn't already been registered */
192 if (portHandlers
.find("stub") == portHandlers
.end())
193 registerHandler("stub", new StubSlavePortHandler
);
197 ExternalSlave::getSlavePort(const std::string
&if_name
,
200 if (if_name
== "port") {
201 DPRINTF(ExternalPort
, "Trying to bind external port: %s %s\n",
205 auto handlerIter
= portHandlers
.find(portType
);
207 if (handlerIter
== portHandlers
.end())
208 fatal("Can't find port handler type '%s'\n", portType
);
210 externalPort
= portHandlers
[portType
]->getExternalPort(portName
,
214 fatal("%s: Can't find external port type: %s"
215 " port_data: '%s'\n", portName
, portType
, portData
);
218 return *externalPort
;
220 return MemObject::getSlavePort(if_name
, idx
);
225 ExternalSlave::init()
228 fatal("ExternalSlave %s: externalPort not set!\n", name());
229 } else if (!externalPort
->isConnected()) {
230 fatal("ExternalSlave %s is unconnected!\n", name());
232 externalPort
->sendRangeChange();
237 ExternalSlaveParams::create()
239 return new ExternalSlave(this);
243 ExternalSlave::registerHandler(const std::string
&handler_name
,
246 portHandlers
[handler_name
] = handler
;