Opcodes

Opcodes are used to specify what operation should be performed when the instruction is executed.

Different opcodes have different default modifiers and some opcodes require only a single operand. See Parser for details on how defaults are introduced into parsed instructions.

The following opcodes can be used in Corewar

Dat - Data

If one of a warrior's processes executes a dat instruction it is removed from the process queue i.e. terminated. This is the main way that warriors are killed within the game of Corewar.

Note that termination of the warrior's process happens after the operand addressing modes are evaluated. See execution for details.

For example if a warrior were to execute the first instruction of the following code block

DAT.F 1, <1 ; <--this instruction is executed
DAT.F 1, 1

The second instruction's B operand would still be decremented, giving:

DAT.F 1, <1 
DAT.F 1, 0 ; <--this instruction was modified

The default modifier for the dat opcode is .f. Only one operand needs to be specified for the dat instruction to be successfully parsed. If this is the case, the A operand is defaulted to 0.

For example dat 7 will be parsed as DAT.F $0, $7

Mov - Move

The mov instruction copies data from the address referenced by the A operand to the address referenced by the B operand.

Which data is copied is determined by the instruction's modifier.

The default modifier for the mov opcode is .i.

Add - Add

The add instruction adds the number(s) from the address referenced by the A operand to the number(s) at the address referenced by the B operand.

As with all operations in Corewar, the add operation uses mod maths, therefore the result of addition will be (A + B) % CORESIZE.

Which data is added is determined by the instruction's modifier.

The .i modifier has the same effect as the .f modifier.

The default modifier for the add opcode is .ab.

Sub - Subtract

The sub instruction subtracts the number(s) from the address referenced by the A operand from the number(s) at the address referenced by the B operand.

As with all operations in Corewar, the subtract operation uses mod maths, therefore the result of subtraction will be (A - B) % CORESIZE.

Which data is subtracted is determined by the instruction's modifier.

The .i modifier has the same effect as the .f modifier.

The default modifier for the sub opcode is .ab.

Mul - Multiply

The mul instruction multiplies the number(s) from the address referenced by the A operand by the number(s) at the address referenced by the B operand.

As with all operations in Corewar, the multiply operation uses mod maths, therefore the result of multiplication will be (A * B) % CORESIZE.

Which data is multiplied is determined by the instruction's modifier.

The .i modifier has the same effect as the .f modifier.

The default modifier for the mul opcode is .ab.

Div - Divide

The div instruction divides the number(s) from the address referenced by the B operand by the number(s) at the address referenced by the A operand. The quotient of this division is always rounded down.

As with all operations in Corewar, the divide operation uses mod maths, therefore the result of division will be floor(A / B) % CORESIZE.

Which data is divided is determined by the instruction's modifier.

The .i modifier has the same effect as the .f modifier.

The default modifier for the div opcode is .ab.

Dividing by zero is considered an illegal instruction in Corewar. The executing warrior's process is removed from the process queue (terminated).

Note that termination of the warrior's process happens after the operand addressing modes are evaluated. See execution for details.

Mod - Modulo

The mod instruction divides the number(s) from the address referenced by the B operand by the number(s) at the address referenced by the A operand. The remainder from this division is stored at the destination.

As with all operations in Corewar, the modulo operation uses mod maths, therefore the result of modulo will be (A % B) % CORESIZE.

Which data is divided is determined by the instruction's modifier.

The .i modifier has the same effect as the .f modifier.

The default modifier for the mod opcode is .ab.

Dividing by zero is considered an illegal instruction in Corewar. The executing warrior's process is removed from the process queue (terminated).

Note that termination of the warrior's process happens after the operand addressing modes are evaluated. See execution for details.

Jmp - Jump

The jmp instruction changes the address of the next instruction which will be executed by the currently executing process. The most common usages of this opcode are to create a loop or to skip over a section of code.

The jmp instruction will jump execution to the address given by the instruction's A operand. The B operand has no purpose within the jmp instruction. However the B operand will still be evaluated, see addressing_modes.

Modifiers have no effect on the jmp instruction, the A operand is always used as the jump address.

The default modifier for the jmp opcode is .b. Only one operand needs to be specified for the jmp instruction to be successfully parsed. If this is the case, the B operand is defaulted to 0.

For example jmp 5 will be parsed as JMP.B $5, $0.

Jmz - Jump if Zero

The jmz instruction works in the same way as the jmp instruction detailed above with the exception that the jump is only performed if the number(s) at the address referenced by the B operand is zero. This allows the jmz instruction to function like an if statement in a higher level language.

The instruction's modifier controls which operands are compared with zero at the destination address according to the following table:

