Execution

Each cycle, a Corewar instruction is executed following a fetch, decode, execute scheme.

Fetch > Decode > Execute

During execution the simulator makes use of a number of registers to temporaily store data. Misunderstanding this process can lead to a number of gotchas where instructions do not behave as you might naively expect.

The following notional registers are used:

Register Purpose
Instruction Register The executing instruction
Source Register The source instruction
Destination Register The destination instruction

Copies of instructions are written to these registers. Therefore changes made to the original instructions in the Core after they are copied to a register, do not affect the data in the registers themselves. This can be best explained with an example.

Fetch

The first step in execution is fetch. During this step the simulator determines the instruction to be executed by populating the Instruction Register.

First, the current warrior is determined (see warriors for details).

Next the current process is determined for the current warrior (see processes for details).

The instruction pointer for the current process is determined.

The instruction in core at the address pointed to by the instruction pointer is retrieved and stored in the Instruction Register.

Decode

The second step in execution is decode. During this step the simulator determines the source and destination instructions for the executing instruction (fetched in the previous step).

First the A operand of the executing instruction is evaluated. The evaluation of this operand is controlled by the operand's addressing mode.

Evaluation produces an address within the Core. The instruction at this address is retrieved and stored in the Source Register.

Next the B operand of the executing instruction is evaluated, again using the operand's addressing mode.

The evaluated address from the B operand is used to retrieve and store an instruction in the Destination Register.

Execute

The final step in execution is execute.

First the current process's instruction pointer is incremented (so that the process will execute the next instruction in core when it is next executed).

Next the Instruction Register instruction's opcode and modifier are used to determine the operation to perform.

The operation is performed using the instructions in the Source Register and Destination Register as the source and destination respectively for the executing instruction.

Note that some opcodes (such as jmp) will modify the current process's instruction pointer, overwritting the current value.

Finally, the current warrior's active process is moved to the next process in the warrior's process list and the game's active warrior is moved to the next warrior in the game's list of active warriors.

Example

Understanding how instructions are evaluated and executed is vitally important to writing correctly functioning warriors, unfortunately it is also something which can be very difficult for beginners to understand. Here is an example to aid understanding.

The executing instruction is modified during evaluation of addressing modes

Consider the following redcode:

0000: mov.i >0, $0
0001: dat.f $0, $0

The instructions have been prefixed with a number indicating their absolute address in the Core.

When imaging how this first instruction will execute, your reasoning might be:

The B Post-Increment Indirect (>) addressing mode will increase the B number of the instruction from 0 to 1 and then the instruction at address 0 will be copied to address 1.

Naively, you might therefore expect the core to look like this after the first instruction is executed:

0000: mov.i >0, $1
0001: mov.i >0, $1

However, this is incorrect.

During the fetch stage, the instruction mov.i >0, $0 will be copied to the Instruction Register.

Instruction Register Source Register Destination Register
0000: mov.i >0, $0

Next, during the decode stage, the A operand will be evaluated. The addressing mode (>) means that the instruction pointed to by the B number will be used as the address of the source instruction. The B number is 0, therefore, the current instruction is copied to the Source Register.

Instruction Register Source Register Destination Register
0000: mov.i >0, $0 0001: mov.i >0, $0

Following this the post-increment is applied to the B operand so the instruction in core looks like this:

0000: mov.i >0, $1
0001: dat.f $0, $0

However, the instruction in the Source Register is still mov.i >0, $0.

Next the B operand will be evaluated using the direct ($) addressing mode. The B number is 1, which references the second instruction (dat.f $0, $0). Therefore the dat instruction is copied to the Destination Register.

Instruction Register Source Register Destination Register
0000: mov.i >0, $0 0000: mov.i >0, $0 0001: dat.f $0, $0

Now the instruction in the Instruction Register is executed. It copies the instruction in the Source Register to the address stored in the Destination Register.

The resulting core looks like this:

0000: mov.i >0, $1
0001: mov.i >0, $0

So in fact, this instruction will continue to execute safetly, in a similar fashion to the classic imp.