1/*
2 * Copyright (c) 2013-2014, 2016-2017 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 * Authors: Andrew Bardsley
38 */
39
40#include "cpu/minor/scoreboard.hh"
41
42#include "arch/registers.hh"
43#include "cpu/reg_class.hh"
44#include "debug/MinorScoreboard.hh"
45#include "debug/MinorTiming.hh"
46
47namespace Minor
48{
49
50bool
51Scoreboard::findIndex(const RegId& reg, Index &scoreboard_index)
52{
53    bool ret = false;
54
55    if (reg.isZeroReg()) {
56        /* Don't bother with the zero register */
57        ret = false;
58    } else {
59        switch (reg.classValue())
60        {
61          case IntRegClass:
62            scoreboard_index = reg.index();
63            ret = true;
64            break;
65          case FloatRegClass:
66            scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
67                reg.index();
68            ret = true;
69            break;
70          case VecRegClass:
71            scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
72                TheISA::NumFloatRegs + reg.index();
73            ret = true;
74            break;
75          case VecElemClass:
76            scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
77                TheISA::NumFloatRegs + reg.flatIndex();
78            ret = true;
79            break;
80          case VecPredRegClass:
81            scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
82                TheISA::NumFloatRegs + TheISA::NumVecRegs + reg.index();
83            ret = true;
84            break;
85          case CCRegClass:
86            scoreboard_index = TheISA::NumIntRegs + reg.index();
87            ret = true;
88            break;
89          case MiscRegClass:
90              /* Don't bother with Misc registers */
91            ret = false;
92            break;
93          default:
94            panic("Unknown register class: %d",
95                    static_cast<int>(reg.classValue()));
96        }
97    }
98
99    return ret;
100}
101
102/** Flatten a RegId, irrespective of what reg type it's pointing to */
103static RegId
104flattenRegIndex(const RegId& reg, ThreadContext *thread_context)
105{
106    return thread_context->flattenRegId(reg);
107}
108
109void
110Scoreboard::markupInstDests(MinorDynInstPtr inst, Cycles retire_time,
111    ThreadContext *thread_context, bool mark_unpredictable)
112{
113    if (inst->isFault())
114        return;
115
116    StaticInstPtr staticInst = inst->staticInst;
117    unsigned int num_dests = staticInst->numDestRegs();
118
119    /** Mark each destination register */
120    for (unsigned int dest_index = 0; dest_index < num_dests;
121        dest_index++)
122    {
123        RegId reg = flattenRegIndex(
124                staticInst->destRegIdx(dest_index), thread_context);
125        Index index;
126
127        if (findIndex(reg, index)) {
128            if (mark_unpredictable)
129                numUnpredictableResults[index]++;
130
131            inst->flatDestRegIdx[dest_index] = reg;
132
133            numResults[index]++;
134            returnCycle[index] = retire_time;
135            /* We should be able to rely on only being given accending
136             *  execSeqNums, but sanity check */
137            if (inst->id.execSeqNum > writingInst[index]) {
138                writingInst[index] = inst->id.execSeqNum;
139                fuIndices[index] = inst->fuIndex;
140            }
141
142            DPRINTF(MinorScoreboard, "Marking up inst: %s"
143                " regIndex: %d final numResults: %d returnCycle: %d\n",
144                *inst, index, numResults[index], returnCycle[index]);
145        } else {
146            /* Use ZeroReg to mark invalid/untracked dests */
147            inst->flatDestRegIdx[dest_index] = RegId(IntRegClass,
148                                                     TheISA::ZeroReg);
149        }
150    }
151}
152
153InstSeqNum
154Scoreboard::execSeqNumToWaitFor(MinorDynInstPtr inst,
155    ThreadContext *thread_context)
156{
157    InstSeqNum ret = 0;
158
159    if (inst->isFault())
160        return ret;
161
162    StaticInstPtr staticInst = inst->staticInst;
163    unsigned int num_srcs = staticInst->numSrcRegs();
164
165    for (unsigned int src_index = 0; src_index < num_srcs; src_index++) {
166        RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
167            thread_context);
168        unsigned short int index;
169
170        if (findIndex(reg, index)) {
171            if (writingInst[index] > ret)
172                ret = writingInst[index];
173        }
174    }
175
176    DPRINTF(MinorScoreboard, "Inst: %s depends on execSeqNum: %d\n",
177        *inst, ret);
178
179    return ret;
180}
181
182void
183Scoreboard::clearInstDests(MinorDynInstPtr inst, bool clear_unpredictable)
184{
185    if (inst->isFault())
186        return;
187
188    StaticInstPtr staticInst = inst->staticInst;
189    unsigned int num_dests = staticInst->numDestRegs();
190
191    /** Mark each destination register */
192    for (unsigned int dest_index = 0; dest_index < num_dests;
193        dest_index++)
194    {
195        const RegId& reg = inst->flatDestRegIdx[dest_index];
196        Index index;
197
198        if (findIndex(reg, index)) {
199            if (clear_unpredictable && numUnpredictableResults[index] != 0)
200                numUnpredictableResults[index] --;
201
202            numResults[index] --;
203
204            if (numResults[index] == 0) {
205                returnCycle[index] = Cycles(0);
206                writingInst[index] = 0;
207                fuIndices[index] = -1;
208            }
209
210            DPRINTF(MinorScoreboard, "Clearing inst: %s"
211                " regIndex: %d final numResults: %d\n",
212                *inst, index, numResults[index]);
213        }
214    }
215}
216
217bool
218Scoreboard::canInstIssue(MinorDynInstPtr inst,
219    const std::vector<Cycles> *src_reg_relative_latencies,
220    const std::vector<bool> *cant_forward_from_fu_indices,
221    Cycles now, ThreadContext *thread_context)
222{
223    /* Always allow fault to be issued */
224    if (inst->isFault())
225        return true;
226
227    StaticInstPtr staticInst = inst->staticInst;
228    unsigned int num_srcs = staticInst->numSrcRegs();
229
230    /* Default to saying you can issue */
231    bool ret = true;
232
233    unsigned int num_relative_latencies = 0;
234    Cycles default_relative_latency = Cycles(0);
235
236    /* Where relative latencies are given, the default is the last
237     *  one as that allows the rel. lat. list to be shorted than the
238     *  number of src. regs */
239    if (src_reg_relative_latencies &&
240        src_reg_relative_latencies->size() != 0)
241    {
242        num_relative_latencies = src_reg_relative_latencies->size();
243        default_relative_latency = (*src_reg_relative_latencies)
244            [num_relative_latencies-1];
245    }
246
247    /* For each source register, find the latest result */
248    unsigned int src_index = 0;
249    while (src_index < num_srcs && /* More registers */
250        ret /* Still possible */)
251    {
252        RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
253            thread_context);
254        unsigned short int index;
255
256        if (findIndex(reg, index)) {
257            bool cant_forward = fuIndices[index] != 1 &&
258                cant_forward_from_fu_indices &&
259                index < cant_forward_from_fu_indices->size() &&
260                (*cant_forward_from_fu_indices)[index];
261
262            Cycles relative_latency = (cant_forward ? Cycles(0) :
263                (src_index >= num_relative_latencies ?
264                    default_relative_latency :
265                    (*src_reg_relative_latencies)[src_index]));
266
267            if (returnCycle[index] > (now + relative_latency) ||
268                numUnpredictableResults[index] != 0)
269            {
270                ret = false;
271            }
272        }
273        src_index++;
274    }
275
276    if (DTRACE(MinorTiming)) {
277        if (ret && num_srcs > num_relative_latencies &&
278            num_relative_latencies != 0)
279        {
280            DPRINTF(MinorTiming, "Warning, inst: %s timing extra decode has"
281                " more src. regs: %d than relative latencies: %d\n",
282                staticInst->disassemble(0), num_srcs, num_relative_latencies);
283        }
284    }
285
286    return ret;
287}
288
289void
290Scoreboard::minorTrace() const
291{
292    std::ostringstream result_stream;
293
294    bool printed_element = false;
295
296    unsigned int i = 0;
297    while (i < numRegs) {
298        unsigned short int num_results = numResults[i];
299        unsigned short int num_unpredictable_results =
300            numUnpredictableResults[i];
301
302        if (!(num_results == 0 && num_unpredictable_results == Cycles(0))) {
303            if (printed_element)
304                result_stream << ',';
305
306            result_stream << '(' << i << ','
307                 << num_results << '/'
308                 << num_unpredictable_results << '/'
309                 << returnCycle[i] << '/'
310                 << writingInst[i] << ')';
311
312            printed_element = true;
313        }
314
315        i++;
316    }
317
318    MINORTRACE("busy=%s\n", result_stream.str());
319}
320
321}
322