An out-of-order CPU core needs to keep track of all dependences in the instruction stream so that instructions do not get executed in the wrong order. We describe below the different types of dependences and how Simics handles them.
Figure 1 shows three types of dependences, read-after-write (RAW), write-after-read (WAR) and write-after-write (WAW). We are using assembly code with the format opcode source1, source2, destination.
![]() |
Figure 1. Different types of dependences |
RAW dependences are also called data dependences since there is a flow of data between the dependent instructions. A data dependence exists between instruction x and y if y uses a result directly produced by x or produced by an instruction that has a RAW dependence on x. Instructions with RAW dependences can not be reordered. Simics will ensure that RAW dependences are followed and will refuse to execute instructions that did not receive all the input they needed (although the user may also speculate on the input values, thus fulfilling this requirement).
WAR and WAW dependences are sometimes called anti-dependences or name dependences since the two instructions use the same resource but there is no flow of data between them. A name dependence exists if:
Instruction WAW and WAR dependences can be reordered by allocating more resources to their execution. In the WAW case, the CPU could write to an internal register %r0 instead of %g4, thus removing the resource conflict and the dependence. This is commonly called register renaming. Simics has the capability to handle all anti-dependences by using an unlimited pool of internal registers.
Simics MAI for SPARC-V9 can rename the following registers:
Instructions accessing other registers need to be synchronized and cannot run out of order. See section 4.5 for more information.
Simics MAI for x86 can rename the following registers:
Instructions accessing other registers need to be synchronized and cannot run out of order. See section 4.5 for more information.
Note that the list does not include the x87 FPU that uses a stack model to represent floating-point registers. All x87 FPU instructions are currently synchronized.
0xfefc cmp %i3,%i4 0xff00 beq 0xff0c 0xff04 nop 0xff08 add %g2,%g3,%g4 0xff0c ... |
Figure 2. A control dependence |
Figure 2 is an example of control dependence: a conditional branch instruction before an add instruction. The add cannot be executed unless the branch target is known. Control dependences can be avoided by speculating on the execution path. In Simics MAI control dependences are handled by speculating on the Program Counter register (PC or IP depending on the architecture). Instructions that have been fetched with a speculative PC are marked as "speculative". The speculative status will be removed as soon as the control path is known. If a speculative instruction was incorrectly executed, it has to be squashed before the execution can continue.
Memory data dependences are handled by an internal load-store queue (LSQ) and an optional consistency controller. The LSQ handles self-consistency (i.e. ensures that program order consistency is fulfilled) and the consistency controller handles memory consistency for multiprocessor systems.
When a store is executed, the transaction is placed in a store queue without being issued to memory. When the store instruction becomes non-speculative, the store operation can be retired and sent to memory. Speculative loads are matched against the LSQ before being sent to memory to ensure that they load the current (and possibly speculative) value of the memory area they access.
The LSQ will also make sure that stores are never committed out of order if they conflict and that loads cannot execute if there is a risk of conflict with a non-executed previous store.
The size of the LSQ is unlimited. It is up to the user module to place restrictions on the number of outstanding stores.
The consistency controller is described in section 5.3.