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

Generated on Mon Oct 27 2025 04:13:00 for gem5 by doxygen 1.14.0