summaryrefslogtreecommitdiff
path: root/src/cpu/minor/dyn_inst.hh
blob: b2decb39b97b5a1a3b0141109f69e97fe36bc372 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
 * Copyright (c) 2013-2014 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andrew Bardsley
 */

/**
 * @file
 *
 *  The dynamic instruction and instruction/line id (sequence numbers)
 *  definition for Minor.  A spirited attempt is made here to not carry too
 *  much on this structure.
 */

#ifndef __CPU_MINOR_DYN_INST_HH__
#define __CPU_MINOR_DYN_INST_HH__

#include <iostream>

#include "base/refcnt.hh"
#include "cpu/minor/buffers.hh"
#include "cpu/inst_seq.hh"
#include "cpu/static_inst.hh"
#include "cpu/timing_expr.hh"
#include "sim/faults.hh"

namespace Minor
{

class MinorDynInst;

/** MinorDynInsts are currently reference counted. */
typedef RefCountingPtr<MinorDynInst> MinorDynInstPtr;

/** Id for lines and instructions.  This includes all the relevant sequence
 *  numbers and thread ids for all stages of execution. */
class InstId
{
  public:
    /** First sequence numbers to use in initialisation of the pipeline and
     *  to be expected on the first line/instruction issued */
    static const InstSeqNum firstStreamSeqNum = 1;
    static const InstSeqNum firstPredictionSeqNum = 1;
    static const InstSeqNum firstLineSeqNum = 1;
    static const InstSeqNum firstFetchSeqNum = 1;
    static const InstSeqNum firstExecSeqNum = 1;

  public:
    /** The thread to which this line/instruction belongs */
    ThreadID threadId;

    /** The 'stream' this instruction belongs to.  Streams are interrupted
     *  (and sequence numbers increased) when Execute finds it wants to
     *  change the stream of instructions due to a branch. */
    InstSeqNum streamSeqNum;

    /** The predicted qualifier to stream, attached by Fetch2 as a
     *  consequence of branch prediction */
    InstSeqNum predictionSeqNum;

    /** Line sequence number.  This is the sequence number of the fetched
     *  line from which this instruction was fetched */
    InstSeqNum lineSeqNum;

    /** Fetch sequence number.  This is 0 for bubbles and an ascending
     *  sequence for the stream of all fetched instructions */
    InstSeqNum fetchSeqNum;

    /** 'Execute' sequence number.  These are assigned after micro-op
     *  decomposition and form an ascending sequence (starting with 1) for
     *  post-micro-op decomposed instructions. */
    InstSeqNum execSeqNum;

  public:
    /** Very boring default constructor */
    InstId(
        ThreadID thread_id = 0, InstSeqNum stream_seq_num = 0,
        InstSeqNum prediction_seq_num = 0, InstSeqNum line_seq_num = 0,
        InstSeqNum fetch_seq_num = 0, InstSeqNum exec_seq_num = 0) :
        threadId(thread_id), streamSeqNum(stream_seq_num),
        predictionSeqNum(prediction_seq_num), lineSeqNum(line_seq_num),
        fetchSeqNum(fetch_seq_num), execSeqNum(exec_seq_num)
    { }

  public:
    /* Equal if the thread and last set sequence number matches */
    bool
    operator== (const InstId &rhs)
    {
        /* If any of fetch and exec sequence number are not set
         *  they need to be 0, so a straight comparison is still
         *  fine */
        bool ret = (threadId == rhs.threadId &&
            lineSeqNum == rhs.lineSeqNum &&
            fetchSeqNum == rhs.fetchSeqNum &&
            execSeqNum == rhs.execSeqNum);

        /* Stream and prediction *must* match if these are the same id */
        if (ret) {
            assert(streamSeqNum == rhs.streamSeqNum &&
                predictionSeqNum == rhs.predictionSeqNum);
        }

        return ret;
    }
};

/** Print this id in the usual slash-separated format expected by
 *  MinorTrace */
std::ostream &operator <<(std::ostream &os, const InstId &id);

class MinorDynInst;

/** Print a short reference to this instruction.  '-' for a bubble and a
 *  series of '/' separated sequence numbers for other instructions.  The
 *  sequence numbers will be in the order: stream, prediction, line, fetch,
 *  exec with exec absent if it is 0.  This is used by MinorTrace. */
std::ostream &operator <<(std::ostream &os, const MinorDynInst &inst);

/** Dynamic instruction for Minor.
 *  MinorDynInst implements the BubbleIF interface
 *  Has two separate notions of sequence number for pre/post-micro-op
 *  decomposition: fetchSeqNum and execSeqNum */
class MinorDynInst : public RefCounted
{
  private:
    /** A prototypical bubble instruction.  You must call MinorDynInst::init
     *  to initialise this */
    static MinorDynInstPtr bubbleInst;

