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.
38 #include "mem/external_slave.hh"
43 #include "base/trace.hh"
44 #include "debug/ExternalPort.hh"
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 */
50 class StubSlavePort
: public ExternalSlave::ExternalPort
53 void processResponseEvent();
55 EventFunctionWrapper responseEvent
;
57 /** Stub can handle a single request at a time. This will be
58 * NULL when no packet is in flight */
59 PacketPtr responsePacket
;
61 /** Received a new request while processing a first. Need to ask for
62 * a retry after completing this packet */
65 StubSlavePort(const std::string
&name_
,
66 ExternalSlave
&owner_
) :
67 ExternalSlave::ExternalPort(name_
, owner_
),
68 responseEvent([this]{ processResponseEvent(); }, name()),
69 responsePacket(NULL
), mustRetry(false)
72 Tick
recvAtomic(PacketPtr packet
);
73 void recvFunctional(PacketPtr packet
);
74 bool recvTimingReq(PacketPtr packet
);
75 bool recvTimingSnoopResp(PacketPtr packet
);
77 void recvFunctionalSnoop(PacketPtr packet
);
80 class StubSlavePortHandler
: public
81 ExternalSlave::Handler
84 ExternalSlave::ExternalPort
*getExternalPort(
85 const std::string
&name_
,
87 const std::string
&port_data
)
89 StringWrap
name(name_
);
91 DPRINTF(ExternalPort
, "finding stub port '%s'\n", port_data
);
92 return new StubSlavePort(name_
, owner
);
97 StubSlavePort::recvAtomic(PacketPtr packet
)
99 if (DTRACE(ExternalPort
)) {
100 unsigned int M5_VAR_USED size
= packet
->getSize();
102 DPRINTF(ExternalPort
, "StubSlavePort: recvAtomic a: 0x%x size: %d"
103 " data: ...\n", packet
->getAddr(), size
);
104 DDUMP(ExternalPort
, packet
->getConstPtr
<uint8_t>(), size
);
111 StubSlavePort::recvFunctional(PacketPtr packet
)
117 StubSlavePort::processResponseEvent()
119 responsePacket
->makeResponse();
120 responsePacket
->headerDelay
= 0;
121 responsePacket
->payloadDelay
= 0;
123 if (sendTimingResp(responsePacket
)) {
124 responsePacket
= NULL
;
133 StubSlavePort::recvTimingReq(PacketPtr packet
)
135 if (responsePacket
) {
142 responsePacket
= packet
;
143 owner
.schedule(responseEvent
, curTick());
150 StubSlavePort::recvTimingSnoopResp(PacketPtr packet
)
152 fatal("StubSlavePort: function: %s\n", __func__
);
157 StubSlavePort::recvRespRetry()
159 assert(responsePacket
);
160 /* Stub handles only one response at a time so responseEvent should never
161 * be scheduled at this point. Retrys shouldn't need to schedule, we
162 * can safely send the response here */
163 responseEvent
.process();
167 StubSlavePort::recvFunctionalSnoop(PacketPtr packet
)
169 fatal("StubSlavePort: unimplemented function: %s\n", __func__
);
172 std::map
<std::string
, ExternalSlave::Handler
*>
173 ExternalSlave::portHandlers
;
176 ExternalSlave::ExternalPort::getAddrRanges() const
178 return owner
.addrRanges
;
181 ExternalSlave::ExternalSlave(ExternalSlaveParams
*params
) :
184 portName(params
->name
+ ".port"),
185 portType(params
->port_type
),
186 portData(params
->port_data
),
187 addrRanges(params
->addr_ranges
.begin(), params
->addr_ranges
.end())
189 /* Register the stub handler if it hasn't already been registered */
190 if (portHandlers
.find("stub") == portHandlers
.end())
191 registerHandler("stub", new StubSlavePortHandler
);
195 ExternalSlave::getPort(const std::string
&if_name
, PortID idx
)
197 if (if_name
== "port") {
198 DPRINTF(ExternalPort
, "Trying to bind external port: %s %s\n",
202 auto handlerIter
= portHandlers
.find(portType
);
204 if (handlerIter
== portHandlers
.end())
205 fatal("Can't find port handler type '%s'\n", portType
);
207 externalPort
= portHandlers
[portType
]->getExternalPort(portName
,
211 fatal("%s: Can't find external port type: %s"
212 " port_data: '%s'\n", portName
, portType
, portData
);
215 return *externalPort
;
217 return SimObject::getPort(if_name
, idx
);
222 ExternalSlave::init()
225 fatal("ExternalSlave %s: externalPort not set!\n", name());
226 } else if (!externalPort
->isConnected()) {
227 fatal("ExternalSlave %s is unconnected!\n", name());
229 externalPort
->sendRangeChange();
234 ExternalSlaveParams::create()
236 return new ExternalSlave(this);
240 ExternalSlave::registerHandler(const std::string
&handler_name
,
243 portHandlers
[handler_name
] = handler
;