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
43 #include "debug/ExternalPort.hh"
44 #include "mem/external_slave.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::Port
53 class ResponseEvent
: public Event
58 ResponseEvent(StubSlavePort
&owner_
) : owner(owner_
) { }
63 ResponseEvent responseEvent
;
65 /** Stub can handle a single request at a time. This will be
66 * NULL when no packet is in flight */
67 PacketPtr responsePacket
;
69 /** Received a new request while processing a first. Need to ask for
70 * a retry after completing this packet */
73 StubSlavePort(const std::string
&name_
,
74 ExternalSlave
&owner_
) :
75 ExternalSlave::Port(name_
, owner_
),
76 responseEvent(*this), responsePacket(NULL
), mustRetry(false)
79 Tick
recvAtomic(PacketPtr packet
);
80 void recvFunctional(PacketPtr packet
);
81 bool recvTimingReq(PacketPtr packet
);
82 bool recvTimingSnoopResp(PacketPtr packet
);
84 void recvFunctionalSnoop(PacketPtr packet
);
87 class StubSlavePortHandler
: public
88 ExternalSlave::Handler
91 ExternalSlave::Port
*getExternalPort(
92 const std::string
&name_
,
94 const std::string
&port_data
)
96 StringWrap
name(name_
);
98 DPRINTF(ExternalPort
, "finding stub port '%s'\n", port_data
);
99 return new StubSlavePort(name_
, owner
);
104 StubSlavePort::recvAtomic(PacketPtr packet
)
106 if (DTRACE(ExternalPort
)) {
107 unsigned int M5_VAR_USED size
= packet
->getSize();
109 DPRINTF(ExternalPort
, "StubSlavePort: recvAtomic a: 0x%x size: %d"
110 " data: ...\n", packet
->getAddr(), size
);
111 DDUMP(ExternalPort
, packet
->getConstPtr
<uint8_t>(), size
);
118 StubSlavePort::recvFunctional(PacketPtr packet
)
124 StubSlavePort::ResponseEvent::process()
126 owner
.responsePacket
->makeResponse();
127 owner
.responsePacket
->headerDelay
= 0;
128 owner
.responsePacket
->payloadDelay
= 0;
130 if (owner
.sendTimingResp(owner
.responsePacket
)) {
131 owner
.responsePacket
= NULL
;
134 owner
.sendRetryReq();
135 owner
.mustRetry
= false;
140 StubSlavePort::recvTimingReq(PacketPtr packet
)
142 if (responsePacket
) {
149 responsePacket
= packet
;
150 owner
.schedule(responseEvent
, curTick());
157 StubSlavePort::recvTimingSnoopResp(PacketPtr packet
)
159 fatal("StubSlavePort: function: %s\n", __func__
);
164 StubSlavePort::recvRespRetry()
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();
174 StubSlavePort::recvFunctionalSnoop(PacketPtr packet
)
176 fatal("StubSlavePort: unimplemented function: %s\n", __func__
);
179 std::map
<std::string
, ExternalSlave::Handler
*>
180 ExternalSlave::portHandlers
;
183 ExternalSlave::Port::getAddrRanges() const
185 return owner
.addrRanges
;
188 ExternalSlave::ExternalSlave(ExternalSlaveParams
*params
) :
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())
196 /* Register the stub handler if it hasn't already been registered */
197 if (portHandlers
.find("stub") == portHandlers
.end())
198 registerHandler("stub", new StubSlavePortHandler
);
202 ExternalSlave::getSlavePort(const std::string
&if_name
,
205 if (if_name
== "port") {
206 DPRINTF(ExternalPort
, "Trying to bind external port: %s %s\n",
210 auto handlerIter
= portHandlers
.find(portType
);
212 if (handlerIter
== portHandlers
.end())
213 fatal("Can't find port handler type '%s'\n", portType
);
215 externalPort
= portHandlers
[portType
]->getExternalPort(portName
,
219 fatal("%s: Can't find external port type: %s"
220 " port_data: '%s'\n", portName
, portType
, portData
);
223 return *externalPort
;
225 return MemObject::getSlavePort(if_name
, idx
);
230 ExternalSlave::init()
233 fatal("ExternalSlave %s: externalPort not set!\n", name());
234 } else if (!externalPort
->isConnected()) {
235 fatal("ExternalSlave %s is unconnected!\n", name());
237 externalPort
->sendRangeChange();
242 ExternalSlaveParams::create()
244 return new ExternalSlave(this);
248 ExternalSlave::registerHandler(const std::string
&handler_name
,
251 portHandlers
[handler_name
] = handler
;