3 ms·
Let me add a couple thoughts: 1. You typically won't get very far without also implementing register renaming, such that the reorder buffer is actually much la
by dbcurtis 8y ago
Let me add a couple thoughts:
1. You typically won't get very far without also implementing register renaming, such that the reorder buffer is actually much larger than the register file.
2. You need to distinguish between instructions that are "complete" (result is available for internal bypass to another instruction that is being speculatively executed) versus "retired" (all instructions before it have retired, the instruction can no longer raise an exception, you know for certain that it was not executed because of incorrect speculation). Canonical, architecturally visible state is only written on retirement.
3. Without good branch prediction, it is kind of pointless. A reasonable rule-of-thumb-Kentucky-windage estimate is that 20-25% of the instructions that you encounter in execution order (not static code analysis) are branches. So if you have 30 or more instructions active in the pipe, your branch prediction needs to be pretty good or you waste too much work. (Note that some branches are just "flakey" (hard to predict) but the compiler can usually do a decent job of identifying those ahead of time. Thus, modern processors include a conditional-move instruction which allows the compiler to manage speculation and replace the flakey branch with an instruction that does not pollute the branch target buffer.
4. Watching what happens in the simulator at the end of a pointer chasing loop is good humor. A strongly predicted branch gets mispredicted on: while(p!=NULL) {}, and all sorts of page-fault, memory-exception, arithmetic-exception logic lights up all over the place until something asserts "OOPS_NEVER_MIND", at which point all that fun stuff collapses in a smoldering heap. Watching that never gets old.