instruction_error_t SIM_instruction_proceed(instruction_id_t ii);
instruction_error_t SIM_instruction_fetch(instruction_id_t ii);
instruction_error_t SIM_instruction_decode(instruction_id_t ii);
instruction_error_t SIM_instruction_execute(instruction_id_t ii);
instruction_error_t SIM_instruction_retire(instruction_id_t ii);
instruction_error_t SIM_instruction_commit(instruction_id_t ii);
The defined phases are the following:
typedef enum instruction_phase { Sim_Phase_Initiated, Sim_Phase_Fetched, Sim_Phase_Decoded, Sim_Phase_Executed, Sim_Phase_Retired, Sim_Phase_Committed, Sim_Phases } instruction_phase_t;
For convenience there are some predefined functions that can be used to proceed to the phases above.
SIM_instruction_fetch(id) will proceed to Sim_Phase_Fetch.
SIM_instruction_decode(id) will proceed to Sim_Phase_Decoded.
SIM_instruction_execute(id) will proceed to Sim_Phase_Executed.
SIM_instruction_retire(id) will proceed to Sim_Phase_Retired.
SIM_instruction_commit(id) will proceed to Sim_Phase_Committed.
Fetching an instruction means that the memory used by the instruction is loaded. This may stall the CPU and SIM_instruction_proceed will signal this by returning Sim_IE_Stalling. The instruction can then be proceeded to the next phase as soon as the stalling period is over (see SIM_instruction_remaining_stall_time).
To fetch an instruction a valid program counter is needed. The value of the program counter is read from the register bank for the first instruction in the tree and for instructions not inserted in the tree. For instructions that have an executed parent the program counter will have the value produced by the parent. SIM_instruction_write_input_reg can also be used to explicitly set the program counter. This is the only way to fetch instructions whose parent has not yet executed and thus not produced a new program counter. This will also mark the instruction as speculative. As soon as the parent instruction is executed the child will become non-speculative again if the produced value matches the one set (if the parent was non-speculative). For miss-matches we will get a speculative instructions that needs to be squashed.
All the above also apply to the next program counter if the architecture has delay slots.
When an instruction is fetched SIM_instruction_opcode can be used to retrieve the opcode.
Decoding means interpreting the fetched data and translate it to a determined instruction. It is then possible to use SIM_instruction_type to determine the type of the instruction and SIM_instruction_get_reg_info to find the registers used by the instruction.
Executing an instruction means that the actual operation is performed. Thus input values are used to produce output values. The input values used are collected from previously executed instructions (or the register bank) and the output values will be available for later instructions. Simics has no restrictions on the number of temporal values that can exists between instruction. This can be viewed as an unlimited resource of internal registers for register renaming.
To be able to execute the instruction all the input values must have been produced, i.e. all dependences must be fulfilled. This is done either by executing all instructions that the instruction depends on or explicitly set the value of an input register by using SIM_instruction_write_input_reg. As with the program counter above the latter case will also make the instruction speculative until an earlier instruction produces the same value. This is how value speculation can be handled.
Sim_IE_Unresolved_Dependences will be returned if an instruction is not ready for execution.
Instructions that access memory may stall and Sim_EI_Stalling will be returned. As with instruction fetches the instruction can be proceeded again as soon as the stalling period is over.
Retiring an instruction sends all speculative stores to memory. The instruction must be non-speculative to enter this phase. The instruction may stall since the stores are sent to the memory hierarchy. The instruction may also get an exception (like a memory parity error). Retiring an instruction can be done out-of-order.
When committing an instruction the output values produced by the instruction are copied to the register bank. The instruction is automatically removed from the instruction tree, but it must be deallocated explicitly by calling SIM_instruction_end. Instructions marked as speculative cannot be committed. This can be forced by the user by calling SIM_instruction_force_correct to remove the speculative status before committing. This is strongly discouraged since it may lead to incorrect execution. Also, the instruction may only have one valid execution path left, all alternative branches have to be squashed before the instruction can be committed.
Certain return values needs special actions to be taken. If some of the functions returns Sim_IE_Exception an exception occurred and the execution of the instruction is aborted. The exception should be handled by calling SIM_instruction_handle_exception on the faulting instruction. This call will set the program counter to the first instruction in the corresponding exception handler.
If Sim_IE_Speculative is returned it means a speculative instruction tried to commit.
If Sim_IE_Sync_Instruction is returned it means that a synchronizing instruction was executed in a speculative state. Synchronizing instructions have to be executed in non-speculative state since they cannot be squashed.