This patch fixes a build error in networktest.cc that occurs with gcc4.2
[gem5.git] / src / cpu / testers / networktest / networktest.cc
1 /*
2 * Copyright (c) 2009 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Tushar Krishna
29 */
30
31 #include <iomanip>
32 #include <set>
33 #include <string>
34 #include <vector>
35 #include <cmath>
36
37 #include "base/misc.hh"
38 #include "base/statistics.hh"
39 #include "cpu/testers/networktest/networktest.hh"
40 #include "mem/mem_object.hh"
41 #include "mem/port.hh"
42 #include "mem/packet.hh"
43 #include "mem/request.hh"
44 #include "sim/sim_events.hh"
45 #include "sim/stats.hh"
46
47 using namespace std;
48
49 int TESTER_NETWORK=0;
50
51 bool
52 NetworkTest::CpuPort::recvTiming(PacketPtr pkt)
53 {
54 if (pkt->isResponse()) {
55 networktest->completeRequest(pkt);
56 } else {
57 // must be snoop upcall
58 assert(pkt->isRequest());
59 assert(pkt->getDest() == Packet::Broadcast);
60 }
61 return true;
62 }
63
64 Tick
65 NetworkTest::CpuPort::recvAtomic(PacketPtr pkt)
66 {
67 panic("NetworkTest doesn't expect recvAtomic call!");
68 // Will not be used
69 assert(pkt->isRequest());
70 assert(pkt->getDest() == Packet::Broadcast);
71 return curTick();
72 }
73
74 void
75 NetworkTest::CpuPort::recvFunctional(PacketPtr pkt)
76 {
77 panic("NetworkTest doesn't expect recvFunctional call!");
78 // Will not be used
79 return;
80 }
81
82 void
83 NetworkTest::CpuPort::recvStatusChange(Status status)
84 {
85 if (status == RangeChange) {
86 if (!snoopRangeSent) {
87 snoopRangeSent = true;
88 sendStatusChange(Port::RangeChange);
89 }
90 return;
91 }
92
93 panic("NetworkTest doesn't expect recvStatusChange callback!");
94 }
95
96 void
97 NetworkTest::CpuPort::recvRetry()
98 {
99 networktest->doRetry();
100 }
101
102 void
103 NetworkTest::sendPkt(PacketPtr pkt)
104 {
105 if (cachePort.sendTiming(pkt)) {
106 numPacketsSent++;
107 accessRetry = false;
108 } else {
109 accessRetry = true;
110 retryPkt = pkt;
111 }
112 }
113
114 NetworkTest::NetworkTest(const Params *p)
115 : MemObject(p),
116 tickEvent(this),
117 cachePort("network-test", this),
118 retryPkt(NULL),
119 size(p->memory_size),
120 blockSizeBits(p->block_offset),
121 numMemories(p->num_memories),
122 fixedPkts(p->fixed_pkts),
123 maxPackets(p->max_packets),
124 trafficType(p->traffic_type),
125 injRate(p->inj_rate),
126 precision(p->precision)
127 {
128 cachePort.snoopRangeSent = false;
129
130 // set up counters
131 noResponseCycles = 0;
132 schedule(tickEvent, 0);
133
134 id = TESTER_NETWORK++;
135 DPRINTF(NetworkTest,"Config Created: Name = %s , and id = %d\n",
136 name(), id);
137
138 accessRetry = false;
139 }
140
141 Port *
142 NetworkTest::getPort(const std::string &if_name, int idx)
143 {
144 if (if_name == "test")
145 return &cachePort;
146 else
147 panic("No Such Port\n");
148 }
149
150 void
151 NetworkTest::init()
152 {
153 numPacketsSent = 0;
154 }
155
156
157 void
158 NetworkTest::completeRequest(PacketPtr pkt)
159 {
160 Request *req = pkt->req;
161
162 DPRINTF(NetworkTest, "Completed injection of %s packet for address %x\n",
163 pkt->isWrite() ? "write" : "read\n",
164 req->getPaddr());
165
166 assert(pkt->isResponse());
167 noResponseCycles = 0;
168 delete req;
169 delete pkt;
170 }
171
172
173 void
174 NetworkTest::tick()
175 {
176 if (!tickEvent.scheduled())
177 schedule(tickEvent, curTick() + ticks(1));
178
179 if (++noResponseCycles >= 500000) {
180 cerr << name() << ": deadlocked at cycle " << curTick() << endl;
181 fatal("");
182 }
183
184 if (accessRetry) {
185 sendPkt(retryPkt);
186 return;
187 }
188
189 // make new request based on injection rate
190 // (injection rate's range depends on precision)
191 // - generate a random number between 0 and 10^precision
192 // - send pkt if this number is < injRate*(10^precision)
193 bool send_this_cycle;
194 double injRange = pow((double) 10, (double) precision);
195 unsigned trySending = random() % (int) injRange;
196 if (trySending < injRate*injRange)
197 send_this_cycle = true;
198 else
199 send_this_cycle = false;
200
201 // always generatePkt unless fixedPkts is enabled
202 if (send_this_cycle) {
203 if (fixedPkts) {
204 if (numPacketsSent < maxPackets) {
205 generatePkt();
206 }
207 } else {
208 generatePkt();
209 }
210 }
211 }
212
213 void
214 NetworkTest::generatePkt()
215 {
216 unsigned destination = id;
217 if (trafficType == 0) { // Uniform Random
218 while (destination == id)
219 destination = random() % numMemories;
220 } else if (trafficType == 1) { // Tornado
221 int networkDimension = (int) sqrt(numMemories);
222 int my_x = id%networkDimension;
223 int my_y = id/networkDimension;
224
225 int dest_x = my_x + (int) ceil(networkDimension/2) - 1;
226 dest_x = dest_x%networkDimension;
227 int dest_y = my_y;
228
229 destination = dest_y*networkDimension + dest_x;
230 } else if (trafficType == 2) { // Bit Complement
231 int networkDimension = (int) sqrt(numMemories);
232 int my_x = id%networkDimension;
233 int my_y = id/networkDimension;
234
235 int dest_x = networkDimension - my_x - 1;
236 int dest_y = networkDimension - my_y - 1;
237
238 destination = dest_y*networkDimension + dest_x;
239 }
240
241 Request *req = new Request();
242 Request::Flags flags;
243
244 // The source of the packets is a cache.
245 // The destination of the packets is a directory.
246 // The destination bits are embedded in the address after byte-offset.
247 Addr paddr = destination;
248 paddr <<= blockSizeBits;
249 unsigned access_size = 1; // Does not affect Ruby simulation
250
251 // Modeling different coherence msg types over different msg classes.
252 //
253 // networktest assumes the Network_test coherence protocol
254 // which models three message classes/virtual networks.
255 // These are: request, forward, response.
256 // requests and forwards are "control" packets (typically 8 bytes),
257 // while responses are "data" packets (typically 72 bytes).
258 //
259 // Life of a packet from the tester into the network:
260 // (1) This function generatePkt() generates packets of one of the
261 // following 3 types (randomly) : ReadReq, INST_FETCH, WriteReq
262 // (2) mem/ruby/system/RubyPort.cc converts these to RubyRequestType_LD,
263 // RubyRequestType_IFETCH, RubyRequestType_ST respectively
264 // (3) mem/ruby/system/Sequencer.cc sends these to the cache controllers
265 // in the coherence protocol.
266 // (4) Network_test-cache.sm tags RubyRequestType:LD,
267 // RubyRequestType:IFETCH and RubyRequestType:ST as
268 // Request, Forward, and Response events respectively;
269 // and injects them into virtual networks 0, 1 and 2 respectively.
270 // It immediately calls back the sequencer.
271 // (5) The packet traverses the network (simple/garnet) and reaches its
272 // destination (Directory), and network stats are updated.
273 // (6) Network_test-dir.sm simply drops the packet.
274 //
275 MemCmd::Command requestType;
276
277 unsigned randomReqType = random() % 3;
278 if (randomReqType == 0) {
279 // generate packet for virtual network 0
280 requestType = MemCmd::ReadReq;
281 req->setPhys(paddr, access_size, flags);
282 } else if (randomReqType == 1) {
283 // generate packet for virtual network 1
284 requestType = MemCmd::ReadReq;
285 flags.set(Request::INST_FETCH);
286 req->setVirt(0, 0x0, access_size, flags, 0x0);
287 req->setPaddr(paddr);
288 } else { // if (randomReqType == 2)
289 // generate packet for virtual network 2
290 requestType = MemCmd::WriteReq;
291 req->setPhys(paddr, access_size, flags);
292 }
293
294 req->setThreadContext(id,0);
295 uint8_t *result = new uint8_t[8];
296
297 //No need to do functional simulation
298 //We just do timing simulation of the network
299
300 DPRINTF(NetworkTest,
301 "Generated packet with destination %d, embedded in address %x\n",
302 destination, req->getPaddr());
303
304 PacketPtr pkt = new Packet(req, requestType, 0);
305 pkt->setSrc(0); //Not used
306 pkt->dataDynamicArray(new uint8_t[req->getSize()]);
307 NetworkTestSenderState *state = new NetworkTestSenderState(result);
308 pkt->senderState = state;
309
310 sendPkt(pkt);
311 }
312
313 void
314 NetworkTest::doRetry()
315 {
316 if (cachePort.sendTiming(retryPkt)) {
317 accessRetry = false;
318 retryPkt = NULL;
319 }
320 }
321
322 void
323 NetworkTest::printAddr(Addr a)
324 {
325 cachePort.printAddr(a);
326 }
327
328
329 NetworkTest *
330 NetworkTestParams::create()
331 {
332 return new NetworkTest(this);
333 }