gem5 v24.0.0.0
Loading...
Searching...
No Matches
execute.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013-2014,2018-2020 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
38#include "cpu/minor/execute.hh"
39
40#include <functional>
41
42#include "cpu/minor/cpu.hh"
44#include "cpu/minor/fetch1.hh"
45#include "cpu/minor/lsq.hh"
46#include "cpu/op_class.hh"
47#include "debug/Activity.hh"
48#include "debug/Branch.hh"
49#include "debug/Drain.hh"
50#include "debug/ExecFaulting.hh"
51#include "debug/MinorExecute.hh"
52#include "debug/MinorInterrupt.hh"
53#include "debug/MinorMem.hh"
54#include "debug/MinorTrace.hh"
55#include "debug/PCEvent.hh"
56
57namespace gem5
58{
59
60namespace minor
61{
62
63Execute::Execute(const std::string &name_,
64 MinorCPU &cpu_,
65 const BaseMinorCPUParams &params,
68 Named(name_),
69 inp(inp_),
70 out(out_),
71 cpu(cpu_),
72 issueLimit(params.executeIssueLimit),
73 memoryIssueLimit(params.executeMemoryIssueLimit),
74 commitLimit(params.executeCommitLimit),
75 memoryCommitLimit(params.executeMemoryCommitLimit),
76 processMoreThanOneInput(params.executeCycleInput),
77 fuDescriptions(*params.executeFuncUnits),
78 numFuncUnits(fuDescriptions.funcUnits.size()),
79 setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit),
80 setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue),
81 allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue),
82 noCostFUIndex(fuDescriptions.funcUnits.size() + 1),
83 lsq(name_ + ".lsq", name_ + ".dcache_port",
84 cpu_, *this,
85 params.executeMaxAccessesInMemory,
86 params.executeMemoryWidth,
87 params.executeLSQRequestsQueueSize,
88 params.executeLSQTransfersQueueSize,
89 params.executeLSQStoreBufferSize,
90 params.executeLSQMaxStoreBufferStoresPerCycle),
91 executeInfo(params.numThreads,
92 ExecuteThreadInfo(params.executeCommitLimit)),
93 interruptPriority(0),
94 issuePriority(0),
95 commitPriority(0)
96{
97 if (commitLimit < 1) {
98 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_,
100 }
101
102 if (issueLimit < 1) {
103 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_,
104 issueLimit);
105 }
106
107 if (memoryIssueLimit < 1) {
108 fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_,
110 }
111
113 fatal("%s: executeMemoryCommitLimit (%d) must be <="
114 " executeCommitLimit (%d)\n",
116 }
117
118 if (params.executeInputBufferSize < 1) {
119 fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
120 params.executeInputBufferSize);
121 }
122
123 if (params.executeInputBufferSize < 1) {
124 fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_,
125 params.executeInputBufferSize);
126 }
127
128 /* This should be large enough to count all the in-FU instructions
129 * which need to be accounted for in the inFlightInsts
130 * queue */
131 unsigned int total_slots = 0;
132
133 /* Make FUPipelines for each MinorFU */
134 for (unsigned int i = 0; i < numFuncUnits; i++) {
135 std::ostringstream fu_name;
136 MinorFU *fu_description = fuDescriptions.funcUnits[i];
137
138 /* Note the total number of instruction slots (for sizing
139 * the inFlightInst queue) and the maximum latency of any FU
140 * (for sizing the activity recorder) */
141 total_slots += fu_description->opLat;
142
143 fu_name << name_ << ".fu." << i;
144
145 FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu);
146
147 funcUnits.push_back(fu);
148 }
149
151 for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) {
152 bool found_fu = false;
153 unsigned int fu_index = 0;
154
155 while (fu_index < numFuncUnits && !found_fu)
156 {
157 if (funcUnits[fu_index]->provides(
158 static_cast<OpClass>(op_class)))
159 {
160 found_fu = true;
161 }
162 fu_index++;
163 }
164
165 if (!found_fu) {
166 warn("No functional unit for OpClass %s\n",
167 enums::OpClassStrings[op_class]);
168 }
169 }
170
171 /* Per-thread structures */
172 for (ThreadID tid = 0; tid < params.numThreads; tid++) {
173 std::string tid_str = std::to_string(tid);
174
175 /* Input Buffers */
176 inputBuffer.push_back(
178 name_ + ".inputBuffer" + tid_str, "insts",
179 params.executeInputBufferSize));
180
181 const auto &regClasses = cpu.threads[tid]->getIsaPtr()->regClasses();
182
183 /* Scoreboards */
184 scoreboard.emplace_back(name_ + ".scoreboard" + tid_str, regClasses);
185
186 /* In-flight instruction records */
187 executeInfo[tid].inFlightInsts = new Queue<QueuedInst,
189 name_ + ".inFlightInsts" + tid_str, "insts", total_slots);
190
191 executeInfo[tid].inFUMemInsts = new Queue<QueuedInst,
193 name_ + ".inFUMemInsts" + tid_str, "insts", total_slots);
194 }
195}
196
197const ForwardInstData *
199{
200 /* Get a line from the inputBuffer to work with */
201 if (!inputBuffer[tid].empty()) {
202 const ForwardInstData &head = inputBuffer[tid].front();
203
204 return (head.isBubble() ? NULL : &(inputBuffer[tid].front()));
205 } else {
206 return NULL;
207 }
208}
209
210void
212{
213 if (!inputBuffer[tid].empty())
214 inputBuffer[tid].pop();
215
216 executeInfo[tid].inputIndex = 0;
217}
218
219void
221{
222 ThreadContext *thread = cpu.getContext(inst->id.threadId);
223 const std::unique_ptr<PCStateBase> pc_before(inst->pc->clone());
224 std::unique_ptr<PCStateBase> target(thread->pcState().clone());
225
226 /* Force a branch for SerializeAfter/SquashAfter instructions
227 * at the end of micro-op sequence when we're not suspended */
228 bool force_branch = thread->status() != ThreadContext::Suspended &&
229 !inst->isFault() &&
230 inst->isLastOpInInst() &&
231 (inst->staticInst->isSerializeAfter() ||
232 inst->staticInst->isSquashAfter());
233
234 DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n",
235 *pc_before, *target, (force_branch ? " (forcing)" : ""));
236
237 /* Will we change the PC to something other than the next instruction? */
238 bool must_branch = *pc_before != *target ||
239 fault != NoFault ||
240 force_branch;
241
242 /* The reason for the branch data we're about to generate, set below */
244
245 if (fault == NoFault) {
246 inst->staticInst->advancePC(*target);
247 thread->pcState(*target);
248
249 DPRINTF(Branch, "Advancing current PC from: %s to: %s\n",
250 *pc_before, *target);
251 }
252
253 if (inst->predictedTaken && !force_branch) {
254 /* Predicted to branch */
255 if (!must_branch) {
256 /* No branch was taken, change stream to get us back to the
257 * intended PC value */
258 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but"
259 " none happened inst: %s\n",
260 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
261 *inst);
262
264 } else if (*inst->predictedTarget == *target) {
265 /* Branch prediction got the right target, kill the branch and
266 * carry on.
267 * Note that this information to the branch predictor might get
268 * overwritten by a "real" branch during this cycle */
269 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly"
270 " inst: %s\n",
271 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
272 *inst);
273
275 } else {
276 /* Branch prediction got the wrong target */
277 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x"
278 " but got the wrong target (actual: 0x%x) inst: %s\n",
279 inst->pc->instAddr(), inst->predictedTarget->instAddr(),
280 target->instAddr(), *inst);
281
283 }
284 } else if (must_branch) {
285 /* Unpredicted branch */
286 DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n",
287 inst->pc->instAddr(), target->instAddr(), *inst);
288
290 } else {
291 /* No branch at all */
292 reason = BranchData::NoBranch;
293 }
294
295 updateBranchData(inst->id.threadId, reason, inst, *target, branch);
296}
297
298void
300 ThreadID tid,
301 BranchData::Reason reason,
302 MinorDynInstPtr inst, const PCStateBase &target,
303 BranchData &branch)
304{
305 if (reason != BranchData::NoBranch) {
306 /* Bump up the stream sequence number on a real branch*/
307 if (BranchData::isStreamChange(reason))
308 executeInfo[tid].streamSeqNum++;
309
310 /* Branches (even mis-predictions) don't change the predictionSeqNum,
311 * just the streamSeqNum */
312 branch = BranchData(reason, tid,
313 executeInfo[tid].streamSeqNum,
314 /* Maintaining predictionSeqNum if there's no inst is just a
315 * courtesy and looks better on minorview */
316 (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum
317 : inst->id.predictionSeqNum),
318 target, inst);
319
320 DPRINTF(Branch, "Branch data signalled: %s\n", branch);
321 }
322}
323
324void
326 LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault)
327{
328 ThreadID thread_id = inst->id.threadId;
329 ThreadContext *thread = cpu.getContext(thread_id);
330
331 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
332
333 PacketPtr packet = response->packet;
334
335 bool is_load = inst->staticInst->isLoad();
336 bool is_store = inst->staticInst->isStore();
337 bool is_atomic = inst->staticInst->isAtomic();
338 bool is_prefetch = inst->staticInst->isDataPrefetch();
339
340 /* If true, the trace's predicate value will be taken from the exec
341 * context predicate, otherwise, it will be set to false */
342 bool use_context_predicate = true;
343
344 if (inst->translationFault != NoFault) {
345 /* Invoke memory faults. */
346 DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n",
347 inst->translationFault->name());
348
349 if (inst->staticInst->isPrefetch()) {
350 DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n",
351 inst->translationFault->name());
352
353 /* Don't assign to fault */
354 } else {
355 /* Take the fault raised during the TLB/memory access */
356 fault = inst->translationFault;
357
358 fault->invoke(thread, inst->staticInst);
359 }
360 } else if (!packet) {
361 DPRINTF(MinorMem, "Completing failed request inst: %s\n",
362 *inst);
363 use_context_predicate = false;
364 if (!context.readMemAccPredicate())
365 inst->staticInst->completeAcc(nullptr, &context, inst->traceData);
366 } else if (packet->isError()) {
367 DPRINTF(MinorMem, "Trying to commit error response: %s\n",
368 *inst);
369
370 fatal("Received error response packet for inst: %s\n", *inst);
371 } else if (is_store || is_load || is_prefetch || is_atomic) {
372 assert(packet);
373
374 DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n",
375 *inst, packet->getAddr(), packet->getSize());
376
377 if (is_load && packet->getSize() > 0) {
378 DPRINTF(MinorMem, "Memory data[0]: 0x%x\n",
379 static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0]));
380 }
381
382 /* Complete the memory access instruction */
383 fault = inst->staticInst->completeAcc(packet, &context,
384 inst->traceData);
385
386 if (fault != NoFault) {
387 /* Invoke fault created by instruction completion */
388 DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n",
389 fault->name());
390 fault->invoke(thread, inst->staticInst);
391 } else {
392 /* Stores need to be pushed into the store buffer to finish
393 * them off */
394 if (response->needsToBeSentToStoreBuffer())
395 lsq.sendStoreToStoreBuffer(response);
396 }
397 } else {
398 fatal("There should only ever be reads, "
399 "writes or faults at this point\n");
400 }
401
402 lsq.popResponse(response);
403
404 if (inst->traceData) {
405 inst->traceData->setPredicate((use_context_predicate ?
406 context.readPredicate() : false));
407 }
408
410
411 /* Generate output to account for branches */
412 tryToBranch(inst, fault, branch);
413}
414
415bool
417{
418 return cpu.checkInterrupts(thread_id);
419}
420
421bool
423{
424 DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n",
425 cpu.getContext(thread_id)->pcState());
426
427 Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt();
428
429 if (interrupt != NoFault) {
430 /* The interrupt *must* set pcState */
432 interrupt->invoke(cpu.getContext(thread_id));
433
434 assert(!lsq.accessesInFlight());
435
436 DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n",
437 interrupt->name(), cpu.getContext(thread_id)->pcState());
438
439 /* Assume that an interrupt *must* cause a branch. Assert this? */
440
443 branch);
444 }
445
446 return interrupt != NoFault;
447}
448
449bool
451 bool &passed_predicate, Fault &fault)
452{
453 bool issued = false;
454
455 /* Set to true if the mem op. is issued and sent to the mem system */
456 passed_predicate = false;
457
458 if (!lsq.canRequest()) {
459 /* Not acting on instruction yet as the memory
460 * queues are full */
461 issued = false;
462 } else {
463 ThreadContext *thread = cpu.getContext(inst->id.threadId);
464 std::unique_ptr<PCStateBase> old_pc(thread->pcState().clone());
465
466 ExecContext context(cpu, *cpu.threads[inst->id.threadId], *this, inst);
467
468 DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst);
469
470 Fault init_fault = inst->staticInst->initiateAcc(&context,
471 inst->traceData);
472
473 if (inst->inLSQ) {
474 if (init_fault != NoFault) {
475 assert(inst->translationFault != NoFault);
476 // Translation faults are dealt with in handleMemResponse()
477 init_fault = NoFault;
478 } else {
479 // If we have a translation fault then it got suppressed by
480 // initateAcc()
481 inst->translationFault = NoFault;
482 }
483 }
484
485 if (init_fault != NoFault) {
486 DPRINTF(MinorExecute, "Fault on memory inst: %s"
487 " initiateAcc: %s\n", *inst, init_fault->name());
488 fault = init_fault;
489 } else {
490 /* Only set this if the instruction passed its
491 * predicate */
492 if (!context.readMemAccPredicate()) {
493 DPRINTF(MinorMem, "No memory access for inst: %s\n", *inst);
494 assert(context.readPredicate());
495 }
496 passed_predicate = context.readPredicate();
497
498 /* Set predicate in tracing */
499 if (inst->traceData)
500 inst->traceData->setPredicate(passed_predicate);
501
502 /* If the instruction didn't pass its predicate
503 * or it is a predicated vector instruction and the
504 * associated predicate register is all-false (and so will not
505 * progress from here) Try to branch to correct and branch
506 * mis-prediction. */
507 if (!inst->inLSQ) {
508 /* Leave it up to commit to handle the fault */
510 inst->inLSQ = true;
511 }
512 }
513
514 /* Restore thread PC */
515 thread->pcState(*old_pc);
516 issued = true;
517 }
518
519 return issued;
520}
521
523inline unsigned int
524cyclicIndexInc(unsigned int index, unsigned int cycle_size)
525{
526 unsigned int ret = index + 1;
527
528 if (ret == cycle_size)
529 ret = 0;
530
531 return ret;
532}
533
535inline unsigned int
536cyclicIndexDec(unsigned int index, unsigned int cycle_size)
537{
538 int ret = index - 1;
539
540 if (ret < 0)
541 ret = cycle_size - 1;
542
543 return ret;
544}
545
546unsigned int
548{
549 const ForwardInstData *insts_in = getInput(thread_id);
550 ExecuteThreadInfo &thread = executeInfo[thread_id];
551
552 /* Early termination if we have no instructions */
553 if (!insts_in)
554 return 0;
555
556 /* Start from the first FU */
557 unsigned int fu_index = 0;
558
559 /* Remains true while instructions are still being issued. If any
560 * instruction fails to issue, this is set to false and we exit issue.
561 * This strictly enforces in-order issue. For other issue behaviours,
562 * a more complicated test in the outer while loop below is needed. */
563 bool issued = true;
564
565 /* Number of insts issues this cycle to check for issueLimit */
566 unsigned num_insts_issued = 0;
567
568 /* Number of memory ops issues this cycle to check for memoryIssueLimit */
569 unsigned num_mem_insts_issued = 0;
570
571 do {
572 MinorDynInstPtr inst = insts_in->insts[thread.inputIndex];
573 Fault fault = inst->fault;
574 bool discarded = false;
575 bool issued_mem_ref = false;
576
577 if (inst->isBubble()) {
578 /* Skip */
579 issued = true;
580 } else if (cpu.getContext(thread_id)->status() ==
582 {
583 DPRINTF(MinorExecute, "Discarding inst: %s from suspended"
584 " thread\n", *inst);
585
586 issued = true;
587 discarded = true;
588 } else if (inst->id.streamSeqNum != thread.streamSeqNum) {
589 DPRINTF(MinorExecute, "Discarding inst: %s as its stream"
590 " state was unexpected, expected: %d\n",
591 *inst, thread.streamSeqNum);
592 issued = true;
593 discarded = true;
594 } else {
595 /* Try and issue an instruction into an FU, assume we didn't and
596 * fix that in the loop */
597 issued = false;
598
599 /* Try FU from 0 each instruction */
600 fu_index = 0;
601
602 /* Try and issue a single instruction stepping through the
603 * available FUs */
604 do {
605 FUPipeline *fu = funcUnits[fu_index];
606
607 DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n",
608 *inst, fu_index);
609
610 /* Does the examined fu have the OpClass-related capability
611 * needed to execute this instruction? Faults can always
612 * issue to any FU but probably should just 'live' in the
613 * inFlightInsts queue rather than having an FU. */
614 bool fu_is_capable = (!inst->isFault() ?
615 fu->provides(inst->staticInst->opClass()) : true);
616
617 if (inst->isNoCostInst()) {
618 /* Issue free insts. to a fake numbered FU */
619 fu_index = noCostFUIndex;
620
621 /* And start the countdown on activity to allow
622 * this instruction to get to the end of its FU */
624
625 /* Mark the destinations for this instruction as
626 * busy */
627 scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() +
628 Cycles(0), cpu.getContext(thread_id), false);
629
630 DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex);
631 inst->fuIndex = noCostFUIndex;
632 inst->extraCommitDelay = Cycles(0);
633 inst->extraCommitDelayExpr = NULL;
634
635 /* Push the instruction onto the inFlight queue so
636 * it can be committed in order */
637 QueuedInst fu_inst(inst);
638 thread.inFlightInsts->push(fu_inst);
639
640 issued = true;
641
642 } else if (!fu_is_capable || fu->alreadyPushed()) {
643 /* Skip */
644 if (!fu_is_capable) {
645 DPRINTF(MinorExecute, "Can't issue as FU: %d isn't"
646 " capable\n", fu_index);
647 } else {
648 DPRINTF(MinorExecute, "Can't issue as FU: %d is"
649 " already busy\n", fu_index);
650 }
651 } else if (fu->stalled) {
652 DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d,"
653 " it's stalled\n",
654 *inst, fu_index);
655 } else if (!fu->canInsert()) {
656 DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU"
657 " for another: %d cycles\n",
658 *inst, fu->cyclesBeforeInsert());
659 } else {
660 MinorFUTiming *timing = (!inst->isFault() ?
661 fu->findTiming(inst->staticInst) : NULL);
662
663 const std::vector<Cycles> *src_latencies =
664 (timing ? &(timing->srcRegsRelativeLats)
665 : NULL);
666
667 const std::vector<bool> *cant_forward_from_fu_indices =
668 &(fu->cantForwardFromFUIndices);
669
670 if (timing && timing->suppress) {
671 DPRINTF(MinorExecute, "Can't issue inst: %s as extra"
672 " decoding is suppressing it\n",
673 *inst);
674 } else if (!scoreboard[thread_id].canInstIssue(inst,
675 src_latencies, cant_forward_from_fu_indices,
676 cpu.curCycle(), cpu.getContext(thread_id)))
677 {
678 DPRINTF(MinorExecute, "Can't issue inst: %s yet\n",
679 *inst);
680 } else {
681 /* Can insert the instruction into this FU */
682 DPRINTF(MinorExecute, "Issuing inst: %s"
683 " into FU %d\n", *inst,
684 fu_index);
685
686 Cycles extra_dest_retire_lat = Cycles(0);
687 TimingExpr *extra_dest_retire_lat_expr = NULL;
688 Cycles extra_assumed_lat = Cycles(0);
689
690 /* Add the extraCommitDelay and extraAssumeLat to
691 * the FU pipeline timings */
692 if (timing) {
693 extra_dest_retire_lat =
694 timing->extraCommitLat;
695 extra_dest_retire_lat_expr =
696 timing->extraCommitLatExpr;
697 extra_assumed_lat =
698 timing->extraAssumedLat;
699 }
700
701 issued_mem_ref = inst->isMemRef();
702
703 QueuedInst fu_inst(inst);
704
705 /* Decorate the inst with FU details */
706 inst->fuIndex = fu_index;
707 inst->extraCommitDelay = extra_dest_retire_lat;
708 inst->extraCommitDelayExpr =
709 extra_dest_retire_lat_expr;
710
711 if (issued_mem_ref) {
712 /* Remember which instruction this memory op
713 * depends on so that initiateAcc can be called
714 * early */
715 if (allowEarlyMemIssue) {
716 inst->instToWaitFor =
717 scoreboard[thread_id].execSeqNumToWaitFor(inst,
718 cpu.getContext(thread_id));
719
720 if (lsq.getLastMemBarrier(thread_id) >
721 inst->instToWaitFor)
722 {
723 DPRINTF(MinorExecute, "A barrier will"
724 " cause a delay in mem ref issue of"
725 " inst: %s until after inst"
726 " %d(exec)\n", *inst,
727 lsq.getLastMemBarrier(thread_id));
728
729 inst->instToWaitFor =
730 lsq.getLastMemBarrier(thread_id);
731 } else {
732 DPRINTF(MinorExecute, "Memory ref inst:"
733 " %s must wait for inst %d(exec)"
734 " before issuing\n",
735 *inst, inst->instToWaitFor);
736 }
737
738 inst->canEarlyIssue = true;
739 }
740 /* Also queue this instruction in the memory ref
741 * queue to ensure in-order issue to the LSQ */
742 DPRINTF(MinorExecute, "Pushing mem inst: %s\n",
743 *inst);
744 thread.inFUMemInsts->push(fu_inst);
745 }
746
747 /* Issue to FU */
748 fu->push(fu_inst);
749 /* And start the countdown on activity to allow
750 * this instruction to get to the end of its FU */
752
753 /* Mark the destinations for this instruction as
754 * busy */
755 scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() +
756 fu->description.opLat +
757 extra_dest_retire_lat +
758 extra_assumed_lat,
759 cpu.getContext(thread_id),
760 issued_mem_ref && extra_assumed_lat == Cycles(0));
761
762 /* Push the instruction onto the inFlight queue so
763 * it can be committed in order */
764 thread.inFlightInsts->push(fu_inst);
765
766 issued = true;
767 }
768 }
769
770 fu_index++;
771 } while (fu_index != numFuncUnits && !issued);
772
773 if (!issued)
774 DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst);
775 }
776
777 if (issued) {
778 /* Generate MinorTrace's MinorInst lines. Do this at commit
779 * to allow better instruction annotation? */
780 if (debug::MinorTrace && !inst->isBubble()) {
781 inst->minorTraceInst(*this);
782 }
783
784 /* Mark up barriers in the LSQ */
785 if (!discarded && inst->isInst() &&
786 inst->staticInst->isFullMemBarrier())
787 {
788 DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst);
790 }
791
792 if (inst->traceData && setTraceTimeOnIssue) {
793 inst->traceData->setWhen(curTick());
794 }
795
796 if (issued_mem_ref)
797 num_mem_insts_issued++;
798
799 if (!discarded && !inst->isBubble()) {
800 num_insts_issued++;
801
802 if (num_insts_issued == issueLimit)
803 DPRINTF(MinorExecute, "Reached inst issue limit\n");
804 }
805
806 thread.inputIndex++;
807 DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n",
808 thread.inputIndex);
809 }
810
811 /* Got to the end of a line */
812 if (thread.inputIndex == insts_in->width()) {
813 popInput(thread_id);
814 /* Set insts_in to null to force us to leave the surrounding
815 * loop */
816 insts_in = NULL;
817
819 DPRINTF(MinorExecute, "Wrapping\n");
820 insts_in = getInput(thread_id);
821 }
822 }
823 } while (insts_in && thread.inputIndex < insts_in->width() &&
824 /* We still have instructions */
825 fu_index != numFuncUnits && /* Not visited all FUs */
826 issued && /* We've not yet failed to issue an instruction */
827 num_insts_issued != issueLimit && /* Still allowed to issue */
828 num_mem_insts_issued != memoryIssueLimit);
829
830 return num_insts_issued;
831}
832
833bool
835{
836 ThreadContext *thread = cpu.getContext(thread_id);
837 unsigned int num_pc_event_checks = 0;
838
839 /* Handle PC events on instructions */
840 Addr oldPC;
841 do {
842 oldPC = thread->pcState().instAddr();
843 cpu.threads[thread_id]->pcEventQueue.service(oldPC, thread);
844 num_pc_event_checks++;
845 } while (oldPC != thread->pcState().instAddr());
846
847 if (num_pc_event_checks > 1) {
848 DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n",
849 thread->pcState());
850 }
851
852 return num_pc_event_checks > 1;
853}
854
855void
857{
858 assert(!inst->isFault());
859
860 MinorThread *thread = cpu.threads[inst->id.threadId];
861
862 /* Increment the many and various inst and op counts in the
863 * thread and system */
864 if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop())
865 {
866 thread->numInst++;
867 thread->threadStats.numInsts++;
868 cpu.commitStats[inst->id.threadId]->numInsts++;
870
871 /* Act on events related to instruction counts */
872 thread->comInstEventQueue.serviceEvents(thread->numInst);
873 }
874 thread->numOp++;
875 thread->threadStats.numOps++;
876 cpu.commitStats[inst->id.threadId]->numOps++;
877 cpu.commitStats[inst->id.threadId]
878 ->committedInstType[inst->staticInst->opClass()]++;
879
880 /* Set the CP SeqNum to the numOps commit number */
881 if (inst->traceData)
882 inst->traceData->setCPSeq(thread->numOp);
883
884 cpu.probeInstCommit(inst->staticInst, inst->pc->instAddr());
885}
886
887bool
888Execute::commitInst(MinorDynInstPtr inst, bool early_memory_issue,
889 BranchData &branch, Fault &fault, bool &committed,
890 bool &completed_mem_issue)
891{
892 ThreadID thread_id = inst->id.threadId;
893 ThreadContext *thread = cpu.getContext(thread_id);
894
895 bool completed_inst = true;
896 fault = NoFault;
897
898 /* Is the thread for this instruction suspended? In that case, just
899 * stall as long as there are no pending interrupts */
900 if (thread->status() == ThreadContext::Suspended &&
901 !isInterrupted(thread_id))
902 {
903 panic("We should never hit the case where we try to commit from a "
904 "suspended thread as the streamSeqNum should not match");
905 } else if (inst->isFault()) {
906 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
907
908 DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n",
909 inst->fault->name());
910
911 fault = inst->fault;
912 inst->fault->invoke(thread, NULL);
913
914 tryToBranch(inst, fault, branch);
915 } else if (inst->staticInst->isMemRef()) {
916 /* Memory accesses are executed in two parts:
917 * executeMemRefInst -- calculates the EA and issues the access
918 * to memory. This is done here.
919 * handleMemResponse -- handles the response packet, done by
920 * Execute::commit
921 *
922 * While the memory access is in its FU, the EA is being
923 * calculated. At the end of the FU, when it is ready to
924 * 'commit' (in this function), the access is presented to the
925 * memory queues. When a response comes back from memory,
926 * Execute::commit will commit it.
927 */
928 bool predicate_passed = false;
929 bool completed_mem_inst = executeMemRefInst(inst, branch,
930 predicate_passed, fault);
931
932 if (completed_mem_inst && fault != NoFault) {
933 if (early_memory_issue) {
934 DPRINTF(MinorExecute, "Fault in early executing inst: %s\n",
935 fault->name());
936 /* Don't execute the fault, just stall the instruction
937 * until it gets to the head of inFlightInsts */
938 inst->canEarlyIssue = false;
939 /* Not completed as we'll come here again to pick up
940 * the fault when we get to the end of the FU */
941 completed_inst = false;
942 } else {
943 DPRINTF(MinorExecute, "Fault in execute: %s\n",
944 fault->name());
945 fault->invoke(thread, NULL);
946
947 tryToBranch(inst, fault, branch);
948 completed_inst = true;
949 }
950 } else {
951 completed_inst = completed_mem_inst;
952 }
953 completed_mem_issue = completed_inst;
954 } else if (inst->isInst() && inst->staticInst->isFullMemBarrier() &&
956 {
957 DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as"
958 " there isn't space in the store buffer\n", *inst);
959
960 completed_inst = false;
961 } else if (inst->isInst() && inst->staticInst->isQuiesce()
962 && !branch.isBubble()){
963 /* This instruction can suspend, need to be able to communicate
964 * backwards, so no other branches may evaluate this cycle*/
965 completed_inst = false;
966 } else {
967 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst);
968
969 DPRINTF(MinorExecute, "Committing inst: %s\n", *inst);
970
971 fault = inst->staticInst->execute(&context,
972 inst->traceData);
973
974 /* Set the predicate for tracing and dump */
975 if (inst->traceData)
976 inst->traceData->setPredicate(context.readPredicate());
977
978 committed = true;
979
980 if (fault != NoFault) {
981 if (inst->traceData) {
982 if (debug::ExecFaulting) {
983 inst->traceData->setFaulting(true);
984 } else {
985 delete inst->traceData;
986 inst->traceData = NULL;
987 }
988 }
989
990 DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n",
991 *inst, fault->name());
992 fault->invoke(thread, inst->staticInst);
993 }
994
996 tryToBranch(inst, fault, branch);
997 }
998
999 if (completed_inst) {
1000 /* Keep a copy of this instruction's predictionSeqNum just in case
1001 * we need to issue a branch without an instruction (such as an
1002 * interrupt) */
1003 executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum;
1004
1005 /* Check to see if this instruction suspended the current thread. */
1006 if (!inst->isFault() &&
1007 thread->status() == ThreadContext::Suspended &&
1008 branch.isBubble() && /* It didn't branch too */
1009 !isInterrupted(thread_id)) /* Don't suspend if we have
1010 interrupts */
1011 {
1012 auto &resume_pc = cpu.getContext(thread_id)->pcState();
1013
1014 assert(resume_pc.microPC() == 0);
1015
1016 DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute"
1017 " inst: %s\n", thread_id, *inst);
1018
1019 cpu.fetchStats[thread_id]->numFetchSuspends++;
1020
1022 resume_pc, branch);
1023 }
1024 }
1025
1026 return completed_inst;
1027}
1028
1029void
1030Execute::commit(ThreadID thread_id, bool only_commit_microops, bool discard,
1031 BranchData &branch)
1032{
1033 Fault fault = NoFault;
1034 Cycles now = cpu.curCycle();
1035 ExecuteThreadInfo &ex_info = executeInfo[thread_id];
1036
1062 /* Has an instruction been completed? Once this becomes false, we stop
1063 * trying to complete instructions. */
1064 bool completed_inst = true;
1065
1066 /* Number of insts committed this cycle to check against commitLimit */
1067 unsigned int num_insts_committed = 0;
1068
1069 /* Number of memory access instructions committed to check against
1070 * memCommitLimit */
1071 unsigned int num_mem_refs_committed = 0;
1072
1073 if (only_commit_microops && !ex_info.inFlightInsts->empty()) {
1074 DPRINTF(MinorInterrupt, "Only commit microops %s %d\n",
1075 *(ex_info.inFlightInsts->front().inst),
1077 }
1078
1079 while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */
1080 !branch.isStreamChange() && /* No real branch */
1081 fault == NoFault && /* No faults */
1082 completed_inst && /* Still finding instructions to execute */
1083 num_insts_committed != commitLimit /* Not reached commit limit */
1084 )
1085 {
1086 if (only_commit_microops) {
1087 DPRINTF(MinorInterrupt, "Committing tail of insts before"
1088 " interrupt: %s\n",
1089 *(ex_info.inFlightInsts->front().inst));
1090 }
1091
1092 QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front());
1093
1094 InstSeqNum head_exec_seq_num =
1095 head_inflight_inst->inst->id.execSeqNum;
1096
1097 /* The instruction we actually process if completed_inst
1098 * remains true to the end of the loop body.
1099 * Start by considering the the head of the in flight insts queue */
1100 MinorDynInstPtr inst = head_inflight_inst->inst;
1101
1102 bool committed_inst = false;
1103 bool discard_inst = false;
1104 bool completed_mem_ref = false;
1105 bool issued_mem_ref = false;
1106 bool early_memory_issue = false;
1107
1108 /* Must set this again to go around the loop */
1109 completed_inst = false;
1110
1111 /* If we're just completing a macroop before an interrupt or drain,
1112 * can we stil commit another microop (rather than a memory response)
1113 * without crosing into the next full instruction? */
1114 bool can_commit_insts = !ex_info.inFlightInsts->empty() &&
1115 !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop);
1116
1117 /* Can we find a mem response for this inst */
1118 LSQ::LSQRequestPtr mem_response =
1119 (inst->inLSQ ? lsq.findResponse(inst) : NULL);
1120
1121 DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n",
1122 can_commit_insts);
1123
1124 /* Test for PC events after every instruction */
1125 if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) {
1126 ThreadContext *thread = cpu.getContext(thread_id);
1127
1128 /* Branch as there was a change in PC */
1130 MinorDynInst::bubble(), thread->pcState(), branch);
1131 } else if (mem_response &&
1132 num_mem_refs_committed < memoryCommitLimit)
1133 {
1134 /* Try to commit from the memory responses next */
1135 discard_inst = inst->id.streamSeqNum !=
1136 ex_info.streamSeqNum || discard;
1137
1138 DPRINTF(MinorExecute, "Trying to commit mem response: %s\n",
1139 *inst);
1140
1141 /* Complete or discard the response */
1142 if (discard_inst) {
1143 DPRINTF(MinorExecute, "Discarding mem inst: %s as its"
1144 " stream state was unexpected, expected: %d\n",
1145 *inst, ex_info.streamSeqNum);
1146
1147 lsq.popResponse(mem_response);
1148 } else {
1149 handleMemResponse(inst, mem_response, branch, fault);
1150 committed_inst = true;
1151 }
1152
1153 completed_mem_ref = true;
1154 completed_inst = true;
1155 } else if (can_commit_insts) {
1156 /* If true, this instruction will, subject to timing tweaks,
1157 * be considered for completion. try_to_commit flattens
1158 * the `if' tree a bit and allows other tests for inst
1159 * commit to be inserted here. */
1160 bool try_to_commit = false;
1161
1162 /* Try and issue memory ops early if they:
1163 * - Can push a request into the LSQ
1164 * - Have reached the end of their FUs
1165 * - Have had all their dependencies satisfied
1166 * - Are from the right stream
1167 *
1168 * For any other case, leave it to the normal instruction
1169 * issue below to handle them.
1170 */
1171 if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) {
1172 DPRINTF(MinorExecute, "Trying to commit from mem FUs\n");
1173
1174 const MinorDynInstPtr head_mem_ref_inst =
1175 ex_info.inFUMemInsts->front().inst;
1176 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex];
1177 const MinorDynInstPtr &fu_inst = fu->front().inst;
1178
1179 /* Use this, possibly out of order, inst as the one
1180 * to 'commit'/send to the LSQ */
1181 if (!fu_inst->isBubble() &&
1182 !fu_inst->inLSQ &&
1183 fu_inst->canEarlyIssue &&
1184 ex_info.streamSeqNum == fu_inst->id.streamSeqNum &&
1185 head_exec_seq_num > fu_inst->instToWaitFor)
1186 {
1187 DPRINTF(MinorExecute, "Issuing mem ref early"
1188 " inst: %s instToWaitFor: %d\n",
1189 *(fu_inst), fu_inst->instToWaitFor);
1190
1191 inst = fu_inst;
1192 try_to_commit = true;
1193 early_memory_issue = true;
1194 completed_inst = true;
1195 }
1196 }
1197
1198 /* Try and commit FU-less insts */
1199 if (!completed_inst && inst->isNoCostInst()) {
1200 DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst);
1201
1202 try_to_commit = true;
1203 completed_inst = true;
1204 }
1205
1206 /* Try to issue from the ends of FUs and the inFlightInsts
1207 * queue */
1208 if (!completed_inst && !inst->inLSQ) {
1209 DPRINTF(MinorExecute, "Trying to commit from FUs\n");
1210
1211 /* Try to commit from a functional unit */
1212 /* Is the head inst of the expected inst's FU actually the
1213 * expected inst? */
1214 QueuedInst &fu_inst =
1215 funcUnits[inst->fuIndex]->front();
1216 InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum;
1217
1218 if (fu_inst.inst->isBubble()) {
1219 /* No instruction ready */
1220 completed_inst = false;
1221 } else if (fu_inst_seq_num != head_exec_seq_num) {
1222 /* Past instruction: we must have already executed it
1223 * in the same cycle and so the head inst isn't
1224 * actually at the end of its pipeline
1225 * Future instruction: handled above and only for
1226 * mem refs on their way to the LSQ */
1227 } else if (fu_inst.inst->id == inst->id) {
1228 /* All instructions can be committed if they have the
1229 * right execSeqNum and there are no in-flight
1230 * mem insts before us */
1231 try_to_commit = true;
1232 completed_inst = true;
1233 }
1234 }
1235
1236 if (try_to_commit) {
1237 discard_inst = inst->id.streamSeqNum !=
1238 ex_info.streamSeqNum || discard;
1239
1240 /* Is this instruction discardable as its streamSeqNum
1241 * doesn't match? */
1242 if (!discard_inst) {
1243 /* Try to commit or discard a non-memory instruction.
1244 * Memory ops are actually 'committed' from this FUs
1245 * and 'issued' into the memory system so we need to
1246 * account for them later (commit_was_mem_issue gets
1247 * set) */
1248 if (inst->extraCommitDelayExpr) {
1249 DPRINTF(MinorExecute, "Evaluating expression for"
1250 " extra commit delay inst: %s\n", *inst);
1251
1252 ThreadContext *thread = cpu.getContext(thread_id);
1253
1254 TimingExprEvalContext context(inst->staticInst,
1255 thread, NULL);
1256
1257 uint64_t extra_delay = inst->extraCommitDelayExpr->
1258 eval(context);
1259
1260 DPRINTF(MinorExecute, "Extra commit delay expr"
1261 " result: %d\n", extra_delay);
1262
1263 if (extra_delay < 128) {
1264 inst->extraCommitDelay += Cycles(extra_delay);
1265 } else {
1266 DPRINTF(MinorExecute, "Extra commit delay was"
1267 " very long: %d\n", extra_delay);
1268 }
1269 inst->extraCommitDelayExpr = NULL;
1270 }
1271
1272 /* Move the extraCommitDelay from the instruction
1273 * into the minimumCommitCycle */
1274 if (inst->extraCommitDelay != Cycles(0)) {
1275 inst->minimumCommitCycle = cpu.curCycle() +
1276 inst->extraCommitDelay;
1277 inst->extraCommitDelay = Cycles(0);
1278 }
1279
1280 /* @todo Think about making lastMemBarrier be
1281 * MAX_UINT_64 to avoid using 0 as a marker value */
1282 if (!inst->isFault() && inst->isMemRef() &&
1283 lsq.getLastMemBarrier(thread_id) <
1284 inst->id.execSeqNum &&
1285 lsq.getLastMemBarrier(thread_id) != 0)
1286 {
1287 DPRINTF(MinorExecute, "Not committing inst: %s yet"
1288 " as there are incomplete barriers in flight\n",
1289 *inst);
1290 completed_inst = false;
1291 } else if (inst->minimumCommitCycle > now) {
1292 DPRINTF(MinorExecute, "Not committing inst: %s yet"
1293 " as it wants to be stalled for %d more cycles\n",
1294 *inst, inst->minimumCommitCycle - now);
1295 completed_inst = false;
1296 } else {
1297 completed_inst = commitInst(inst,
1298 early_memory_issue, branch, fault,
1299 committed_inst, issued_mem_ref);
1300 }
1301 } else {
1302 /* Discard instruction */
1303 completed_inst = true;
1304 }
1305
1306 if (completed_inst) {
1307 /* Allow the pipeline to advance. If the FU head
1308 * instruction wasn't the inFlightInsts head
1309 * but had already been committed, it would have
1310 * unstalled the pipeline before here */
1311 if (inst->fuIndex != noCostFUIndex) {
1312 DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id);
1313 funcUnits[inst->fuIndex]->stalled = false;
1314 }
1315 }
1316 }
1317 } else {
1318 DPRINTF(MinorExecute, "No instructions to commit\n");
1319 completed_inst = false;
1320 }
1321
1322 /* All discardable instructions must also be 'completed' by now */
1323 assert(!(discard_inst && !completed_inst));
1324
1325 /* Instruction committed but was discarded due to streamSeqNum
1326 * mismatch */
1327 if (discard_inst) {
1328 DPRINTF(MinorExecute, "Discarding inst: %s as its stream"
1329 " state was unexpected, expected: %d\n",
1330 *inst, ex_info.streamSeqNum);
1331
1332 if (fault == NoFault) {
1333 cpu.executeStats[thread_id]->numDiscardedOps++;
1334 }
1335 }
1336
1337 /* Mark the mem inst as being in the LSQ */
1338 if (issued_mem_ref) {
1339 inst->fuIndex = 0;
1340 inst->inLSQ = true;
1341 }
1342
1343 /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts
1344 * as they've *definitely* exited the FUs */
1345 if (completed_inst && inst->isMemRef()) {
1346 /* The MemRef could have been discarded from the FU or the memory
1347 * queue, so just check an FU instruction */
1348 if (!ex_info.inFUMemInsts->empty() &&
1349 ex_info.inFUMemInsts->front().inst == inst)
1350 {
1351 ex_info.inFUMemInsts->pop();
1352 }
1353 }
1354
1355 if (completed_inst && !(issued_mem_ref && fault == NoFault)) {
1356 /* Note that this includes discarded insts */
1357 DPRINTF(MinorExecute, "Completed inst: %s\n", *inst);
1358
1359 /* Got to the end of a full instruction? */
1360 ex_info.lastCommitWasEndOfMacroop = inst->isFault() ||
1361 inst->isLastOpInInst();
1362
1363 /* lastPredictionSeqNum is kept as a convenience to prevent its
1364 * value from changing too much on the minorview display */
1365 ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum;
1366
1367 /* Finished with the inst, remove it from the inst queue and
1368 * clear its dependencies */
1369 ex_info.inFlightInsts->pop();
1370
1371 /* Complete barriers in the LSQ/move to store buffer */
1372 if (inst->isInst() && inst->staticInst->isFullMemBarrier()) {
1373 DPRINTF(MinorMem, "Completing memory barrier"
1374 " inst: %s committed: %d\n", *inst, committed_inst);
1375 lsq.completeMemBarrierInst(inst, committed_inst);
1376 }
1377
1378 scoreboard[thread_id].clearInstDests(inst, inst->isMemRef());
1379 }
1380
1381 /* Handle per-cycle instruction counting */
1382 if (committed_inst) {
1383 bool is_no_cost_inst = inst->isNoCostInst();
1384
1385 /* Don't show no cost instructions as having taken a commit
1386 * slot */
1387 if (debug::MinorTrace && !is_no_cost_inst)
1388 ex_info.instsBeingCommitted.insts[num_insts_committed] = inst;
1389
1390 if (!is_no_cost_inst)
1391 num_insts_committed++;
1392
1393 if (num_insts_committed == commitLimit)
1394 DPRINTF(MinorExecute, "Reached inst commit limit\n");
1395
1396 /* Re-set the time of the instruction if that's required for
1397 * tracing */
1398 if (inst->traceData) {
1400 inst->traceData->setWhen(curTick());
1401 inst->traceData->dump();
1402 }
1403
1404 if (completed_mem_ref)
1405 num_mem_refs_committed++;
1406
1407 if (num_mem_refs_committed == memoryCommitLimit)
1408 DPRINTF(MinorExecute, "Reached mem ref commit limit\n");
1409 }
1410 }
1411}
1412
1413bool
1415{
1416 return executeInfo[thread_id].lastCommitWasEndOfMacroop &&
1418}
1419
1420void
1422{
1423 if (!inp.outputWire->isBubble())
1424 inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire);
1425
1426 BranchData &branch = *out.inputWire;
1427
1428 unsigned int num_issued = 0;
1429
1430 /* Do all the cycle-wise activities for dcachePort here to potentially
1431 * free up input spaces in the LSQ's requests queue */
1432 lsq.step();
1433
1434 /* Check interrupts first. Will halt commit if interrupt found */
1435 bool interrupted = false;
1436 ThreadID interrupt_tid = checkInterrupts(branch, interrupted);
1437
1438 if (interrupt_tid != InvalidThreadID) {
1439 /* Signalling an interrupt this cycle, not issuing/committing from
1440 * any other threads */
1441 } else if (!branch.isBubble()) {
1442 /* It's important that this is here to carry Fetch1 wakeups to Fetch1
1443 * without overwriting them */
1444 DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old"
1445 " branch to complete\n");
1446 } else {
1447 ThreadID commit_tid = getCommittingThread();
1448
1449 if (commit_tid != InvalidThreadID) {
1450 ExecuteThreadInfo& commit_info = executeInfo[commit_tid];
1451
1452 DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n",
1453 commit_tid);
1454 /* commit can set stalled flags observable to issue and so *must* be
1455 * called first */
1456 if (commit_info.drainState != NotDraining) {
1457 if (commit_info.drainState == DrainCurrentInst) {
1458 /* Commit only micro-ops, don't kill anything else */
1459 commit(commit_tid, true, false, branch);
1460
1461 if (isInbetweenInsts(commit_tid))
1462 setDrainState(commit_tid, DrainHaltFetch);
1463
1464 /* Discard any generated branch */
1465 branch = BranchData::bubble();
1466 } else if (commit_info.drainState == DrainAllInsts) {
1467 /* Kill all instructions */
1468 while (getInput(commit_tid))
1469 popInput(commit_tid);
1470 commit(commit_tid, false, true, branch);
1471 }
1472 } else {
1473 /* Commit micro-ops only if interrupted. Otherwise, commit
1474 * anything you like */
1475 DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n",
1476 commit_tid);
1477 bool only_commit_microops = interrupted &&
1478 hasInterrupt(commit_tid);
1479 commit(commit_tid, only_commit_microops, false, branch);
1480 }
1481
1482 /* Halt fetch, but don't do it until we have the current instruction in
1483 * the bag */
1484 if (commit_info.drainState == DrainHaltFetch) {
1487 cpu.getContext(commit_tid)->pcState(), branch);
1488
1490 setDrainState(commit_tid, DrainAllInsts);
1491 }
1492 }
1493 ThreadID issue_tid = getIssuingThread();
1494 /* This will issue merrily even when interrupted in the sure and
1495 * certain knowledge that the interrupt with change the stream */
1496 if (issue_tid != InvalidThreadID) {
1497 DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n",
1498 issue_tid);
1499 num_issued = issue(issue_tid);
1500 }
1501
1502 }
1503
1504 /* Run logic to step functional units + decide if we are active on the next
1505 * clock cycle */
1506 std::vector<MinorDynInstPtr> next_issuable_insts;
1507 bool can_issue_next = false;
1508
1509 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1510 /* Find the next issuable instruction for each thread and see if it can
1511 be issued */
1512 if (getInput(tid)) {
1513 unsigned int input_index = executeInfo[tid].inputIndex;
1514 MinorDynInstPtr inst = getInput(tid)->insts[input_index];
1515 if (inst->isFault()) {
1516 can_issue_next = true;
1517 } else if (!inst->isBubble()) {
1518 next_issuable_insts.push_back(inst);
1519 }
1520 }
1521 }
1522
1523 bool becoming_stalled = true;
1524
1525 /* Advance the pipelines and note whether they still need to be
1526 * advanced */
1527 for (unsigned int i = 0; i < numFuncUnits; i++) {
1529 fu->advance();
1530
1531 /* If we need to tick again, the pipeline will have been left or set
1532 * to be unstalled */
1533 if (fu->occupancy !=0 && !fu->stalled)
1534 becoming_stalled = false;
1535
1536 /* Could we possibly issue the next instruction from any thread?
1537 * This is quite an expensive test and is only used to determine
1538 * if the CPU should remain active, only run it if we aren't sure
1539 * we are active next cycle yet */
1540 for (auto inst : next_issuable_insts) {
1541 if (!fu->stalled && fu->provides(inst->staticInst->opClass()) &&
1542 scoreboard[inst->id.threadId].canInstIssue(inst,
1543 NULL, NULL, cpu.curCycle() + Cycles(1),
1544 cpu.getContext(inst->id.threadId))) {
1545 can_issue_next = true;
1546 break;
1547 }
1548 }
1549 }
1550
1551 bool head_inst_might_commit = false;
1552
1553 /* Could the head in flight insts be committed */
1554 for (auto const &info : executeInfo) {
1555 if (!info.inFlightInsts->empty()) {
1556 const QueuedInst &head_inst = info.inFlightInsts->front();
1557
1558 if (head_inst.inst->isNoCostInst()) {
1559 head_inst_might_commit = true;
1560 } else {
1561 FUPipeline *fu = funcUnits[head_inst.inst->fuIndex];
1562 if ((fu->stalled &&
1563 fu->front().inst->id == head_inst.inst->id) ||
1564 lsq.findResponse(head_inst.inst))
1565 {
1566 head_inst_might_commit = true;
1567 break;
1568 }
1569 }
1570 }
1571 }
1572
1573 DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n",
1574 (num_issued != 0 ? " (issued some insts)" : ""),
1575 (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"),
1576 (can_issue_next ? " (can issued next inst)" : ""),
1577 (head_inst_might_commit ? "(head inst might commit)" : ""),
1578 (lsq.needsToTick() ? " (LSQ needs to tick)" : ""),
1579 (interrupted ? " (interrupted)" : ""));
1580
1581 bool need_to_tick =
1582 num_issued != 0 || /* Issued some insts this cycle */
1583 !becoming_stalled || /* Some FU pipelines can still move */
1584 can_issue_next || /* Can still issue a new inst */
1585 head_inst_might_commit || /* Could possible commit the next inst */
1586 lsq.needsToTick() || /* Must step the dcache port */
1587 interrupted; /* There are pending interrupts */
1588
1589 if (!need_to_tick) {
1590 DPRINTF(Activity, "The next cycle might be skippable as there are no"
1591 " advanceable FUs\n");
1592 }
1593
1594 /* Wake up if we need to tick again */
1595 if (need_to_tick)
1597
1598 /* Note activity of following buffer */
1599 if (!branch.isBubble())
1601
1602 /* Make sure the input (if any left) is pushed */
1603 if (!inp.outputWire->isBubble())
1604 inputBuffer[inp.outputWire->threadId].pushTail();
1605}
1606
1608Execute::checkInterrupts(BranchData& branch, bool& interrupted)
1609{
1611 /* Evaluate interrupts in round-robin based upon service */
1612 do {
1613 /* Has an interrupt been signalled? This may not be acted on
1614 * straighaway so this is different from took_interrupt */
1615 bool thread_interrupted = false;
1616
1618 /* This is here because it seems that after drainResume the
1619 * interrupt controller isn't always set */
1620 thread_interrupted = executeInfo[tid].drainState == NotDraining &&
1621 isInterrupted(tid);
1622 interrupted = interrupted || thread_interrupted;
1623 } else {
1624 DPRINTF(MinorInterrupt, "No interrupt controller\n");
1625 }
1626 DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n",
1627 tid, thread_interrupted, isInbetweenInsts(tid));
1628 /* Act on interrupts */
1629 if (thread_interrupted && isInbetweenInsts(tid)) {
1630 if (takeInterrupt(tid, branch)) {
1631 interruptPriority = tid;
1632 return tid;
1633 }
1634 } else {
1635 tid = (tid + 1) % cpu.numThreads;
1636 }
1637 } while (tid != interruptPriority);
1638
1639 return InvalidThreadID;
1640}
1641
1642bool
1644{
1645 if (FullSystem && cpu.getInterruptController(thread_id)) {
1646 return executeInfo[thread_id].drainState == NotDraining &&
1647 isInterrupted(thread_id);
1648 }
1649
1650 return false;
1651}
1652
1653void
1655{
1656 std::ostringstream insts;
1657 std::ostringstream stalled;
1658
1659 executeInfo[0].instsBeingCommitted.reportData(insts);
1660 lsq.minorTrace();
1661 inputBuffer[0].minorTrace();
1662 scoreboard[0].minorTrace();
1663
1664 /* Report functional unit stalling in one string */
1665 unsigned int i = 0;
1666 while (i < numFuncUnits)
1667 {
1668 stalled << (funcUnits[i]->stalled ? '1' : 'E');
1669 i++;
1670 if (i != numFuncUnits)
1671 stalled << ',';
1672 }
1673
1674 minor::minorTrace("insts=%s inputIndex=%d streamSeqNum=%d"
1675 " stalled=%s drainState=%d isInbetweenInsts=%d\n",
1676 insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum,
1677 stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0));
1678
1679 std::for_each(funcUnits.begin(), funcUnits.end(),
1680 std::mem_fn(&FUPipeline::minorTrace));
1681
1682 executeInfo[0].inFlightInsts->minorTrace();
1683 executeInfo[0].inFUMemInsts->minorTrace();
1684}
1685
1686inline ThreadID
1688{
1689 std::vector<ThreadID> priority_list;
1690
1691 switch (cpu.threadPolicy) {
1692 case enums::SingleThreaded:
1693 return 0;
1694 case enums::RoundRobin:
1695 priority_list = cpu.roundRobinPriority(commitPriority);
1696 break;
1697 case enums::Random:
1698 priority_list = cpu.randomPriority();
1699 break;
1700 default:
1701 panic("Invalid thread policy");
1702 }
1703
1704 for (auto tid : priority_list) {
1705 ExecuteThreadInfo &ex_info = executeInfo[tid];
1706 bool can_commit_insts = !ex_info.inFlightInsts->empty();
1707 if (can_commit_insts) {
1708 QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front());
1709 MinorDynInstPtr inst = head_inflight_inst->inst;
1710
1711 can_commit_insts = can_commit_insts &&
1712 (!inst->inLSQ || (lsq.findResponse(inst) != NULL));
1713
1714 if (!inst->inLSQ) {
1715 bool can_transfer_mem_inst = false;
1716 if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) {
1717 const MinorDynInstPtr head_mem_ref_inst =
1718 ex_info.inFUMemInsts->front().inst;
1719 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex];
1720 const MinorDynInstPtr &fu_inst = fu->front().inst;
1721 can_transfer_mem_inst =
1722 !fu_inst->isBubble() &&
1723 fu_inst->id.threadId == tid &&
1724 !fu_inst->inLSQ &&
1725 fu_inst->canEarlyIssue &&
1726 inst->id.execSeqNum > fu_inst->instToWaitFor;
1727 }
1728
1729 bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex;
1730 if (can_commit_insts && !can_transfer_mem_inst &&
1731 inst->fuIndex != noCostFUIndex)
1732 {
1733 QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front();
1734 can_execute_fu_inst = !fu_inst.inst->isBubble() &&
1735 fu_inst.inst->id == inst->id;
1736 }
1737
1738 can_commit_insts = can_commit_insts &&
1739 (can_transfer_mem_inst || can_execute_fu_inst);
1740 }
1741 }
1742
1743
1744 if (can_commit_insts) {
1745 commitPriority = tid;
1746 return tid;
1747 }
1748 }
1749
1750 return InvalidThreadID;
1751}
1752
1753inline ThreadID
1755{
1756 std::vector<ThreadID> priority_list;
1757
1758 switch (cpu.threadPolicy) {
1759 case enums::SingleThreaded:
1760 return 0;
1761 case enums::RoundRobin:
1762 priority_list = cpu.roundRobinPriority(issuePriority);
1763 break;
1764 case enums::Random:
1765 priority_list = cpu.randomPriority();
1766 break;
1767 default:
1768 panic("Invalid thread scheduling policy.");
1769 }
1770
1771 for (auto tid : priority_list) {
1772 if (getInput(tid)) {
1773 issuePriority = tid;
1774 return tid;
1775 }
1776 }
1777
1778 return InvalidThreadID;
1779}
1780
1781void
1783{
1784 DPRINTF(Drain, "MinorExecute drainResume\n");
1785
1786 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1788 }
1789
1791}
1792
1793std::ostream &operator <<(std::ostream &os, Execute::DrainState state)
1794{
1795 switch (state)
1796 {
1798 os << "NotDraining";
1799 break;
1801 os << "DrainCurrentInst";
1802 break;
1804 os << "DrainHaltFetch";
1805 break;
1807 os << "DrainAllInsts";
1808 break;
1809 default:
1810 os << "Drain-" << static_cast<int>(state);
1811 break;
1812 }
1813
1814 return os;
1815}
1816
1817void
1819{
1820 DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state);
1821 executeInfo[thread_id].drainState = state;
1822}
1823
1824unsigned int
1826{
1827 DPRINTF(Drain, "MinorExecute drain\n");
1828
1829 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1830 if (executeInfo[tid].drainState == NotDraining) {
1832
1833 /* Go to DrainCurrentInst if we're between microops
1834 * or waiting on an unbufferable memory operation.
1835 * Otherwise we can go straight to DrainHaltFetch
1836 */
1837 if (isInbetweenInsts(tid))
1839 else
1841 }
1842 }
1843 return (isDrained() ? 0 : 1);
1844}
1845
1846bool
1848{
1849 if (!lsq.isDrained())
1850 return false;
1851
1852 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
1853 if (!inputBuffer[tid].empty() ||
1854 !executeInfo[tid].inFlightInsts->empty()) {
1855
1856 return false;
1857 }
1858 }
1859
1860 return true;
1861}
1862
1864{
1865 for (unsigned int i = 0; i < numFuncUnits; i++)
1866 delete funcUnits[i];
1867
1868 for (ThreadID tid = 0; tid < cpu.numThreads; tid++)
1869 delete executeInfo[tid].inFlightInsts;
1870}
1871
1872bool
1874{
1875 return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum;
1876}
1877
1878bool
1880{
1881 bool ret = false;
1882
1883 if (!executeInfo[inst->id.threadId].inFlightInsts->empty())
1884 ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id;
1885
1886 return ret;
1887}
1888
1891{
1892 return lsq.getDcachePort();
1893}
1894
1895} // namespace minor
1896} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
void activity()
Records that there is activity this cycle.
Definition activity.cc:55
BaseInterrupts * getInterruptController(ThreadID tid)
Definition base.hh:228
virtual ThreadContext * getContext(int tn)
Given a thread num get tho thread context for it.
Definition base.hh:288
std::vector< std::unique_ptr< CommitCPUStats > > commitStats
Definition base.hh:821
gem5::BaseCPU::BaseCPUStats baseStats
ThreadID numThreads
Number of threads we're actually simulating (<= SMT_MAX_THREADS).
Definition base.hh:390
std::vector< std::unique_ptr< ExecuteCPUStats > > executeStats
Definition base.hh:820
bool checkInterrupts(ThreadID tid) const
Definition base.hh:254
std::vector< std::unique_ptr< FetchCPUStats > > fetchStats
Definition base.hh:819
virtual void probeInstCommit(const StaticInstPtr &inst, Addr pc)
Helper method to trigger PMU probes for a committed instruction.
Definition base.cc:390
virtual void updateIntrInfo()=0
virtual Fault getInterrupt()=0
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
Provide a non-protected base class for Minor's Ports as derived classes are created by Fetch1 and Exe...
Definition cpu.hh:106
MinorCPU is an in-order CPU model with four fixed pipeline stages:
Definition cpu.hh:85
minor::MinorActivityRecorder * activityRecorder
Activity recording for pipeline.
Definition cpu.hh:95
void wakeupOnEvent(unsigned int stage_id)
Interface for stages to signal that they have become active after a callback or eventq event where th...
Definition cpu.cc:291
std::vector< ThreadID > randomPriority()
Definition cpu.hh:181
std::vector< ThreadID > roundRobinPriority(ThreadID priority)
Thread scheduling utility functions.
Definition cpu.hh:172
enums::ThreadPolicy threadPolicy
Thread Scheduling Policy (RoundRobin, Random, etc)
Definition cpu.hh:119
std::vector< minor::MinorThread * > threads
These are thread state-representing objects for this CPU.
Definition cpu.hh:100
std::vector< MinorFU * > funcUnits
Definition func_unit.hh:192
Extra timing capability to allow individual ops to have their source register dependency latencies tw...
Definition func_unit.hh:104
TimingExpr * extraCommitLatExpr
Definition func_unit.hh:121
std::vector< Cycles > srcRegsRelativeLats
Cycle offsets from the scoreboard delivery times of register values for each of this instruction's so...
Definition func_unit.hh:136
Cycles extraAssumedLat
Extra delay that results should show in the scoreboard after leaving the pipeline.
Definition func_unit.hh:127
bool suppress
If true, instructions matching this mask/match should not be issued in this FU.
Definition func_unit.hh:116
Cycles extraCommitLat
Extra latency that the instruction should spend at the end of the pipeline.
Definition func_unit.hh:120
A functional unit that can execute any of opClasses operations with a single op(eration)Lat(ency) and...
Definition func_unit.hh:158
Cycles opLat
Delay from issuing the operation, to it reaching the end of the associated pipeline.
Definition func_unit.hh:164
Interface for things with names.
Definition named.hh:39
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition pcstate.hh:108
virtual PCStateBase * clone() const =0
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
Addr getAddr() const
Definition packet.hh:807
bool isError() const
Definition packet.hh:622
unsigned getSize() const
Definition packet.hh:817
const T * getConstPtr() const
Definition packet.hh:1234
The SimpleThread object provides a combination of the ThreadState object and the ThreadContext interf...
EventQueue comInstEventQueue
An instruction-based event queue.
Base class for branch operations.
Definition branch.hh:49
ThreadContext is the external interface to all thread state for anything outside of the CPU.
@ Suspended
Temporarily inactive.
virtual const PCStateBase & pcState() const =0
virtual Status status() const =0
Object to gather the visible context for evaluation.
Forward data betwen Execute and Fetch1 carrying change-of-address/stream information.
Definition pipe_data.hh:66
static bool isStreamChange(const BranchData::Reason reason)
Is a request with this reason actually a request to change the PC rather than a bubble or branch pred...
Definition pipe_data.cc:84
bool isStreamChange() const
As static isStreamChange but on this branch data.
Definition pipe_data.hh:166
static BranchData bubble()
BubbleIF interface.
Definition pipe_data.hh:162
ExecContext bears the exec_context interface for Minor.
bool readMemAccPredicate() const override
bool readPredicate() const override
bool setTraceTimeOnIssue
Modify instruction trace times on issue.
Definition execute.hh:111
void handleMemResponse(MinorDynInstPtr inst, LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault)
Handle extracting mem ref responses from the memory queues and completing the associated instructions...
Definition execute.cc:325
bool processMoreThanOneInput
If true, more than one input line can be processed each cycle if there is room to execute more instru...
Definition execute.hh:95
LSQ lsq
Dcache port to pass on to the CPU.
Definition execute.hh:122
void evaluate()
Pass on input/buffer data to the output if you can.
Definition execute.cc:1421
unsigned int commitLimit
Number of instructions that can be committed per cycle.
Definition execute.hh:87
void popInput(ThreadID tid)
Pop an element off the input buffer, if there are any.
Definition execute.cc:211
unsigned int memoryCommitLimit
Number of memory instructions that can be committed per cycle.
Definition execute.hh:90
bool executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, bool &failed_predicate, Fault &fault)
Execute a memory reference instruction.
Definition execute.cc:450
unsigned int issue(ThreadID thread_id)
Try and issue instructions from the inputBuffer.
Definition execute.cc:547
unsigned int noCostFUIndex
The FU index of the non-existent costless FU for instructions which pass the MinorDynInst::isNoCostIn...
Definition execute.hh:119
unsigned int memoryIssueLimit
Number of memory ops that can be issued per cycle.
Definition execute.hh:84
Latch< ForwardInstData >::Output inp
Input port carrying instructions from Decode.
Definition execute.hh:72
ThreadID commitPriority
Definition execute.hh:211
void commit(ThreadID thread_id, bool only_commit_microops, bool discard, BranchData &branch)
Try and commit instructions from the ends of the functional unit pipelines.
Definition execute.cc:1030
MinorCPU & cpu
Pointer back to the containing CPU.
Definition execute.hh:78
ThreadID getIssuingThread()
Definition execute.cc:1754
unsigned int drain()
Like the drain interface on SimObject.
Definition execute.cc:1825
unsigned int issueLimit
Number of instructions that can be issued per cycle.
Definition execute.hh:81
bool instIsRightStream(MinorDynInstPtr inst)
Does the given instruction have the right stream sequence number to be committed?
Definition execute.cc:1873
void setDrainState(ThreadID thread_id, DrainState state)
Set the drain state (with useful debugging messages)
Definition execute.cc:1818
bool setTraceTimeOnCommit
Modify instruction trace times on commit.
Definition execute.hh:108
ThreadID checkInterrupts(BranchData &branch, bool &interrupted)
Check all threads for possible interrupts.
Definition execute.cc:1608
void updateBranchData(ThreadID tid, BranchData::Reason reason, MinorDynInstPtr inst, const PCStateBase &target, BranchData &branch)
Actually create a branch to communicate to Fetch1/Fetch2 and, if that is a stream-changing branch upd...
Definition execute.cc:299
DrainState
Stage cycle-by-cycle state.
Definition execute.hh:145
MinorFUPool & fuDescriptions
Descriptions of the functional units we want to generate.
Definition execute.hh:98
bool allowEarlyMemIssue
Allow mem refs to leave their FUs before reaching the head of the in flight insts queue if their depe...
Definition execute.hh:115
unsigned int numFuncUnits
Number of functional units to produce.
Definition execute.hh:101
std::vector< FUPipeline * > funcUnits
The execution functional units.
Definition execute.hh:128
void tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch)
Generate Branch data based (into branch) on an observed (or not) change in PC while executing an inst...
Definition execute.cc:220
bool commitInst(MinorDynInstPtr inst, bool early_memory_issue, BranchData &branch, Fault &fault, bool &committed, bool &completed_mem_issue)
Commit a single instruction.
Definition execute.cc:888
bool hasInterrupt(ThreadID thread_id)
Checks if a specific thread has an interrupt.
Definition execute.cc:1643
bool isInterrupted(ThreadID thread_id) const
Has an interrupt been raised.
Definition execute.cc:416
bool isInbetweenInsts(ThreadID thread_id) const
Are we between instructions? Can we be interrupted?
Definition execute.cc:1414
Execute(const std::string &name_, MinorCPU &cpu_, const BaseMinorCPUParams &params, Latch< ForwardInstData >::Output inp_, Latch< BranchData >::Input out_)
Definition execute.cc:63
ThreadID interruptPriority
Definition execute.hh:209
std::vector< Scoreboard > scoreboard
Scoreboard of instruction dependencies.
Definition execute.hh:125
bool takeInterrupt(ThreadID thread_id, BranchData &branch)
Act on an interrupt.
Definition execute.cc:422
std::vector< ExecuteThreadInfo > executeInfo
Definition execute.hh:207
std::vector< InputBuffer< ForwardInstData > > inputBuffer
Definition execute.hh:131
void doInstCommitAccounting(MinorDynInstPtr inst)
Do the stats handling and instruction count and PC event events related to the new instruction/op cou...
Definition execute.cc:856
MinorCPU::MinorCPUPort & getDcachePort()
Returns the DcachePort owned by this Execute to pass upwards.
Definition execute.cc:1890
bool instIsHeadInst(MinorDynInstPtr inst)
Returns true if the given instruction is at the head of the inFlightInsts instruction queue.
Definition execute.cc:1879
const ForwardInstData * getInput(ThreadID tid)
Get a piece of data to work on from the inputBuffer, or 0 if there is no data.
Definition execute.cc:198
void minorTrace() const
Definition execute.cc:1654
Latch< BranchData >::Input out
Input port carrying stream changes to Fetch1.
Definition execute.hh:75
ThreadID issuePriority
Definition execute.hh:210
bool isDrained()
After thread suspension, has Execute been drained of in-flight instructions and memory accesses.
Definition execute.cc:1847
ThreadID getCommittingThread()
Use the current threading policy to determine the next thread to decode from.
Definition execute.cc:1687
bool tryPCEvents(ThreadID thread_id)
Try to act on PC-related events.
Definition execute.cc:834
A functional unit configured from a MinorFU object.
Definition func_unit.hh:233
void advance()
Step the pipeline.
Definition func_unit.cc:158
Forward flowing data between Fetch2,Decode,Execute carrying a packet of instructions of a width appro...
Definition pipe_data.hh:284
bool isBubble() const
BubbleIF interface.
Definition pipe_data.cc:250
MinorDynInstPtr insts[MAX_FORWARD_INSTS]
Array of carried insts, ref counted.
Definition pipe_data.hh:287
unsigned int width() const
Number of instructions carried by this object.
Definition pipe_data.hh:303
Like a Queue but with a restricted interface and a setTail function which, when the queue is empty,...
Definition buffers.hh:572
Derived SenderState to carry data access info.
Definition lsq.hh:129
bool needsToBeSentToStoreBuffer()
This request, once processed by the requests/transfers queues, will need to go to the store buffer.
Definition lsq.cc:164
bool needsToTick()
May need to be ticked next cycle as one of the queues contains an actionable transfers or address tra...
Definition lsq.cc:1563
void issuedMemBarrierInst(MinorDynInstPtr inst)
A memory barrier instruction has been issued, remember its execSeqNum that we can avoid issuing memor...
Definition lsq.cc:1717
void minorTrace() const
Definition lsq.cc:1673
void sendStoreToStoreBuffer(LSQRequestPtr request)
A store has been committed, please move it to the store buffer.
Definition lsq.cc:1543
void pushFailedRequest(MinorDynInstPtr inst)
Push a predicate failed-representing request into the queues just to maintain commit order.
Definition lsq.cc:1666
bool canPushIntoStoreBuffer() const
Must check this before trying to insert into the store buffer.
Definition lsq.hh:681
bool accessesInFlight() const
Are there any accesses other than normal cached loads in the memory system or having received respons...
Definition lsq.hh:689
MinorCPU::MinorCPUPort & getDcachePort()
Return the raw-bindable port.
Definition lsq.hh:731
void step()
Step checks the queues to see if their are issuable transfers which were not otherwise picked up by t...
Definition lsq.cc:1475
InstSeqNum getLastMemBarrier(ThreadID thread_id) const
Get the execSeqNum of the last issued memory barrier.
Definition lsq.hh:698
void completeMemBarrierInst(MinorDynInstPtr inst, bool committed)
Complete a barrier instruction.
Definition lsq.cc:913
void popResponse(LSQRequestPtr response)
Sanity check and pop the head response.
Definition lsq.cc:1521
LSQRequestPtr findResponse(MinorDynInstPtr inst)
Returns a response if it's at the head of the transfers queue and it's either complete or can be sent...
Definition lsq.cc:1486
bool isDrained()
Is there nothing left in the LSQ.
Definition lsq.cc:1556
bool canRequest()
Is their space in the request queue to be able to push a request by issuing an isMemRef instruction.
Definition lsq.hh:669
Encapsulate wires on either input or output of the latch.
Definition buffers.hh:252
static MinorDynInstPtr bubble()
There is a single bubble inst.
Definition dyn_inst.hh:250
Wrapper for a queue type to act as a pipeline stage input queue.
Definition buffers.hh:404
Container class to box instructions in the FUs to make those queues have correct bubble behaviour whe...
Definition func_unit.hh:207
MinorDynInstPtr inst
Definition func_unit.hh:209
...ReportTraits are trait classes with the same functionality as ReportIF, but with elements explicit...
Definition buffers.hh:97
STL vector class.
Definition stl.hh:37
Top level definition of the Minor in-order CPU model.
All the fun of executing instructions from Decode and sending branch/new instruction stream info.
Fetch1 is responsible for fetching "lines" from memory and passing them to Fetch2.
void serviceEvents(Tick when)
process all events up to the given timestamp.
Definition eventq.hh:869
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
atomic_var_t state
Definition helpers.cc:211
#define warn(...)
Definition logging.hh:256
ExecContext bears the exec_context interface for Minor.
A load/store queue that allows outstanding reads and writes.
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 30, 0 > index
Bitfield< 12 > fu
Definition misc.hh:94
Bitfield< 17 > os
Definition misc.hh:838
unsigned int cyclicIndexInc(unsigned int index, unsigned int cycle_size)
Increment a cyclic buffer index for indices [0, cycle_size-1].
Definition execute.cc:524
unsigned int cyclicIndexDec(unsigned int index, unsigned int cycle_size)
Decrement a cyclic buffer index for indices [0, cycle_size-1].
Definition execute.cc:536
std::ostream & operator<<(std::ostream &os, const InstId &id)
Print this id in the usual slash-separated format expected by MinorTrace.
Definition dyn_inst.cc:63
void minorTrace(const char *fmt, Args ...args)
DPRINTFN for MinorTrace reporting.
Definition trace.hh:66
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
int16_t ThreadID
Thread index/ID type.
Definition types.hh:235
const ThreadID InvalidThreadID
Definition types.hh:236
static const OpClass Num_OpClasses
Definition op_class.hh:135
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition root.cc:220
constexpr decltype(nullptr) NoFault
Definition types.hh:253
uint64_t InstSeqNum
Definition inst_seq.hh:40
Minor contains all the definitions within the MinorCPU apart from the CPU class itself.
statistics::Scalar numInsts
Definition base.hh:637
statistics::Scalar numOps
Stat for number ops (including micro ops) committed.
statistics::Scalar numInsts
Stat for number instructions committed.
Counter numInst
Number of instructions committed.
Counter numOp
Number of ops (including micro ops) committed.
gem5::ThreadState::ThreadStateStats threadStats
unsigned int inputIndex
Index that we've completed upto in getInput data.
Definition execute.hh:181
ForwardInstData instsBeingCommitted
Structure for reporting insts currently being processed/retired for MinorTrace.
Definition execute.hh:189
bool lastCommitWasEndOfMacroop
The last commit was the end of a full instruction so an interrupt can safely happen.
Definition execute.hh:185
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFlightInsts
In-order instructions either in FUs or the LSQ.
Definition execute.hh:174
DrainState drainState
State progression for draining NotDraining -> ... -> DrainAllInsts.
Definition execute.hh:204
InstSeqNum lastPredictionSeqNum
A prediction number for use where one isn't available from an instruction.
Definition execute.hh:201
InstSeqNum streamSeqNum
Source of sequence number for instuction streams.
Definition execute.hh:195
Queue< QueuedInst, ReportTraitsAdaptor< QueuedInst > > * inFUMemInsts
Memory ref instructions still in the FUs.
Definition execute.hh:177

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0