From 8db27aa230c40c21acf55fda3755ed173c34e47c Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 7 Jan 2013 13:05:45 -0500 Subject: [PATCH] cpu: Fix broken squashAfter implementation in O3 CPU Commit can currently both commit and squash in the same cycle. This confuses other stages since the signals coming from the commit stage can only signal either a squash or a commit in a cycle. This changeset changes the behavior of squashAfter so that it commits all instructions, including the instruction that requested the squash, in the first cycle and then starts to squash in the next cycle. --- src/cpu/o3/commit.hh | 47 +++++++++++++++++++++++++++++++----- src/cpu/o3/commit_impl.hh | 50 +++++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index fdd9609a4..2d8d88b21 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2012 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -129,7 +129,8 @@ class DefaultCommit Idle, ROBSquashing, TrapPending, - FetchTrapPending + FetchTrapPending, + SquashAfterPending, //< Committing instructions before a squash. }; /** Commit policy for SMT mode. */ @@ -259,13 +260,38 @@ class DefaultCommit /** Handles squashing due to an TC write. */ void squashFromTC(ThreadID tid); - /** Handles squashing from instruction with SquashAfter set. + /** Handles a squash from a squashAfter() request. */ + void squashFromSquashAfter(ThreadID tid); + + /** + * Handle squashing from instruction with SquashAfter set. + * * This differs from the other squashes as it squashes following * instructions instead of the current instruction and doesn't - * clean up various status bits about traps/tc writes pending. + * clean up various status bits about traps/tc writes + * pending. Since there might have been instructions committed by + * the commit stage before the squashing instruction was reached + * and we can't commit and squash in the same cycle, we have to + * squash in two steps: + * + *
    + *
  1. Immediately set the commit status of the thread of + * SquashAfterPending. This forces the thread to stop + * committing instructions in this cycle. The last + * instruction to be committed in this cycle will be the + * SquashAfter instruction. + *
  2. In the next cycle, commit() checks for the + * SquashAfterPending state and squashes all + * in-flight instructions. Since the SquashAfter instruction + * was the last instruction to be committed in the previous + * cycle, this causes all subsequent instructions to be + * squashed. + *
+ * + * @param tid ID of the thread to squash. + * @param head_inst Instruction that requested the squash. */ - void squashAfter(ThreadID tid, DynInstPtr &head_inst, - uint64_t squash_after_seq_num); + void squashAfter(ThreadID tid, DynInstPtr &head_inst); /** Handles processing an interrupt. */ void handleInterrupt(); @@ -372,6 +398,15 @@ class DefaultCommit /** Records if a thread has to squash this cycle due to an XC write. */ bool tcSquash[Impl::MaxThreads]; + /** + * Instruction passed to squashAfter(). + * + * The squash after implementation needs to buffer the instruction + * that caused a squash since this needs to be passed to the fetch + * stage once squashing starts. + */ + DynInstPtr squashAfterInst[Impl::MaxThreads]; + /** Priority List used for Commit Policy */ std::list priority_list; diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index bff5c5ae9..333ccc89f 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -144,6 +144,7 @@ DefaultCommit::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params) tcSquash[tid] = false; pc[tid].set(0); lastCommitedSeqNum[tid] = 0; + squashAfterInst[tid] = NULL; } interrupt = NoFault; } @@ -404,6 +405,7 @@ DefaultCommit::takeOverFrom() changedROBNumEntries[tid] = false; trapSquash[tid] = false; tcSquash[tid] = false; + squashAfterInst[tid] = NULL; } squashCounter = 0; rob->takeOverFrom(); @@ -587,31 +589,32 @@ DefaultCommit::squashFromTC(ThreadID tid) template void -DefaultCommit::squashAfter(ThreadID tid, DynInstPtr &head_inst, - uint64_t squash_after_seq_num) +DefaultCommit::squashFromSquashAfter(ThreadID tid) { - youngestSeqNum[tid] = squash_after_seq_num; + DPRINTF(Commit, "Squashing after squash after request, " + "restarting at PC %s\n", pc[tid]); - rob->squash(squash_after_seq_num, tid); - changedROBNumEntries[tid] = true; - - // Send back the sequence number of the squashed instruction. - toIEW->commitInfo[tid].doneSeqNum = squash_after_seq_num; - - toIEW->commitInfo[tid].squashInst = head_inst; - // Send back the squash signal to tell stages that they should squash. - toIEW->commitInfo[tid].squash = true; - - // Send back the rob squashing signal so other stages know that - // the ROB is in the process of squashing. - toIEW->commitInfo[tid].robSquashing = true; + squashAll(tid); + // Make sure to inform the fetch stage of which instruction caused + // the squash. It'll try to re-fetch an instruction executing in + // microcode unless this is set. + toIEW->commitInfo[tid].squashInst = squashAfterInst[tid]; + squashAfterInst[tid] = NULL; - toIEW->commitInfo[tid].mispredictInst = NULL; + commitStatus[tid] = ROBSquashing; + cpu->activityThisCycle(); +} - toIEW->commitInfo[tid].pc = pc[tid]; +template +void +DefaultCommit::squashAfter(ThreadID tid, DynInstPtr &head_inst) +{ DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%lli]\n", - tid, squash_after_seq_num); - commitStatus[tid] = ROBSquashing; + tid, head_inst->seqNum); + + assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst); + commitStatus[tid] = SquashAfterPending; + squashAfterInst[tid] = head_inst; } template @@ -797,6 +800,11 @@ DefaultCommit::commit() } else if (tcSquash[tid] == true) { assert(commitStatus[tid] != TrapPending); squashFromTC(tid); + } else if (commitStatus[tid] == SquashAfterPending) { + // A squash from the previous cycle of the commit stage (i.e., + // commitInsts() called squashAfter) is pending. Squash the + // thread now. + squashFromSquashAfter(tid); } // Squashed sequence number must be older than youngest valid @@ -1008,7 +1016,7 @@ DefaultCommit::commitInsts() // If this is an instruction that doesn't play nicely with // others squash everything and restart fetch if (head_inst->isSquashAfter()) - squashAfter(tid, head_inst, head_inst->seqNum); + squashAfter(tid, head_inst); int count = 0; Addr oldpc; -- 2.30.2