ARM: Decode to specialized conditional/unconditional versions of instructions.
[gem5.git] / src / base / cp_annotate.hh
1 /*
2 * Copyright (c) 2006-2009 The Regents of The University of Michigan
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: Ali Saidi
29 */
30
31 #ifndef __BASE__CP_ANNOTATE_HH__
32 #define __BASE__CP_ANNOTATE_HH__
33
34 #include <string>
35 #include <list>
36 #include <vector>
37 #include <map>
38
39 #include "base/hashmap.hh"
40 #include "base/loader/symtab.hh"
41 #include "base/trace.hh"
42 #include "base/types.hh"
43 #include "config/cp_annotate.hh"
44 #include "config/the_isa.hh"
45 #include "sim/serialize.hh"
46 #include "sim/startup.hh"
47 #include "sim/system.hh"
48
49 #if CP_ANNOTATE
50 #include "params/CPA.hh"
51 #endif
52
53 class System;
54 class ThreadContext;
55
56
57 #if !CP_ANNOTATE
58 class CPA
59 {
60 public:
61 enum flags {
62 FL_NONE = 0x00,
63 FL_HW = 0x01,
64 FL_BAD = 0x02,
65 FL_QOPP = 0x04,
66 FL_WAIT = 0x08,
67 FL_LINK = 0x10,
68 FL_RESET = 0x20
69 };
70
71 static CPA *cpa() { return NULL; }
72 static bool available() { return false; }
73 bool enabled() { return false; }
74 void swSmBegin(ThreadContext *tc) { return; }
75 void swSmEnd(ThreadContext *tc) { return; }
76 void swExplictBegin(ThreadContext *tc) { return; }
77 void swAutoBegin(ThreadContext *tc, Addr next_pc) { return; }
78 void swEnd(ThreadContext *tc) { return; }
79 void swQ(ThreadContext *tc) { return; }
80 void swDq(ThreadContext *tc) { return; }
81 void swPq(ThreadContext *tc) { return; }
82 void swRq(ThreadContext *tc) { return; }
83 void swWf(ThreadContext *tc) { return; }
84 void swWe(ThreadContext *tc) { return; }
85 void swSq(ThreadContext *tc) { return; }
86 void swAq(ThreadContext *tc) { return; }
87 void swLink(ThreadContext *tc) { return; }
88 void swIdentify(ThreadContext *tc) { return; }
89 uint64_t swGetId(ThreadContext *tc) { return 0; }
90 void swSyscallLink(ThreadContext *tc) { return; }
91 void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
92 std::string st) { return; }
93 void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
94 std::string q, uint64_t qid, System *q_sys = NULL,
95 int32_t count = 1) { return; }
96 void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
97 std::string q, uint64_t qid, System *q_sys = NULL,
98 int32_t count = 1) { return; }
99 void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
100 std::string q, uint64_t qid, System *q_sys = NULL,
101 int32_t count = 1) { return; }
102 void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
103 std::string q, uint64_t qid, System *q_sys = NULL,
104 int32_t count = 1) { return; }
105 void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
106 std::string q, uint64_t qid, System *q_sys = NULL,
107 int32_t count = 1) { return; }
108 void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
109 std::string q, uint64_t qid, System *q_sys = NULL,
110 int32_t count = 1) { return; }
111 };
112 #else
113 class CPA : SimObject
114 {
115 public:
116 typedef CPAParams Params;
117
118 /** The known operations that are written to the annotation output file. */
119 enum ops {
120 OP_BEGIN = 0x01,
121 OP_WAIT_EMPTY = 0x02,
122 OP_WAIT_FULL = 0x03,
123 OP_QUEUE = 0x04,
124 OP_DEQUEUE = 0x05,
125 OP_SIZE_QUEUE = 0x08,
126 OP_PEEK = 0x09,
127 OP_LINK = 0x0A,
128 OP_IDENT = 0x0B,
129 OP_RESERVE = 0x0C
130 };
131
132 /** Flags for the various options.*/
133 enum flags {
134 /* no flags */
135 FL_NONE = 0x00,
136 /* operation was done on hardware */
137 FL_HW = 0x01,
138 /* operation should cause a warning when encountered */
139 FL_BAD = 0x02,
140 /* Queue like a stack, not a queue */
141 FL_QOPP = 0x04,
142 /* Mark HW state as waiting for some non-resource constraint
143 * (e.g. wait because SM only starts after 10 items are queued) */
144 FL_WAIT = 0x08,
145 /* operation is linking to another state machine */
146 FL_LINK = 0x10,
147 /* queue should be completely cleared/reset before executing this
148 * operation */
149 FL_RESET = 0x20
150 };
151
152
153
154 protected:
155 const Params *
156 params() const
157 {
158 return dynamic_cast<const Params *>(_params);
159 }
160
161 /* struct that is written to the annotation output file */
162 struct AnnotateData : public RefCounted {
163
164 Tick time;
165 uint32_t data;
166 uint32_t orig_data;
167 uint16_t sm;
168 uint16_t stq;
169 uint8_t op;
170 uint8_t flag;
171 uint8_t cpu;
172 bool dump;
173
174 void serialize(std::ostream &os);
175 void unserialize(Checkpoint *cp, const std::string &section);
176
177 };
178
179 typedef RefCountingPtr<AnnotateData> AnnDataPtr;
180
181 /* header for the annotation file */
182 struct AnnotateHeader {
183 uint64_t version;
184 uint64_t num_recs;
185 uint64_t key_off;
186 uint64_t idx_off;
187 uint32_t key_len;
188 uint32_t idx_len;
189 };
190
191 AnnotateHeader ah;
192
193 std::vector<uint64_t> annotateIdx;
194
195 // number of state machines encountered in the simulation
196 int numSm;
197 // number of states encountered in the simulation
198 int numSmt;
199 // number of states/queues for a given state machine/system respectively
200 std::vector<int> numSt, numQ;
201 // number of systems in the simulation
202 int numSys;
203 // number of queues in the state machine
204 int numQs;
205 // maximum connection id assigned so far
206 uint64_t conId;
207
208 // Convert state strings into state ids
209 typedef m5::hash_map<std::string, int> SCache;
210 typedef std::vector<SCache> StCache;
211
212 // Convert sm and queue name,id into queue id
213 typedef std::pair<std::string, uint64_t> Id;
214 typedef m5::hash_map<Id, int> IdHCache;
215 typedef std::vector<IdHCache> IdCache;
216
217 // Hold mapping of sm and queues to output python
218 typedef std::vector<std::pair<int, Id> > IdMap;
219
220 // System pointer to name,id
221 typedef std::map<System*, std::pair<std::string, int> > NameCache;
222
223 // array of systems each of which is a stack of running sm
224 typedef std::pair<int, uint64_t> StackId;
225 typedef std::map<StackId, std::vector<int> > SmStack;
226
227 // map of each context and if it's currently in explict state mode
228 // states are not automatically updated until it leaves
229 typedef std::map<StackId, bool> SwExpl;
230
231 typedef std::map<int,int> IMap;
232 // List of annotate records have not been written/completed yet
233 typedef std::list<AnnDataPtr> AnnotateList;
234
235 // Maintain link state information
236 typedef std::map<int, int> LinkMap;
237
238 // SC Links
239 typedef m5::hash_map<Id, AnnDataPtr> ScHCache;
240 typedef std::vector<ScHCache> ScCache;
241
242
243 AnnotateList data;
244
245 // vector indexed by queueid to find current number of elements and bytes
246 std::vector<int> qSize;
247 std::vector<int32_t> qBytes;
248
249
250 // Turn state machine string into state machine id (small int)
251 // Used for outputting key to convert id back into string
252 SCache smtCache;
253 // Turn state machine id, state name into state id (small int)
254 StCache stCache;
255 // turn system, queue, and queue identify into qid (small int)
256 // turn system, state, and context into state machine id (small int)
257 IdCache qCache, smCache;
258 //Link state machines accross system calls
259 ScCache scLinks;
260 // System pointer to name,id
261 NameCache nameCache;
262 // Stack of state machines currently nested (should unwind correctly)
263 SmStack smStack;
264 // Map of currently outstanding links
265 LinkMap lnMap;
266 // If the state machine is currently exculding automatic changes
267 SwExpl swExpl;
268 // Last state that a given state machine was in
269 IMap lastState;
270 // Hold mapping of sm and queues to output python
271 IdMap smMap, qMap;
272 // Items still in queue, used for sanity checking
273 std::vector<AnnotateList> qData;
274
275 void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi,
276 int count);
277 void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi,
278 int count);
279
280 void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame);
281
282 // Turn a system id, state machine string, state machine id into a small int
283 // for annotation output
284 int
285 getSm(int sysi, std::string si, uint64_t id)
286 {
287 int smi;
288 Id smid = Id(si, id);
289
290 smi = smCache[sysi-1][smid];
291 if (smi == 0) {
292 smCache[sysi-1][smid] = smi = ++numSm;
293 assert(smi < 65535);
294 smMap.push_back(std::make_pair<int, Id>(sysi, smid));
295 }
296 return smi;
297 }
298
299 // Turn a state machine string, state string into a small int
300 // for annotation output
301 int
302 getSt(std::string sm, std::string s)
303 {
304 int sti, smi;
305
306 smi = smtCache[sm];
307 if (smi == 0)
308 smi = smtCache[sm] = ++numSmt;
309
310 while (stCache.size() < smi) {
311 //stCache.resize(sm);
312 stCache.push_back(SCache());
313 numSt.push_back(0);
314 }
315 //assert(stCache.size() == sm);
316 //assert(numSt.size() == sm);
317 sti = stCache[smi-1][s];
318 if (sti == 0)
319 stCache[smi-1][s] = sti = ++numSt[smi-1];
320 return sti;
321 }
322
323 // Turn state machine pointer into a smal int for annotation output
324 int
325 getSys(System *s)
326 {
327 NameCache::iterator i = nameCache.find(s);
328 if (i == nameCache.end()) {
329 nameCache[s] = std::make_pair<std::string,int>(s->name(), ++numSys);
330 i = nameCache.find(s);
331 // might need to put smstackid into map here, but perhaps not
332 //smStack.push_back(std::vector<int>());
333 //swExpl.push_back(false);
334 numQ.push_back(0);
335 qCache.push_back(IdHCache());
336 smCache.push_back(IdHCache());
337 scLinks.push_back(ScHCache());
338 }
339 return i->second.second;
340 }
341
342 // Turn queue name, and queue context into small int for
343 // annotation output
344 int
345 getQ(int sys, std::string q, uint64_t id)
346 {
347 int qi;
348 Id qid = Id(q, id);
349
350 qi = qCache[sys-1][qid];
351 if (qi == 0) {
352 qi = qCache[sys-1][qid] = ++numQs;
353 assert(qi < 65535);
354 qSize.push_back(0);
355 qBytes.push_back(0);
356 qData.push_back(AnnotateList());
357 numQ[sys-1]++;
358 qMap.push_back(std::make_pair<int, Id>(sys, qid));
359 }
360 return qi;
361 }
362
363 void swBegin(System *sys, int cpuid, std::string st, uint64_t frame,
364 bool expl = false, int flags = FL_NONE);
365
366 AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0);
367
368 std::ostream *osbin;
369
370 bool _enabled;
371
372 /** Only allow one CPA object in a system. It doesn't make sense to have
373 * more that one per simulation because if a part of the system was
374 * important it would have annotations and queues, and with more than one
375 * object none of the sanity checking for queues will work. */
376 static bool exists;
377 static CPA *_cpa;
378
379
380 std::map<std::string, SymbolTable*> userApp;
381
382 public:
383 static CPA *cpa() { return _cpa; }
384 void swSmBegin(ThreadContext *tc);
385 void swSmEnd(ThreadContext *tc);
386 void swExplictBegin(ThreadContext *tc);
387 void swAutoBegin(ThreadContext *tc, Addr next_pc);
388 void swEnd(ThreadContext *tc);
389 void swQ(ThreadContext *tc);
390 void swDq(ThreadContext *tc);
391 void swPq(ThreadContext *tc);
392 void swRq(ThreadContext *tc);
393 void swWf(ThreadContext *tc);
394 void swWe(ThreadContext *tc);
395 void swSq(ThreadContext *tc);
396 void swAq(ThreadContext *tc);
397 void swLink(ThreadContext *tc);
398 void swIdentify(ThreadContext *tc);
399 uint64_t swGetId(ThreadContext *tc);
400 void swSyscallLink(ThreadContext *tc);
401
402 inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
403 std::string st)
404 {
405 if (!enabled())
406 return;
407
408 int sysi = getSys(sys);
409 int smi = getSm(sysi, sm, frame);
410 add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st));
411 if (f & FL_BAD)
412 warn("BAD state encountered: at cycle %d: %s\n", curTick, st);
413 }
414
415 inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
416 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
417 {
418 if (!enabled())
419 return;
420
421 int sysi = getSys(sys);
422 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
423 DPRINTFS(AnnotateQ, sys,
424 "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n",
425 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
426 doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count);
427
428 }
429
430 inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
431 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
432 {
433 if (!enabled())
434 return;
435
436 int sysi = getSys(sys);
437 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
438 DPRINTFS(AnnotateQ, sys,
439 "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n",
440 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
441 doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count);
442 }
443
444 inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
445 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
446 {
447 if (!enabled())
448 return;
449
450 int sysi = getSys(sys);
451 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
452 DPRINTFS(AnnotateQ, sys,
453 "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n",
454 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
455 add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
456 }
457
458 inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
459 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
460 {
461 if (!enabled())
462 return;
463
464 int sysi = getSys(sys);
465 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
466 DPRINTFS(AnnotateQ, sys,
467 "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n",
468 q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
469 add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
470 }
471
472 inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
473 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
474 {
475 if (!enabled())
476 return;
477
478 int sysi = getSys(sys);
479 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
480 add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
481 }
482
483 inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
484 std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
485 {
486 if (!enabled())
487 return;
488
489 int sysi = getSys(sys);
490 int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
491 add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
492 }
493
494 public:
495 CPA(Params *p);
496 void startup();
497
498 // This code is ISA specific and will need to be changed
499 // if the annotation code is used for something other than Alpha
500 inline uint64_t getFrame(ThreadContext *tc)
501 { return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) &
502 ~ULL(0x3FFF)); }
503
504 static bool available() { return true; }
505
506 bool
507 enabled()
508 {
509 if (!this)
510 return false;
511 return _enabled;
512 }
513
514 void dump(bool all);
515 void dumpKey();
516
517 void serialize(std::ostream &os);
518 void unserialize(Checkpoint *cp, const std::string &section);
519
520 };
521 #endif // !CP_ANNOTATE
522
523 #endif //__BASE__CP_ANNOTATE_HH__
524