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 class ResponseEvent
: public Event
60 ResponseEvent(StubSlavePort
&owner_
) : owner(owner_
) { }
65 ResponseEvent responseEvent
;
67 /** Stub can handle a single request at a time. This will be
68 * NULL when no packet is in flight */
69 PacketPtr responsePacket
;
71 /** Received a new request while processing a first. Need to ask for
72 * a retry after completing this packet */
75 StubSlavePort(const std::string
&name_
,
76 ExternalSlave
&owner_
) :
77 ExternalSlave::Port(name_
, owner_
),
78 responseEvent(*this), responsePacket(NULL
), mustRetry(false)
81 Tick
recvAtomic(PacketPtr packet
);
82 void recvFunctional(PacketPtr packet
);
83 bool recvTimingReq(PacketPtr packet
);
84 bool recvTimingSnoopResp(PacketPtr packet
);
86 void recvFunctionalSnoop(PacketPtr packet
);
89 class StubSlavePortHandler
: public
90 ExternalSlave::Handler
93 ExternalSlave::Port
*getExternalPort(
94 const std::string
&name_
,
96 const std::string
&port_data
)
98 StringWrap
name(name_
);
100 DPRINTF(ExternalPort
, "finding stub port '%s'\n", port_data
);
101 return new StubSlavePort(name_
, owner
);
106 StubSlavePort::recvAtomic(PacketPtr packet
)
108 if (DTRACE(ExternalPort
)) {
109 unsigned int M5_VAR_USED size
= packet
->getSize();
111 DPRINTF(ExternalPort
, "StubSlavePort: recvAtomic a: 0x%x size: %d"
112 " data: ...\n", packet
->getAddr(), size
);
113 DDUMP(ExternalPort
, packet
->getConstPtr
<uint8_t>(), size
);
120 StubSlavePort::recvFunctional(PacketPtr packet
)
126 StubSlavePort::ResponseEvent::process()
128 owner
.responsePacket
->makeResponse();
129 owner
.responsePacket
->headerDelay
= 0;
130 owner
.responsePacket
->payloadDelay
= 0;
132 if (owner
.sendTimingResp(owner
.responsePacket
)) {
133 owner
.responsePacket
= NULL
;
136 owner
.sendRetryReq();
137 owner
.mustRetry
= false;
142 StubSlavePort::recvTimingReq(PacketPtr packet
)
144 if (responsePacket
) {
151 responsePacket
= packet
;
152 owner
.schedule(responseEvent
, curTick());
159 StubSlavePort::recvTimingSnoopResp(PacketPtr packet
)
161 fatal("StubSlavePort: function: %s\n", __func__
);
166 StubSlavePort::recvRespRetry()
168 assert(responsePacket
);
169 /* Stub handles only one response at a time so responseEvent should never
170 * be scheduled at this point. Retrys shouldn't need to schedule, we
171 * can safely send the response here */
172 responseEvent
.process();
176 StubSlavePort::recvFunctionalSnoop(PacketPtr packet
)
178 fatal("StubSlavePort: unimplemented function: %s\n", __func__
);
181 std::map
<std::string
, ExternalSlave::Handler
*>
182 ExternalSlave::portHandlers
;
185 ExternalSlave::Port::getAddrRanges() const
187 return owner
.addrRanges
;
190 ExternalSlave::ExternalSlave(ExternalSlaveParams
*params
) :
193 portName(params
->name
+ ".port"),
194 portType(params
->port_type
),
195 portData(params
->port_data
),
196 addrRanges(params
->addr_ranges
.begin(), params
->addr_ranges
.end())
198 /* Register the stub handler if it hasn't already been registered */
199 if (portHandlers
.find("stub") == portHandlers
.end())
200 registerHandler("stub", new StubSlavePortHandler
);
204 ExternalSlave::getSlavePort(const std::string
&if_name
,
207 if (if_name
== "port") {
208 DPRINTF(ExternalPort
, "Trying to bind external port: %s %s\n",
212 auto handlerIter
= portHandlers
.find(portType
);
214 if (handlerIter
== portHandlers
.end())
215 fatal("Can't find port handler type '%s'\n", portType
);
217 externalPort
= portHandlers
[portType
]->getExternalPort(portName
,
221 fatal("%s: Can't find external port type: %s"
222 " port_data: '%s'\n", portName
, portType
, portData
);
225 return *externalPort
;
227 return MemObject::getSlavePort(if_name
, idx
);
232 ExternalSlave::init()
235 fatal("ExternalSlave %s: externalPort not set!\n", name());
236 } else if (!externalPort
->isConnected()) {
237 fatal("ExternalSlave %s is unconnected!\n", name());
239 externalPort
->sendRangeChange();
244 ExternalSlaveParams::create()
246 return new ExternalSlave(this);
250 ExternalSlave::registerHandler(const std::string
&handler_name
,
253 portHandlers
[handler_name
] = handler
;