The virtual computer implemented in avida consists of a central processing unit (CPU) and an instruction set. These components define the low-level behavior of each program; the CPU and the instruction set together form the hardware of a Turing machine.
When a genome is loaded into the memory (as the software) of a CPU, the initial state of the Turing machine is set. The hardware, combined with the interaction with other CPUs, then governs the set of transitions between CPU states.
The CPU contains the following set of variables, as shown in Fig. 1.1:
|
The instruction set in avida is loaded on startup from a configuration file (inst_set.24.base by default). This allows selection of different instruction sets without recompilation, as well as allowing different numbers of instructions to be specified. However, it is not possible to alter the behavior of individual instructions or add new instructions without recompiling avida; this has to be done directly in the source code.
All of the available instructions are listed in the inst_set.* files with a 1 or a 0 next to an instruction to indicate if it should or should not be included. Changing the instruction set to be used simply involves adjusting these flags.
The instructions were created with three things in mind:
One major concept which differentiates this assembly language from its real-world counterparts is in the additional uses of nops (no-operation commands). These have no effect on the CPU when executed, but may modify the behavior of any instruction which precedes them. This occurs in two ways; most of the time it will change the register affected by a command. For example, an inc command followed by the instruction nop-A would cause the contents of the AX register to be incremented, while an inc command followed by a nop-B would increment BX.
Below, whenever a register name is surrounded by ?'s in an instruction description, it is the default register to be used. If a nop follows the command, the register it represents will replace this default.
The second way nops can be used is as labels (reference points) for a search or a jump as in tierra. If nop-A follows a jump-forward command, it scans forward for the first complementary label (nop-B) and moves the instruction pointer there. Labels may be composed of more than a single nop instruction.
The label system used in avida allows for an arbitrary number of different nops. By default, we have three nop instructions, nop-A's complement is nop-B, nop-B's is nop-C, and nop-C's is nop-A.
A description of all of the instructions implemented in avida follows below. Those commands in red are part of the default instruction set.
There are three nops in the default instruction set, and a fourth which is a ``pure'' no-operation, as follows:
All of these affect the ?BX? register.
What follows is one of the simpler ancestor organisms distributed with avida; it is contained in the file creature.small in the work/genebank/ directory. It is a simple self-replicator, and very short compared to other ancestors included in this distribution. Due to its efficiency in self-replication, this creature is not well suited as an ancestor for adaptation experiments. Note that when an instruction pointer runs off of the end of the program, it will automatically loop back to its beginning, in order to ensure that the chemistry of the program never halts.
This simple program contains two label pairs (P and Q), one for the purpose of calculating the length, and the other for the implementation of a copy loop. The search-f followed by label P searches forward in the genome for its complement, and returns its distance (from the end of the first label to the end of the second) into the BX register, and the size of the label into CX. The program then adds CX to the BX register, to account for the length of the label itself, and finally increments BX to account for the single instruction before the first label. The creature now has its own size in BX. When the instruction on line five (allocate) is called, the program is doubled in length and the absolute address of the new chunk of memory is put in AX. Now, AX contains the offset of the newly allocated section, and BX contains the length of the cell (which, if a creature is copying itself properly, will always be the same). Lines 6 through 11 move the size of the creature (via the stack) into the CX register, and clear out BX.
| 00 | search-f | find distance to the end label |
| 01 | nop-A | label P |
| 02 | nop-A | |
| 03 | add | account for the end label's size |
| 04 | inc | account for the initial search-f |
| 05 | allocate | allocate space for daughter. |
| 06 | push | move size from BX onto the stack. |
| 07 | nop-B | |
| 08 | pop | move size off of the stack into CX |
| 09 | nop-C | |
| 10 | pop | since the stack is empty, pop 0 into BX |
| 11 | nop-B | label Q' (Copy Loop start) |
| 12 | nop-C | |
| 13 | copy | copy the current line... |
| 14 | inc | move onto the next line. |
| 15 | if-n-equ | if we aren't done copying... |
| 16 | jump-b | ...jump back to the loop's beginning. |
| 17 | nop-A | label Q |
| 18 | nop-B | |
| 19 | divide | done copying; separate the daughter! |
| 20 | nop-B | label P' |
| 21 | nop-B |
The copy loop follows. It starts by copying from line BX and uses
BX + AX as the destination. Initially, BX is 0 and AX is
the size (22). This means the first time through the copy loop, line 0 is
copied to line 22 (the first line in the newly allocated memory). Then line
14 is executed and BX is incremented. Finally, the if-n-equ
tests to see if whether BX and CX are different, and jumps
back to the beginning of the
loop if this is the case. The loop will continue (copying a new line each
time) until BX equals CX and hence all the lines have
been copied. Finally, the divide instruction is reached.
The divide instruction divides the cell at the offset specified in the AX register, creating a parent and daughter cell. The daughter is placed in a neighboring cell (the exact mechanism of which is described in the Reproduction section). At the end of the program, the instruction pointer is looped back to the beginning.
Here is a trace of the execution of the program, with the values of the registers and stack at each moment in time.
| line | instruction | AX | BX | CX | stack | comments |
|---|---|---|---|---|---|---|
| 00 | search-f | 0 | 19 | 2 | ||
| 03 | add | 0 | 21 | 2 | ||
| 04 | inc | 0 | 22 | 2 | We have the size! | |
| 05 | allocate | 22 | 22 | 2 | Allocate space | |
| 06 | push | 22 | 22 | 2 | 22 | push BX |
| 08 | pop | 22 | 22 | 22 | pop CX | |
| 10 | pop | 22 | 0 | 22 | pop BX | |
| 12 | nop-C | 22 | 0 | 22 | No-Operation | |
| 13 | copy | 22 | 0 | 22 | Copy line 0... | |
| 14 | inc | 22 | 1 | 22 | ||
| 15 | if-n-equ | 22 | 1 | 22 | ||
| 16 | jump-b | 22 | 1 | 22 | ...to start of loop | |
| 13 | copy | 22 | 1 | 22 | Copy line 1... | |
| 14 | inc | 22 | 2 | 22 | ||
| 15 | if-n-equ | 22 | 2 | 22 | ||
| 16 | jump-b | 22 | 2 | 22 | ...to start of loop | |
| 13 | copy | 22 | 2 | 22 | Copy line 2... | |
| 13 | copy | 22 | 21 | 22 | Copy line 21.. | |
| 14 | inc | 22 | 22 | 22 | ||
| 15 | if-n-equ | 22 | 22 | 22 | ||
| 17 | nop-A | 22 | 22 | 22 | ||
| 18 | nop-B | 22 | 22 | 22 | ||
| 19 | divide | 22 | 22 | 22 | Divided! | |
| 20 | nop-B | 22 | 22 | 22 | ||
| 21 | nop-B | 22 | 22 | 22 | ||
For this program, the gestation time (the number of instructions
required to reproduce) varies between 98 and 100 instructions. The
first time through requires 98 instructions: the portion before the
copy loop consists of 8 executed instructions; the copy loop
contains another 4 instructions that are each executed
22 times each, except for the last time the copy loop is executed,
where the last jump-b is skipped over; and from there it is
another 3 instructions until the divide is issued.
So, 8 + (4×22 - 1) + 3 = 98. However, the second time through, an
additional 2 instructions are executed because of the P label
after the divide instruction, and a gestation time of 100,
rather than 98, is averaged into the genotype record.
NEXT: Mutations
PREV: Reproduction
Page maintained by Charles Ofria
Send all comments to
charles@krl.caltech.edu