  public:
    StaticInstPtr staticInst;

    InstId id;

    /** Trace information for this instruction's execution */
    Trace::InstRecord *traceData;

    /** The fetch address of this instruction */
    TheISA::PCState pc;

    /** This is actually a fault masquerading as an instruction */
    Fault fault;

    /** Tried to predict the destination of this inst (if a control
     *  instruction or a sys call) */
    bool triedToPredict;

    /** This instruction was predicted to change control flow and
     *  the following instructions will have a newer predictionSeqNum */
    bool predictedTaken;

    /** Predicted branch target */
    TheISA::PCState predictedTarget;

    /** Fields only set during execution */

    /** FU this instruction is issued to */
    unsigned int fuIndex;

    /** This instruction is in the LSQ, not a functional unit */
    bool inLSQ;

    /** The instruction has been sent to the store buffer */
    bool inStoreBuffer;

    /** Can this instruction be executed out of order.  In this model,
     *  this only happens with mem refs that need to be issued early
     *  to allow other instructions to fill the fetch delay */
    bool canEarlyIssue;

    /** execSeqNum of the latest inst on which this inst depends.
     *  This can be used as a sanity check for dependency ordering
     *  where slightly out of order execution is required (notably
     *  initiateAcc for memory ops) */
    InstSeqNum instToWaitFor;

    /** Extra delay at the end of the pipeline */
    Cycles extraCommitDelay;
    TimingExpr *extraCommitDelayExpr;

    /** Once issued, extraCommitDelay becomes minimumCommitCycle
     *  to account for delay in absolute time */
    Cycles minimumCommitCycle;

    /** Flat register indices so that, when clearing the scoreboard, we
     *  have the same register indices as when the instruction was marked
     *  up */
    RegId flatDestRegIdx[TheISA::MaxInstDestRegs];

  public:
    MinorDynInst(InstId id_ = InstId(), Fault fault_ = NoFault) :
        staticInst(NULL), id(id_), traceData(NULL),
        pc(TheISA::PCState(0)), fault(fault_),
        triedToPredict(false), predictedTaken(false),
        fuIndex(0), inLSQ(false), inStoreBuffer(false),
        canEarlyIssue(false),
        instToWaitFor(0), extraCommitDelay(Cycles(0)),
        extraCommitDelayExpr(NULL), minimumCommitCycle(Cycles(0))
    { }

  public:
    /** The BubbleIF interface. */
    bool isBubble() const { return id.fetchSeqNum == 0; }

    /** There is a single bubble inst */
    static MinorDynInstPtr bubble() { return bubbleInst; }

    /** Is this a fault rather than instruction */
    bool isFault() const { return fault != NoFault; }

    /** Is this a real instruction */
    bool isInst() const { return !isBubble() && !isFault(); }

    /** Is this a real mem ref instruction */
    bool isMemRef() const { return isInst() && staticInst->isMemRef(); }

    /** Is this an instruction that can be executed `for free' and
     *  needn't spend time in an FU */
    bool isNoCostInst() const;

    /** Assuming this is not a fault, is this instruction either
     *  a whole instruction or the last microop from a macroop */
    bool isLastOpInInst() const;

    /** Initialise the class */
    static void init();

    /** Print (possibly verbose) instruction information for
     *  MinorTrace using the given Named object's name */
    void minorTraceInst(const Named &named_object) const;

    /** ReportIF interface */
    void reportData(std::ostream &os) const;

    ~MinorDynInst();
};

/** Print a summary of the instruction */
std::ostream &operator <<(std::ostream &os, const MinorDynInst &inst);

}

#endif /* __CPU_MINOR_DYN_INST_HH__ */