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