304 lines
12 KiB
Markdown
304 lines
12 KiB
Markdown
<p>
|
|
This document discusses how to implement your own instructions.
|
|
</p>
|
|
|
|
|
|
<p> </p>
|
|
<h2>1. Build the method to be attached to the new instruction</h2>
|
|
|
|
<p>
|
|
For this first step, you will be editing the virtual CPU definition in
|
|
<kbd>cHardwareCPU.h</kbd> and <kbd>cHardwareCPU.cc</kbd>, both of which are
|
|
found in the directory <kbd>source/cpu/</kbd>. Start by going to the
|
|
final section of the class definition in the header file and writing
|
|
the declaration for the new method that will be called whenever the
|
|
instruction is executed. For example, if you were going to add the
|
|
instruction <code>minus-17</code> (which performs the oh-so-useful behavior
|
|
of subtracting 17 from the ?BX? register), you would add the line:
|
|
</p>
|
|
<pre>
|
|
bool <span class="method">Inst_Minus17</span>(<span class="class">cAvidaContext</span>& <span class="object">ctx</span>);
|
|
</pre>
|
|
|
|
<p>
|
|
If possible, place it near other instructions of the same type. There are
|
|
about a hundred methods cHardwareCPU. This instruction would likely fit best
|
|
with the group of instruction described as "Single-Argument Math".
|
|
That is, all those instructions that perform mathematical operation that only
|
|
affect a single register.
|
|
</p>
|
|
<p>
|
|
All methods associated with instructions return a
|
|
<span class="class">bool</span> value that determines if it was
|
|
successfully executed. Most instructions will always return true since they
|
|
have no way to fail. The convention that we use to designate a method
|
|
explicitly associated with an instruction is placing a prefix of
|
|
<code>Inst_</code> in front of it.
|
|
</p>
|
|
<p>
|
|
Next, you have to write the function body in the code file
|
|
(<kbd>cHardwareCPU.cc</kbd>). The method bodies will be listed at the end of
|
|
this file in the same order that they were declared in the header. You would
|
|
find the proper position, and write something to the effect of:
|
|
</p>
|
|
|
|
<pre>
|
|
bool <span class="class">cHardwareCPU</span>::<span class="method">Inst_Minus17</span>(<span class="class">cAvidaContext</span>& <span class="object">ctx</span>)
|
|
{
|
|
const <span class="class">int</span> <span class="object">reg_used</span> = <span class="method">FindModifiedRegister</span>(REG_BX);
|
|
<span class="method">GetRegister</span>(<span class="object">reg_used</span>) -= 17;
|
|
return true;
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
The first line of this method uses a helper function called
|
|
<span class="method">FindModifiedRegister</span>() to identify the register
|
|
that should be affected (it scans the next instruction to test if it is a
|
|
<code>nop</code>), with a default value of <code>REG_BX</code> passed in.
|
|
The second line then subtracts 17 from the value in that register. The
|
|
constant values and available helper functions will be described in more
|
|
detail below, as will a guide to accessing the components in the virtual
|
|
CPU. For the moment, you have finished implementing the method!
|
|
</p>
|
|
<p>
|
|
Note that this would be a good time to recompile if you want to test how
|
|
well your implementation is going so far.
|
|
</p>
|
|
|
|
|
|
<p> </p>
|
|
<h2>2. Link the instruction name to its method</h2>
|
|
|
|
For this step, you will need to edit the code file. You would go into the method
|
|
<span class="class">cHardwareCPU</span>::<span class="method">initInstLib</span>(void)
|
|
and add in the line
|
|
|
|
<pre>
|
|
<span class="class">cInstEntryCPU</span>("minus-17", &<span class="class">cHardwareCPU</span>::<span class="method">Inst_Minus17</span>);
|
|
</pre>
|
|
|
|
<p>
|
|
in the same order that it was defined in the class definition.
|
|
</p>
|
|
<p>
|
|
Since we want to use a pointer to the appropriate method, that is what we
|
|
must pass into the dictionary. To obtain said pointer, we must list the class
|
|
the function is part of (<span class="class">cHardwareCPU</span>) follow it
|
|
by a double colon (::) and then give the method name
|
|
(<span class="method">Inst_Minus17</span>) <em>without</em> the normal
|
|
parentheses following it. The parentheses indicate that we should execute
|
|
the method. Without them, it is just the data that represents the method,
|
|
and by preceding this whole mess with an ampersand ('&') we get the pointer
|
|
to the location in memory that the method resides.
|
|
</p>
|
|
<p>
|
|
<b>IMPORTANT:</b> If your instruction interacts with the population, resources,
|
|
or IO, make sure to flag the instruction for speculative stall by adding a third
|
|
argument, <i>nInstFlags::STALL</i>. For an example, look at the 'h-divide'
|
|
instruction.
|
|
</p>
|
|
<p>
|
|
Compile again, and you should have your instruction ready for use.
|
|
</p>
|
|
|
|
|
|
<p> </p>
|
|
<h2>3. Add the entry to your instruction set and test it!</h2>
|
|
|
|
<p>
|
|
This last part should be the easiest. If you want the new instruction you
|
|
just created to be loaded on startup, you must add a line in the instruction
|
|
set you are using (specified in the configuration file) to indicate its
|
|
inclusion:
|
|
</p>
|
|
<pre>
|
|
minus-17 1
|
|
</pre>
|
|
|
|
<p>
|
|
And there you have it! Now the real trick is to test if its working
|
|
properly. I'd recommend using as a framework the creature
|
|
<kbd>default-classic.org</kbd> and modifying some of the long series of
|
|
<code>nop-C</code> instructions inside of it to perform some math using the
|
|
new instruction (only the very first <code>nop-C</code> cannot be changed). You
|
|
can then either go into zoom mode in the viewer and step through the creature,
|
|
or else use analyze mode trace its execution. If you are going to use zoom
|
|
mode, setup your modified creature as the START_CREATURE in configuration file.
|
|
If you want to use analyze mode, put the following lines into the
|
|
<code>analyze.cfg</code> file in your work/ directory:
|
|
|
|
<pre>
|
|
LOAD_ORGANISM inst_test.org
|
|
TRACE
|
|
</pre>
|
|
|
|
<p>
|
|
Where you have to replace <kbd>inst_test.org</kbd> with the name of the
|
|
organism you want to trace. The new file will appear in the
|
|
<kbd>data/archive/</kbd> directory, with the same name as the one you loaded
|
|
in, but a <kbd>.trace</kbd> appended to the end.
|
|
</p>
|
|
|
|
|
|
<p> </p>
|
|
<h3>CPU Components</h3>
|
|
|
|
<p>
|
|
Various CPU components are often manipulated by instructions, and we
|
|
need a standard way of doing this. We have settled on each component being
|
|
associated with a method to access it, to provide a single location that can
|
|
control that access. This has already been useful -- in a multi-threaded
|
|
CPU (i.e., a CPU that has multiple positions in its genome being executed at
|
|
the same time) each thread has its own registers and heads, so we need to
|
|
always be sure we are manipulating the component of the active thread. If
|
|
you simply use the following methods, they will always find the correct
|
|
component for you.
|
|
</p>
|
|
|
|
<dl>
|
|
<dt>
|
|
<pre>
|
|
void <span class="method">StackPush</span>(<span class="class">int</span> <span class="object">value</span>);
|
|
<span class="class">int</span> <span class="method">StackPop</span>();
|
|
void <span class="method">SwitchStack</span>();
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
There are two stacks in a normal CPU, and more in a multi-threaded version
|
|
(one global stack, and one local to each thread). The first stack method will
|
|
place a new value on the top of the currently active stack, the second will
|
|
remove the top value, and the last will toggle the currently active stack.
|
|
</dd>
|
|
<dt>
|
|
<pre>
|
|
<span class="class">cCPUHead</span>& <span class="method">GetHead</span>(int <span class="object">head_id</span>);
|
|
<span class="class">cCPUHead</span>& <span class="method">IP</span>();</pre>
|
|
</dt>
|
|
<dd>
|
|
Each thread in a CPU has four heads associated with it, designated by the
|
|
constants <code>HEAD_IP</code>, <code>HEAD_READ</code>,
|
|
<code>HEAD_WRITE</code>, and <code>HEAD_FLOW</code>. These heads each point
|
|
to a position in memory, and all have their own purpose. A head can be
|
|
accessed by passing the appropriate constant into the GetHead() method. The
|
|
extra method IP() was added to more easily obtain just the instruction pointer.
|
|
The IP is a very special head since it designates what instruction is going to
|
|
be executed next, and often it will make code clearer if you obtain it by
|
|
calling IP(). (It will show that you need to make sure of the special
|
|
qualities of the instruction pointer.)
|
|
</dd>
|
|
<dt>
|
|
<pre>
|
|
int& <span class="method">Register</span>(int <span class="object">reg_id</span>);
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
There are three registers available, associated with the constants
|
|
<code>REG_AX</code>, <code>REG_BX</code>, and <code>REG_CX</code>. If the
|
|
Register() method is called, an integer reference will be returned associated
|
|
with that register. Any change to this integer will make a corresponding
|
|
change to the register in question.
|
|
</dd>
|
|
<dt>
|
|
<pre>
|
|
<span class="class">cCPUMemory</span>& <span class="method">GetMemory</span>();
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
This method allows the programmer to access the full memory of the CPU. As
|
|
you know, the class cCPUMemory is built on top of Genome, so you can
|
|
manipulate it in all of the same ways.
|
|
</dd>
|
|
</dl>
|
|
|
|
<p>
|
|
These are only a sampling of the available methods of interacting with the
|
|
components of the CPU, but they give you a good cross-section without
|
|
overwhelming you with all of the possibilities. You should look through the
|
|
source files if you want to see the other options that are available to you.
|
|
</p>
|
|
|
|
|
|
<p> </p>
|
|
<h2>Helper Methods</h2>
|
|
|
|
<p>
|
|
There are several very common tasks that are performed during the execution
|
|
of many of the instructions. For each of these tasks we have created a
|
|
helper function to ease the creation of new instructions.
|
|
</p>
|
|
|
|
<dl>
|
|
<dt>
|
|
<pre>
|
|
void <span class="method">ReadLabel</span>();
|
|
<span class="class">cCodeLabel</span>& <span class="method">GetLabel</span>();
|
|
<span class="class">cCPUHead</span> <span class="method">FindLabel</span>(int <span class="object">direction</span>);
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
ReadLabel() will read in the label (series of nop instructions) that
|
|
immediately follows the instruction being executed. The label that was read
|
|
can then be accessed (and even modified) using GetLabel(). Finally, the
|
|
Findlabel() method takes single int argument that determines the direction
|
|
(from the instruction pointer) in which the label should be search for. If
|
|
this argument is a 1 it will search forward, and if its a -1, it will search
|
|
backwards. A zero indicates that the search should start from the beginning
|
|
of the genome, and proceed to the end. Once it finds the matching label, it
|
|
will return a head at the position in which the label was found. These
|
|
helper methods are particularly useful in any instruction that has to affect
|
|
other portions of the source code. See the method Inst_HeadSearch for an
|
|
example of how these are used.
|
|
</dd>
|
|
<dt>
|
|
<pre>
|
|
int <span class="method">FindModifiedRegister</span>(int <span class="object">default_register</span>);
|
|
int <span class="method">FindModifiedHead</span>(int <span class="object">default_head</span>);
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
These two methods will look ahead and determine if a nop instruction is
|
|
immediately following the instruction being executed. If so, it will return
|
|
the register or head ID associated with that nop (for use in the rest of the
|
|
method), and if no nop is found, it will automatically return the
|
|
default value passed in. We used FindModifiedRegister in the example new
|
|
instruction above.
|
|
</dd>
|
|
<dt>
|
|
<pre>
|
|
int <span class="method">FindComplementRegister</span>(int <span class="object">base_reg</span>);
|
|
</pre>
|
|
</dt>
|
|
<dd>
|
|
Several instructions are defined as affecting a certain, modifiable register
|
|
and its complement. In order to have a standard way of determining the
|
|
complement of a register (which, by default, cycle in the same order as
|
|
complement labels), we use this function whenever we need to determine one.
|
|
See, for example, see the definition of Inst_IfNEqu().
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
<p> </p>
|
|
<h2>Problem</h2>
|
|
|
|
<p>
|
|
To test your understanding of adding instruction into Avida, try writing two
|
|
new instructions. The first one is the mathematical instruction
|
|
<strong><code>cube</code></strong> that will take the ?BX? register, and put
|
|
its value to the third power. If you look in the actual source files, you
|
|
will see that there is already a <code>square</code> instruction that you can
|
|
model this on.
|
|
</p>
|
|
<p>
|
|
Next, you will implement the instruction <strong><code>if-twice</code></strong>
|
|
that will execute the next instruction if-and-only-if the value in the ?BX?
|
|
register is twice that of the value in its complement. In other words by
|
|
default, if would test of BX was twice CX, but if it is followed by a
|
|
<code>nop-C</code> it will test if CX is twice AX.
|
|
</p>
|
|
<p>
|
|
For both of these instruction make sure to craft an organism to test that
|
|
they are working properly!
|
|
</p>
|