mem-cache: Fix setting prefetch bit
[gem5.git] / src / mem / external_slave.cc
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
38 #include "mem/external_slave.hh"
39
40 #include <cctype>
41 #include <iomanip>
42
43 #include "base/trace.hh"
44 #include "debug/ExternalPort.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 */
50 class StubSlavePort : public ExternalSlave::ExternalPort
51 {
52 public:
53 void processResponseEvent();
54
55 EventFunctionWrapper responseEvent;
56
57 /** Stub can handle a single request at a time. This will be
58 * NULL when no packet is in flight */
59 PacketPtr responsePacket;
60
61 /** Received a new request while processing a first. Need to ask for
62 * a retry after completing this packet */
63 bool mustRetry;
64
65 StubSlavePort(const std::string &name_,
66 ExternalSlave &owner_) :
67 ExternalSlave::ExternalPort(name_, owner_),
68 responseEvent([this]{ processResponseEvent(); }, name()),
69 responsePacket(NULL), mustRetry(false)
70 { }
71
72 Tick recvAtomic(PacketPtr packet);
73 void recvFunctional(PacketPtr packet);
74 bool recvTimingReq(PacketPtr packet);
75 bool recvTimingSnoopResp(PacketPtr packet);
76 void recvRespRetry();
77 void recvFunctionalSnoop(PacketPtr packet);
78 };
79
80 class StubSlavePortHandler : public
81 ExternalSlave::Handler
82 {
83 public:
84 ExternalSlave::ExternalPort *getExternalPort(
85 const std::string &name_,
86 ExternalSlave &owner,
87 const std::string &port_data)
88 {
89 StringWrap name(name_);
90
91 DPRINTF(ExternalPort, "finding stub port '%s'\n", port_data);
92 return new StubSlavePort(name_, owner);
93 }
94 };
95
96 Tick
97 StubSlavePort::recvAtomic(PacketPtr packet)
98 {
99 if (DTRACE(ExternalPort)) {
100 M5_VAR_USED unsigned int size = packet->getSize();
101
102 DPRINTF(ExternalPort, "StubSlavePort: recvAtomic a: 0x%x size: %d"
103 " data: ...\n", packet->getAddr(), size);
104 DDUMP(ExternalPort, packet->getConstPtr<uint8_t>(), size);
105 }
106
107 return 0;
108 }
109
110 void
111 StubSlavePort::recvFunctional(PacketPtr packet)
112 {
113 recvAtomic(packet);
114 }
115
116 void
117 StubSlavePort::processResponseEvent()
118 {
119 responsePacket->makeResponse();
120 responsePacket->headerDelay = 0;
121 responsePacket->payloadDelay = 0;
122
123 if (sendTimingResp(responsePacket)) {
124 responsePacket = NULL;
125
126 if (mustRetry)
127 sendRetryReq();
128 mustRetry = false;
129 }
130 }
131
132 bool
133 StubSlavePort::recvTimingReq(PacketPtr packet)
134 {
135 if (responsePacket) {
136 mustRetry = true;
137
138 return false;
139 } else {
140 recvAtomic(packet);
141
142 responsePacket = packet;
143 owner.schedule(responseEvent, curTick());
144
145 return true;
146 }
147 }
148
149 bool
150 StubSlavePort::recvTimingSnoopResp(PacketPtr packet)
151 {
152 fatal("StubSlavePort: function: %s\n", __func__);
153 return false;
154 }
155
156 void
157 StubSlavePort::recvRespRetry()
158 {
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();
164 }
165
166 void
167 StubSlavePort::recvFunctionalSnoop(PacketPtr packet)
168 {
169 fatal("StubSlavePort: unimplemented function: %s\n", __func__);
170 }
171
172 std::map<std::string, ExternalSlave::Handler *>
173 ExternalSlave::portHandlers;
174
175 AddrRangeList
176 ExternalSlave::ExternalPort::getAddrRanges() const
177 {
178 return owner.addrRanges;
179 }
180
181 ExternalSlave::ExternalSlave(const ExternalSlaveParams &params) :
182 SimObject(params),
183 externalPort(NULL),
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())
188 {
189 /* Register the stub handler if it hasn't already been registered */
190 if (portHandlers.find("stub") == portHandlers.end())
191 registerHandler("stub", new StubSlavePortHandler);
192 }
193
194 Port &
195 ExternalSlave::getPort(const std::string &if_name, PortID idx)
196 {
197 if (if_name == "port") {
198 DPRINTF(ExternalPort, "Trying to bind external port: %s %s\n",
199 portType, portName);
200
201 if (!externalPort) {
202 auto handlerIter = portHandlers.find(portType);
203
204 if (handlerIter == portHandlers.end())
205 fatal("Can't find port handler type '%s'\n", portType);
206
207 externalPort = portHandlers[portType]->getExternalPort(portName,
208 *this, portData);
209
210 if (!externalPort) {
211 fatal("%s: Can't find external port type: %s"
212 " port_data: '%s'\n", portName, portType, portData);
213 }
214 }
215 return *externalPort;
216 } else {
217 return SimObject::getPort(if_name, idx);
218 }
219 }
220
221 void
222 ExternalSlave::init()
223 {
224 if (!externalPort) {
225 fatal("ExternalSlave %s: externalPort not set!\n", name());
226 } else if (!externalPort->isConnected()) {
227 fatal("ExternalSlave %s is unconnected!\n", name());
228 } else {
229 externalPort->sendRangeChange();
230 }
231 }
232
233 void
234 ExternalSlave::registerHandler(const std::string &handler_name,
235 Handler *handler)
236 {
237 portHandlers[handler_name] = handler;
238 }