Modifier Destination
.a A operand
.b B operand
.ab B operand
.ba A operand
.f A and B operands
.x A and B operands
.i A and B operands

We can see from this that .a and .ba are equivalent, as are .b and .ab. We can also see that .f, .x and .i are equivalent.

Note that when comparing both A and B operands with zero, the jump will not be taken if either operand is non-zero.

dat 0, 1 ; <- won't jump if compared with jmz.f
dat 1, 0 ; <- won't jump if compared with jmz.f
dat 1, 1 ; <- won't jump if compared with jmz.f
dat 0, 0 ; <- will jump if compared with jmz.f

The default modifier for the jmz opcode is .b.

Jmn - Jump if not Zero

The jmn instruction works in the same way as the jmz instruction detailed above with the exception that the jump is performed if the referenced number(s) are not zero.

Note that when comparing both A and B operands with zero, the jump will not be taken if either operand is zero.

dat 0, 1 ; <- won't jump if compared with jmn.f
dat 1, 0 ; <- won't jump if compared with jmn.f
dat 1, 1 ; <- will jump if compared with jmn.f
dat 0, 0 ; <- won't jump if compared with jmn.f

The default modifier for the jmn opcode is .b.

Djn - Decrement and Jump if not Zero

The djn instruction works in a similar way to the jmn instruction detailed above with one addition. Before comparing the destination instruction against zero, the number(s) at the destination instruction are decremented. One common use of this opcode is to create the equivalent of a simple for loop in higher level languages.

Unlike the jmn intruction, the djn instruction will perform the jump if either operand is zero when using the .f, .x and .i modifiers.

dat 0, 1 ; <- will jump if compared with djn.f
dat 1, 0 ; <- will jump if compared with djn.f
dat 1, 1 ; <- will jump if compared with djn.f
dat 0, 0 ; <- won't jump if compared with jmn.f

Decrement happens after the addressing modes are evaluated and before the comparison against zero is made.

The default modifier for the djn opcode is .b.

Seq - Skip if Equal

The cmp opcode is an alias for seq used to support legacy corewar standards. cmp and seq work in exactly the same way within Corewar.

The seq instruction compares the number(s) at the addresses specified by its source and destination operands and if they are equal, increments the next address to be executed by the current process by one - in effect skipping the next instruction. Skip instructions are commonly used to develop scanners which scan the core looking for other warriors.

The instruction's modifier determines what at the two addresses is compared for equality. Importantly, using a modifier of .i will compare the entire source and destination instructions. This means even if the instructions differ only by opcode, modifier or addressing mode, the next instruction will not be skipped.

The default modifier for the 'seq' opcode is .i.

Sne - Skip if not Equal

The sne instruction works in the same way as the seq instruction detailed above with the exception that the next instruction is skipped if the source and destination instructions are not equal.

The default modifier for the 'sne' opcode is .i.

Slt - Skip if Less Than

The slt instruction compares the number(s) at the addresses specified by its source and destination operands. If the source number(s) are less than than the destination number(s), the next address to be executed by the current process is incremented by one - in effect skipping the next instruction.

The instruction's modifier controls which operands are compared at the source and destination addresses according to the following table:

Modifier Source Destination
.a A operand A operand
.b B operand B operand
.ab A operand B operand
.ba B operand A operand
.f A and B operands A and B operands
.x A and B operands B and A operands
.i A and B operands A and B operands

We can see from this that the .f and .i modifiers are equivalent.

If comparing both A and B operands (using .f, .x or .i), the instruction will not be skipped if either source number is greater than or equal to its corresponding destination number.

The default modifier for the 'slt' opcode is .b.

Spl - Split

The spl instruction spawns a new process for the current warrior at the address specified by the A operand.

The newly created process is added to the process queue after the currently executing process.

Consider the following example:

a: spl c
b: jmp 0
c: jmp 0

The first instruction is executed, creating a second process at c. The next instruction to execute will be b (executed by the original process). Finally the new process will execute at c.

Modifiers have no effect on the spl instruction, the A operand is always used as the split address.

The default modifier for the spl opcode is .b. Only one operand needs to be specified for the spl instruction to be successfully parsed. If this is the case, the B operand is defaulted to 0.

For example spl 3 will be parsed as SPL.B $3, $0.

Nop - No Operation

The nop instruction does not perform any operation. The instruction takes a single cycle to execute as normal, and addressing modes are evaluated as normal. One potential use of the nop instruction is to introduce a delay in execution when working on a multi-process warrior.

Modifiers have no effect on the nop instruction.

The default modifier for the nop opcode is .f. Only one operand needs to be specified for the nop instruction to be successfully parsed. If this is the case, the B operand is defaulted to 0.

For example nop 8 will be parsed as NOP.F $8, $0.