Each operand in a Corewar instruction has an addressing mode. The
addressing mode controls how the Source
and Destination
instructions are
determined.
When an instruction is executed, the addressing modes for the A
and B
operands of the instruction are evaluated to determine the source and
destination instruction for the current opcode. Additionally, some
addressing modes modify the operand number by incrementing or decrementing it
during this evaluation.
The following addressing modes can be used in Corewar
Operands with the immediate (#
) addressing mode are always evaluated as an
address of 0. This allows data to be stored in the operand without affecting
the address the operand references.
For example, the follow example works just like the classic imp
despite
having a non-zero A
operand. This can also make the imp more resilient as it
will continue to function perfectly even if the A
number is modified.
mov.i #123, $1
The direct ($
) addressing mode provides a relative address from the executing
instruction to another instruction in the core.
This is used in the classic imp
.
mov.i $0, $1
The A
operand has a direct address of 0 and the B
operand has a direct
address of 1. This corresponds to the current and next instructions
respectively.
The direct addressing mode is the default addressing mode.
The A Indirect (*
) addressing mode uses the executing instruction’s operand
as a pointer to an intermediate instruction. This second instruction’s A
field is then used as a direct reference to the instruction of interest.
Note the intermediate instruction’s address is resolved relative to this intermediate instruction, not the executing instruction.
Let’s look at an example.
mov.i *1, $2
dat 2, 0 ; <- 2 is used as a pointer
dat 0, 0 ; <- this instruction will be overwritten
jmp 0 ; <- with this instruction
The mov
instruction is about to be executed. The B
operand is using the
Direct addressing mode and is referring to the third instruction
(dat 0, 0
).
The A
operand is using the A Indirect addressing mode. The A
number is 1
,
which indicates that the A
operand of the second instruction (dat 2, 0
)
should be used as a pointer to the source
instruction.
The A
number of the second instruction is 2
, therefore the source
instruction is found by moving 2 addresses forward from the second instruction.
This means that the fourth instruction (jmp 0
) will be used as the source
for this move instruction.
The B Indirect (@
) addressing mode works in the same way as the A
Indirect (*
) addressing mode described above except that it
uses the intermediate instruction’s B
field as a pointer rather than its A
field.
The @
addressing mode is used by the classic warrior dwarf
to set the
location where its bombs will fall:
add #4, 3
mov 2, @2
jmp -2
dat #0, #0
The dat
instruction is used both as a bomb and also as a pointer to the
target address. The dwarf warrior runs in an infinite loop. Each iteration of
the loop, it adds 4
(the step size) to the dat
instructions B
number.
After this it executes mov 2, @2
to copy the dat
bomb to the address
pointed to by the dat
bomb’s B
number.
The A Pre-decrement Indirect ({
) addressing mode works in the same way as the
A Indirect addressing mode detailed above with the addition that it
first decrements the A
number before using it as a pointer.
mov.i {1, $1
dat $0, $0
The above example will first decrement the A
number of the dat
instruction
before using the dat
instruction’s A
number as a pointer.
mov.i {1, $1
dat $-1, $0
After decrementing, the A
number of the dat
instruction will be -1
and
therefore refer to the mov
instruction, which will be used as the source
instruction.
The A Post-increment Indirect (}
) addressing mode works in the same way as
the A Indirect addressing mode detailed above with the addition that it
increments the A
number after using it as a pointer.
mov.i }1, $1
dat $0, $0
The above example will first use the A
number of the dat
instruction as a
pointer. As the dat
instruction’s A
number is 0
, the dat
instruction is
pointing to itself and so the dat
instruction will be used as the source
instruction for the move operation.
After this has happened, the dat
instruction’s A
number will be incremented
to 1
.
mov.i }1, $1
dat $1, $0
Finally the move operation will be applied using the copy of the dat
instruction from the Source Register
:
mov.i }1, $1
dat $0, $0
Note, perhaps counter-intuitively, the final resulting core looks exactly the same as the starting core. The change made by the post-increment was overwritten by the move operation.
The B Pre-decrement Indirect (<
) addressing mode works in the same way as the
A Pre-decrement Indirect addressing mode detailed
above except it decrements and uses the intermediate instruction’s B
number
as a pointer, rather than its A
number.
The B Post-increment Indirect (>
) addressing mode works in the same way as
the A Post-increment Indirect addressing mode
detailed above except it increments and uses the intermediate instruction’s B
number as a pointer, rather than its A
number.