diff options
author | Andreas Sandberg <Andreas.Sandberg@ARM.com> | 2013-01-07 13:05:46 -0500 |
---|---|---|
committer | Andreas Sandberg <Andreas.Sandberg@ARM.com> | 2013-01-07 13:05:46 -0500 |
commit | 1814a85a055732baf98fd030441bb4c5c5db9bdc (patch) | |
tree | 33dd6adc62342a55ac3b0f4dbe9fdb9d82faa323 /src/cpu/o3/lsq_impl.hh | |
parent | 9e8003148f78811e600e51a900f96b71cb525b60 (diff) | |
download | gem5-1814a85a055732baf98fd030441bb4c5c5db9bdc.tar.xz |
cpu: Rewrite O3 draining to avoid stopping in microcode
Previously, the O3 CPU could stop in the middle of a microcode
sequence. This patch makes sure that the pipeline stops when it has
committed a normal instruction or exited from a microcode
sequence. Additionally, it makes sure that the pipeline has no
instructions in flight when it is drained, which should make draining
more robust.
Draining is controlled in the commit stage, which checks if the next
PC after a committed instruction is in microcode. If this isn't the
case, it requests a squash of all instructions after that the
instruction that just committed and immediately signals a drain stall
to the fetch stage. The CPU then continues to execute until the
pipeline and all associated buffers are empty.
Diffstat (limited to 'src/cpu/o3/lsq_impl.hh')
-rw-r--r-- | src/cpu/o3/lsq_impl.hh | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 7051c9f7c..c796d7078 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -45,6 +45,7 @@ #include <string> #include "cpu/o3/lsq.hh" +#include "debug/Drain.hh" #include "debug/Fetch.hh" #include "debug/LSQ.hh" #include "debug/Writeback.hh" @@ -143,11 +144,36 @@ LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr) template <class Impl> void -LSQ<Impl>::switchOut() +LSQ<Impl>::drainSanityCheck() const { - for (ThreadID tid = 0; tid < numThreads; tid++) { - thread[tid].switchOut(); + assert(isDrained()); + + for (ThreadID tid = 0; tid < numThreads; tid++) + thread[tid].drainSanityCheck(); +} + +template <class Impl> +bool +LSQ<Impl>::isDrained() const +{ + bool drained(true); + + if (!lqEmpty()) { + DPRINTF(Drain, "Not drained, LQ not empty.\n"); + drained = false; + } + + if (!sqEmpty()) { + DPRINTF(Drain, "Not drained, SQ not empty.\n"); + drained = false; + } + + if (retryTid != InvalidThreadID) { + DPRINTF(Drain, "Not drained, the LSQ has blocked the caches.\n"); + drained = false; } + + return drained; } template <class Impl> @@ -458,6 +484,47 @@ LSQ<Impl>::isFull(ThreadID tid) template<class Impl> bool +LSQ<Impl>::isEmpty() const +{ + return lqEmpty() && sqEmpty(); +} + +template<class Impl> +bool +LSQ<Impl>::lqEmpty() const +{ + list<ThreadID>::const_iterator threads = activeThreads->begin(); + list<ThreadID>::const_iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (!thread[tid].lqEmpty()) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::sqEmpty() const +{ + list<ThreadID>::const_iterator threads = activeThreads->begin(); + list<ThreadID>::const_iterator end = activeThreads->end(); + + while (threads != end) { + ThreadID tid = *threads++; + + if (!thread[tid].sqEmpty()) + return false; + } + + return true; +} + +template<class Impl> +bool LSQ<Impl>::lqFull() { list<ThreadID>::iterator threads = activeThreads->begin(); |