1 /*
2  *  cHardwareGX.cc
3  *  Avida
4  *
5  *  Copyright 1999-2011 Michigan State University. All rights reserved.
6  *
7  *  This file is part of Avida.
8  *
9  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
10  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11  *
12  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
16  *  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "cHardwareGX.h"
21 
22 #include "avida/core/WorldDriver.h"
23 
24 #include "cAvidaContext.h"
25 #include "cCPUTestInfo.h"
26 #include "cEnvironment.h"
27 #include "cHardwareManager.h"
28 #include "cHardwareTracer.h"
29 #include "cInstSet.h"
30 #include "cOrganism.h"
31 #include "cPhenotype.h"
32 #include "cStringUtil.h"
33 #include "cTestCPU.h"
34 #include "cWorld.h"
35 #include "tInstLibEntry.h"
36 
37 #include <climits>
38 #include <fstream>
39 #include <algorithm>
40 
41 using namespace std;
42 using namespace Avida;
43 using namespace AvidaTools;
44 
45 //! A small helper struct to make deleting a little easier.
46 struct delete_functor {
operator ()delete_functor47   template <typename T> void operator()(T *ptr) { delete ptr; }
48 };
49 
50 
51 tInstLib<cHardwareGX::tMethod>* cHardwareGX::s_inst_slib = cHardwareGX::initInstLib();
52 const double cHardwareGX::EXECUTABLE_COPY_PROCESSIVITY = 1.0;
53 const double cHardwareGX::READABLE_COPY_PROCESSIVITY = 1.0;
54 
initInstLib(void)55 tInstLib<cHardwareGX::tMethod>* cHardwareGX::initInstLib(void)
56 {
57   struct cNOPEntryCPU {
58     cString name;
59     int nop_mod;
60     cNOPEntryCPU(const cString &name, int nop_mod)
61       : name(name), nop_mod(nop_mod) {}
62   };
63   static const cNOPEntryCPU s_n_array[] = {
64     cNOPEntryCPU("nop-A", REG_AX),
65     cNOPEntryCPU("nop-B", REG_BX),
66     cNOPEntryCPU("nop-C", REG_CX)
67   };
68 
69   static const tInstLibEntry<tMethod> s_f_array[] = {
70     /*
71      Note: all entries of cNOPEntryCPU s_n_array must have corresponding
72      in the same order in tInstLibEntry<tMethod> s_f_array, and these entries must
73      be the first elements of s_f_array.
74      */
75     tInstLibEntry<tMethod>("nop-A", &cHardwareGX::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
76     tInstLibEntry<tMethod>("nop-B", &cHardwareGX::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
77     tInstLibEntry<tMethod>("nop-C", &cHardwareGX::Inst_Nop, (nInstFlag::DEFAULT | nInstFlag::NOP), "No-operation instruction; modifies other instructions"),
78 
79     tInstLibEntry<tMethod>("nop-X", &cHardwareGX::Inst_Nop, 0, "True no-operation instruction: does nothing"),
80     tInstLibEntry<tMethod>("if-equ-0", &cHardwareGX::Inst_If0, 0, "Execute next instruction if ?BX?==0, else skip it"),
81     tInstLibEntry<tMethod>("if-not-0", &cHardwareGX::Inst_IfNot0, 0, "Execute next instruction if ?BX?!=0, else skip it"),
82     tInstLibEntry<tMethod>("if-n-equ", &cHardwareGX::Inst_IfNEqu, nInstFlag::DEFAULT, "Execute next instruction if ?BX?!=?CX?, else skip it"),
83     tInstLibEntry<tMethod>("if-equ", &cHardwareGX::Inst_IfEqu, 0, "Execute next instruction if ?BX?==?CX?, else skip it"),
84     tInstLibEntry<tMethod>("if-grt-0", &cHardwareGX::Inst_IfGr0),
85     tInstLibEntry<tMethod>("if-grt", &cHardwareGX::Inst_IfGr),
86     tInstLibEntry<tMethod>("if->=-0", &cHardwareGX::Inst_IfGrEqu0),
87     tInstLibEntry<tMethod>("if->=", &cHardwareGX::Inst_IfGrEqu),
88     tInstLibEntry<tMethod>("if-les-0", &cHardwareGX::Inst_IfLess0),
89     tInstLibEntry<tMethod>("if-less", &cHardwareGX::Inst_IfLess, nInstFlag::DEFAULT, "Execute next instruction if ?BX? < ?CX?, else skip it"),
90     tInstLibEntry<tMethod>("if-<=-0", &cHardwareGX::Inst_IfLsEqu0),
91     tInstLibEntry<tMethod>("if-<=", &cHardwareGX::Inst_IfLsEqu),
92     tInstLibEntry<tMethod>("if-A!=B", &cHardwareGX::Inst_IfANotEqB),
93     tInstLibEntry<tMethod>("if-B!=C", &cHardwareGX::Inst_IfBNotEqC),
94     tInstLibEntry<tMethod>("if-A!=C", &cHardwareGX::Inst_IfANotEqC),
95     tInstLibEntry<tMethod>("if-bit-1", &cHardwareGX::Inst_IfBit1),
96 
97     tInstLibEntry<tMethod>("call", &cHardwareGX::Inst_Call),
98     tInstLibEntry<tMethod>("return", &cHardwareGX::Inst_Return),
99 
100     tInstLibEntry<tMethod>("throw", &cHardwareGX::Inst_Throw),
101     tInstLibEntry<tMethod>("throwif=0", &cHardwareGX::Inst_ThrowIf0),
102     tInstLibEntry<tMethod>("throwif!=0", &cHardwareGX::Inst_ThrowIfNot0),
103     tInstLibEntry<tMethod>("catch", &cHardwareGX::Inst_Catch),
104 
105     tInstLibEntry<tMethod>("goto", &cHardwareGX::Inst_Goto),
106     tInstLibEntry<tMethod>("goto-if=0", &cHardwareGX::Inst_GotoIf0),
107     tInstLibEntry<tMethod>("goto-if!=0", &cHardwareGX::Inst_GotoIfNot0),
108     tInstLibEntry<tMethod>("label", &cHardwareGX::Inst_Label),
109 
110     tInstLibEntry<tMethod>("pop", &cHardwareGX::Inst_Pop, nInstFlag::DEFAULT, "Remove top number from stack and place into ?BX?"),
111     tInstLibEntry<tMethod>("push", &cHardwareGX::Inst_Push, nInstFlag::DEFAULT, "Copy number from ?BX? and place it into the stack"),
112     tInstLibEntry<tMethod>("swap-stk", &cHardwareGX::Inst_SwitchStack, nInstFlag::DEFAULT, "Toggle which stack is currently being used"),
113     tInstLibEntry<tMethod>("flip-stk", &cHardwareGX::Inst_FlipStack),
114     tInstLibEntry<tMethod>("swap", &cHardwareGX::Inst_Swap, nInstFlag::DEFAULT, "Swap the contents of ?BX? with ?CX?"),
115     tInstLibEntry<tMethod>("swap-AB", &cHardwareGX::Inst_SwapAB),
116     tInstLibEntry<tMethod>("swap-BC", &cHardwareGX::Inst_SwapBC),
117     tInstLibEntry<tMethod>("swap-AC", &cHardwareGX::Inst_SwapAC),
118     tInstLibEntry<tMethod>("copy-reg", &cHardwareGX::Inst_CopyReg),
119     tInstLibEntry<tMethod>("set_A=B", &cHardwareGX::Inst_CopyRegAB),
120     tInstLibEntry<tMethod>("set_A=C", &cHardwareGX::Inst_CopyRegAC),
121     tInstLibEntry<tMethod>("set_B=A", &cHardwareGX::Inst_CopyRegBA),
122     tInstLibEntry<tMethod>("set_B=C", &cHardwareGX::Inst_CopyRegBC),
123     tInstLibEntry<tMethod>("set_C=A", &cHardwareGX::Inst_CopyRegCA),
124     tInstLibEntry<tMethod>("set_C=B", &cHardwareGX::Inst_CopyRegCB),
125     tInstLibEntry<tMethod>("reset", &cHardwareGX::Inst_Reset),
126 
127     tInstLibEntry<tMethod>("pop-A", &cHardwareGX::Inst_PopA),
128     tInstLibEntry<tMethod>("pop-B", &cHardwareGX::Inst_PopB),
129     tInstLibEntry<tMethod>("pop-C", &cHardwareGX::Inst_PopC),
130     tInstLibEntry<tMethod>("push-A", &cHardwareGX::Inst_PushA),
131     tInstLibEntry<tMethod>("push-B", &cHardwareGX::Inst_PushB),
132     tInstLibEntry<tMethod>("push-C", &cHardwareGX::Inst_PushC),
133 
134     tInstLibEntry<tMethod>("shift-r", &cHardwareGX::Inst_ShiftR, nInstFlag::DEFAULT, "Shift bits in ?BX? right by one (divide by two)"),
135     tInstLibEntry<tMethod>("shift-l", &cHardwareGX::Inst_ShiftL, nInstFlag::DEFAULT, "Shift bits in ?BX? left by one (multiply by two)"),
136     tInstLibEntry<tMethod>("bit-1", &cHardwareGX::Inst_Bit1),
137     tInstLibEntry<tMethod>("set-num", &cHardwareGX::Inst_SetNum),
138     tInstLibEntry<tMethod>("val-grey", &cHardwareGX::Inst_ValGrey),
139     tInstLibEntry<tMethod>("val-dir", &cHardwareGX::Inst_ValDir),
140     tInstLibEntry<tMethod>("val-add-p", &cHardwareGX::Inst_ValAddP),
141     tInstLibEntry<tMethod>("val-fib", &cHardwareGX::Inst_ValFib),
142     tInstLibEntry<tMethod>("val-poly-c", &cHardwareGX::Inst_ValPolyC),
143     tInstLibEntry<tMethod>("inc", &cHardwareGX::Inst_Inc, nInstFlag::DEFAULT, "Increment ?BX? by one"),
144     tInstLibEntry<tMethod>("dec", &cHardwareGX::Inst_Dec, nInstFlag::DEFAULT, "Decrement ?BX? by one"),
145     tInstLibEntry<tMethod>("zero", &cHardwareGX::Inst_Zero, 0, "Set ?BX? to zero"),
146     tInstLibEntry<tMethod>("neg", &cHardwareGX::Inst_Neg),
147     tInstLibEntry<tMethod>("square", &cHardwareGX::Inst_Square),
148     tInstLibEntry<tMethod>("sqrt", &cHardwareGX::Inst_Sqrt),
149     tInstLibEntry<tMethod>("not", &cHardwareGX::Inst_Not),
150 
151     tInstLibEntry<tMethod>("add", &cHardwareGX::Inst_Add, nInstFlag::DEFAULT, "Add BX to CX and place the result in ?BX?"),
152     tInstLibEntry<tMethod>("sub", &cHardwareGX::Inst_Sub, nInstFlag::DEFAULT, "Subtract CX from BX and place the result in ?BX?"),
153     tInstLibEntry<tMethod>("mult", &cHardwareGX::Inst_Mult, 0, "Multiple BX by CX and place the result in ?BX?"),
154     tInstLibEntry<tMethod>("div", &cHardwareGX::Inst_Div, 0, "Divide BX by CX and place the result in ?BX?"),
155     tInstLibEntry<tMethod>("mod", &cHardwareGX::Inst_Mod),
156     tInstLibEntry<tMethod>("nand", &cHardwareGX::Inst_Nand, nInstFlag::DEFAULT, "Nand BX by CX and place the result in ?BX?"),
157     tInstLibEntry<tMethod>("nor", &cHardwareGX::Inst_Nor),
158     tInstLibEntry<tMethod>("and", &cHardwareGX::Inst_And),
159     tInstLibEntry<tMethod>("order", &cHardwareGX::Inst_Order),
160     tInstLibEntry<tMethod>("xor", &cHardwareGX::Inst_Xor),
161 
162     tInstLibEntry<tMethod>("copy", &cHardwareGX::Inst_Copy),
163     tInstLibEntry<tMethod>("read", &cHardwareGX::Inst_ReadInst),
164     tInstLibEntry<tMethod>("write", &cHardwareGX::Inst_WriteInst),
165     tInstLibEntry<tMethod>("stk-read", &cHardwareGX::Inst_StackReadInst),
166     tInstLibEntry<tMethod>("stk-writ", &cHardwareGX::Inst_StackWriteInst),
167 
168     tInstLibEntry<tMethod>("compare", &cHardwareGX::Inst_Compare),
169     tInstLibEntry<tMethod>("if-n-cpy", &cHardwareGX::Inst_IfNCpy),
170     tInstLibEntry<tMethod>("allocate", &cHardwareGX::Inst_Allocate),
171     tInstLibEntry<tMethod>("c-alloc", &cHardwareGX::Inst_CAlloc),
172     tInstLibEntry<tMethod>("search-f", &cHardwareGX::Inst_SearchF),
173     tInstLibEntry<tMethod>("search-b", &cHardwareGX::Inst_SearchB),
174     tInstLibEntry<tMethod>("mem-size", &cHardwareGX::Inst_MemSize),
175 
176     tInstLibEntry<tMethod>("get", &cHardwareGX::Inst_TaskGet),
177     tInstLibEntry<tMethod>("get-2", &cHardwareGX::Inst_TaskGet2),
178     tInstLibEntry<tMethod>("stk-get", &cHardwareGX::Inst_TaskStackGet),
179     tInstLibEntry<tMethod>("stk-load", &cHardwareGX::Inst_TaskStackLoad),
180     tInstLibEntry<tMethod>("put", &cHardwareGX::Inst_TaskPut),
181     tInstLibEntry<tMethod>("put-reset", &cHardwareGX::Inst_TaskPutResetInputs),
182     tInstLibEntry<tMethod>("IO", &cHardwareGX::Inst_TaskIO, nInstFlag::DEFAULT, "Output ?BX?, and input new number back into ?BX?"),
183     tInstLibEntry<tMethod>("IO-decay", &cHardwareGX::Inst_TaskIO_DecayBonus),
184     tInstLibEntry<tMethod>("IO-Feedback", &cHardwareGX::Inst_TaskIO_Feedback, 0, "Output ?BX?, and input new number back into ?BX?,  and push 1,0,  or -1 onto stack1 if merit increased, stayed the same, or decreased"),
185     tInstLibEntry<tMethod>("match-strings", &cHardwareGX::Inst_MatchStrings),
186     tInstLibEntry<tMethod>("sell", &cHardwareGX::Inst_Sell),
187     tInstLibEntry<tMethod>("buy", &cHardwareGX::Inst_Buy),
188     tInstLibEntry<tMethod>("send", &cHardwareGX::Inst_Send),
189     tInstLibEntry<tMethod>("receive", &cHardwareGX::Inst_Receive),
190     tInstLibEntry<tMethod>("sense", &cHardwareGX::Inst_SenseLog2),
191     tInstLibEntry<tMethod>("sense-unit", &cHardwareGX::Inst_SenseUnit),
192     tInstLibEntry<tMethod>("sense-m100", &cHardwareGX::Inst_SenseMult100),
193 
194     tInstLibEntry<tMethod>("donate-rnd", &cHardwareGX::Inst_DonateRandom),
195     tInstLibEntry<tMethod>("donate-edt", &cHardwareGX::Inst_DonateEditDist),
196     tInstLibEntry<tMethod>("donate-gbg",  &cHardwareGX::Inst_DonateGreenBeardGene),
197     tInstLibEntry<tMethod>("donate-tgb",  &cHardwareGX::Inst_DonateTrueGreenBeard),
198     tInstLibEntry<tMethod>("donate-threshgb",  &cHardwareGX::Inst_DonateThreshGreenBeard),
199     tInstLibEntry<tMethod>("donate-quantagb",  &cHardwareGX::Inst_DonateQuantaThreshGreenBeard),
200     tInstLibEntry<tMethod>("donate-NUL", &cHardwareGX::Inst_DonateNULL),
201 
202     tInstLibEntry<tMethod>("rotate-l", &cHardwareGX::Inst_RotateL),
203     tInstLibEntry<tMethod>("rotate-r", &cHardwareGX::Inst_RotateR),
204 
205     tInstLibEntry<tMethod>("set-cmut", &cHardwareGX::Inst_SetCopyMut),
206     tInstLibEntry<tMethod>("mod-cmut", &cHardwareGX::Inst_ModCopyMut),
207 
208     // Energy instruction
209     tInstLibEntry<tMethod>("recover", &cHardwareGX::Inst_ZeroEnergyUsed),
210 
211     // Head-based instructions
212     tInstLibEntry<tMethod>("h-alloc", &cHardwareGX::Inst_MaxAlloc, nInstFlag::DEFAULT, "Allocate maximum allowed space"),
213     tInstLibEntry<tMethod>("h-divide", &cHardwareGX::Inst_HeadDivide, nInstFlag::DEFAULT, "Divide code between read and write heads."),
214     tInstLibEntry<tMethod>("h-read", &cHardwareGX::Inst_HeadRead),
215     tInstLibEntry<tMethod>("h-write", &cHardwareGX::Inst_HeadWrite),
216     tInstLibEntry<tMethod>("h-copy", &cHardwareGX::Inst_HeadCopy, nInstFlag::DEFAULT, "Copy from read-head to write-head; advance both"),
217     tInstLibEntry<tMethod>("h-search", &cHardwareGX::Inst_HeadSearch, nInstFlag::DEFAULT, "Find complement template and make with flow head"),
218     tInstLibEntry<tMethod>("h-push", &cHardwareGX::Inst_HeadPush),
219     tInstLibEntry<tMethod>("h-pop", &cHardwareGX::Inst_HeadPop),
220     tInstLibEntry<tMethod>("adv-head", &cHardwareGX::Inst_AdvanceHead),
221     tInstLibEntry<tMethod>("mov-head", &cHardwareGX::Inst_MoveHead, nInstFlag::DEFAULT, "Move head ?IP? to the flow head"),
222     tInstLibEntry<tMethod>("jmp-head", &cHardwareGX::Inst_JumpHead, nInstFlag::DEFAULT, "Move head ?IP? by amount in CX register; CX = old pos."),
223     tInstLibEntry<tMethod>("get-head", &cHardwareGX::Inst_GetHead, nInstFlag::DEFAULT, "Copy the position of the ?IP? head into CX"),
224     tInstLibEntry<tMethod>("if-label", &cHardwareGX::Inst_IfLabel, nInstFlag::DEFAULT, "Execute next if we copied complement of attached label"),
225     tInstLibEntry<tMethod>("if-label2", &cHardwareGX::Inst_IfLabel2, 0, "If copied label compl., exec next inst; else SKIP W/NOPS"),
226     tInstLibEntry<tMethod>("set-flow", &cHardwareGX::Inst_SetFlow, nInstFlag::DEFAULT, "Set flow-head to position in ?CX?"),
227 
228     tInstLibEntry<tMethod>("h-copy2", &cHardwareGX::Inst_HeadCopy2),
229     tInstLibEntry<tMethod>("h-copy3", &cHardwareGX::Inst_HeadCopy3),
230     tInstLibEntry<tMethod>("h-copy4", &cHardwareGX::Inst_HeadCopy4),
231     tInstLibEntry<tMethod>("h-copy5", &cHardwareGX::Inst_HeadCopy5),
232     tInstLibEntry<tMethod>("h-copy6", &cHardwareGX::Inst_HeadCopy6),
233     tInstLibEntry<tMethod>("h-copy7", &cHardwareGX::Inst_HeadCopy7),
234     tInstLibEntry<tMethod>("h-copy8", &cHardwareGX::Inst_HeadCopy8),
235     tInstLibEntry<tMethod>("h-copy9", &cHardwareGX::Inst_HeadCopy9),
236     tInstLibEntry<tMethod>("h-copy10", &cHardwareGX::Inst_HeadCopy10),
237 
238     tInstLibEntry<tMethod>("repro", &cHardwareGX::Inst_Repro),
239 
240     tInstLibEntry<tMethod>("spawn-deme", &cHardwareGX::Inst_SpawnDeme),
241 
242     // Suicide
243     tInstLibEntry<tMethod>("kazi",	&cHardwareGX::Inst_Kazi),
244     tInstLibEntry<tMethod>("kazi5", &cHardwareGX::Inst_Kazi5),
245     tInstLibEntry<tMethod>("die", &cHardwareGX::Inst_Die),
246 
247     // Placebo instructions
248     tInstLibEntry<tMethod>("skip", &cHardwareGX::Inst_Skip),
249 
250     // Gene Expression Instructions
251     tInstLibEntry<tMethod>("p-alloc", &cHardwareGX::Inst_NewExecutableProgramid),
252     tInstLibEntry<tMethod>("g-alloc", &cHardwareGX::Inst_NewGenomeProgramid),
253     tInstLibEntry<tMethod>("p-copy", &cHardwareGX::Inst_ProgramidCopy),
254     tInstLibEntry<tMethod>("p-divide", &cHardwareGX::Inst_ProgramidDivide),
255 
256     tInstLibEntry<tMethod>("site", &cHardwareGX::Inst_Site),
257     tInstLibEntry<tMethod>("bind", &cHardwareGX::Inst_Bind),
258     tInstLibEntry<tMethod>("bind2", &cHardwareGX::Inst_Bind2),
259     tInstLibEntry<tMethod>("if-bind", &cHardwareGX::Inst_IfBind),
260     tInstLibEntry<tMethod>("if-bind2", &cHardwareGX::Inst_IfBind2),
261     tInstLibEntry<tMethod>("num-sites", &cHardwareGX::Inst_NumSites),
262 
263     tInstLibEntry<tMethod>("i-alloc", &cHardwareGX::Inst_ProgramidImplicitAllocate),
264     tInstLibEntry<tMethod>("i-divide", &cHardwareGX::Inst_ProgramidImplicitDivide),
265 
266     tInstLibEntry<tMethod>("promoter", &cHardwareGX::Inst_Promoter),
267     tInstLibEntry<tMethod>("terminator", &cHardwareGX::Inst_Terminator),
268     tInstLibEntry<tMethod>("h-repress", &cHardwareGX::Inst_HeadRepress),
269     tInstLibEntry<tMethod>("h-activate", &cHardwareGX::Inst_HeadActivate),
270     tInstLibEntry<tMethod>("end", &cHardwareGX::Inst_EndProgramidExecution),
271 
272     // These are dummy instructions used for making mutiple programids
273     // look like one genome (for purposes of passing to offspring and printing).
274     // They need to be included for the full GX model but should have ZERO probabilities!!!
275     tInstLibEntry<tMethod>("PROGRAMID", &cHardwareGX::Inst_Nop),
276     tInstLibEntry<tMethod>("READABLE", &cHardwareGX::Inst_Nop),
277     tInstLibEntry<tMethod>("BINDABLE", &cHardwareGX::Inst_Nop),
278     tInstLibEntry<tMethod>("EXECUTABLE", &cHardwareGX::Inst_Nop),
279 
280     // Must always be the last instruction
281     tInstLibEntry<tMethod>("NULL", &cHardwareGX::Inst_Nop, 0, "True no-operation instruction: does nothing"),
282   };
283 
284   const int n_size = sizeof(s_n_array)/sizeof(cNOPEntryCPU);
285 
286   static cString n_names[n_size];
287   static int nop_mods[n_size];
288   for (int i = 0; i < n_size && i < NUM_REGISTERS; i++) {
289     n_names[i] = s_n_array[i].name;
290     nop_mods[i] = s_n_array[i].nop_mod;
291   }
292 
293   const int f_size = sizeof(s_f_array)/sizeof(tInstLibEntry<tMethod>);
294   static tMethod functions[f_size];
295   for (int i = 0; i < f_size; i++) functions[i] = s_f_array[i].GetFunction();
296 
297 	const int def = 0;
298   const int null_inst = f_size - 1;
299 
300   return new tInstLib<tMethod>(f_size, s_f_array, n_names, nop_mods, functions, def, null_inst);
301 }
302 
303 
304 /*! Construct a cHardwareGX instance from the passed-in cOrganism.  This amounts to
305 creating an initial cProgramid from in_organism's genome.
306 */
cHardwareGX(cAvidaContext & ctx,cWorld * world,cOrganism * in_organism,cInstSet * in_inst_set)307 cHardwareGX::cHardwareGX(cAvidaContext& ctx, cWorld* world, cOrganism* in_organism, cInstSet* in_inst_set)
308 : cHardwareBase(world, in_organism, in_inst_set)
309 {
310   m_last_unique_id_assigned = 0;
311   m_functions = s_inst_slib->GetFunctions();
312   Reset(ctx);   // Setup the rest of the hardware...also creates initial programid(s) from genome
313 }
314 
315 
316 /*! Destructor; delete all programids. */
~cHardwareGX()317 cHardwareGX::~cHardwareGX()
318 {
319   std::for_each(m_programids.begin(), m_programids.end(), delete_functor());
320 }
321 
322 
323 /*! Reset this cHardwareGX to a known state.
324 Removes all the current cProgramids, and creates new cProgramids from the germ.
325 */
internalReset()326 void cHardwareGX::internalReset()
327 {
328   // Clear the current list of programids.
329   std::for_each(m_programids.begin(), m_programids.end(), delete_functor());
330   m_programids.clear();
331 
332   // Using the "full" gene expression setup.  All programid creation is explicit.
333   if (m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get() == 0)
334   {
335 
336     // And add any programids specified by the "genome."
337     Sequence genome = m_organism->GetGenome().GetSequence();
338 
339     // These specify the range of instructions that will be used to create a new
340     // programid.  The range of instructions used to create a programid is:
341     // [begin, end), that is, the instruction pointed to by end is *not* copied.
342     // Find the first instance of a PROGRAMID instruction.
343     int begin = genome.FindInst(GetInstSet().GetInst("PROGRAMID"));
344     while (true) {
345       // Find the boundary of this programid.
346       int i = genome.FindInst(GetInstSet().GetInst("PROGRAMID"), begin + 1);
347       if (i == -1) {
348         if (begin != -1) AddProgramid(new cProgramid(genome.Crop(begin, genome.GetSize()), this));
349         break;
350       }
351       AddProgramid(new cProgramid(genome.Crop(begin, i), this));
352       begin = i;
353     }
354 
355     assert(m_programids.size()>0);
356 
357     // Sanity, oh, where is my sanity?
358     bool has_executable=false;
359     bool has_bindable=false;
360     for(programid_list::iterator i=m_programids.begin(); i!=m_programids.end(); ++i) {
361       has_executable = has_executable || (*i)->GetExecutable();
362       has_bindable = has_bindable || (*i)->GetBindable();
363     }
364     assert(has_bindable && has_executable);
365   }
366   else // Implicit RNAP GX Model. Executable programids created from genome.
367   {
368     m_recycle_state = 0.0;
369     // Optimization -- don't actually need a programid for the genome in the double implicit model.
370     // In the implicit model, we create one genome programid as the first memory space
371     programid_ptr p = new cProgramid(m_organism->GetGenome().GetSequence(), this);
372     p->SetReadable(true);
373     AddProgramid(p);
374 
375     // Initialize the promoter state and rates
376     m_promoter_update_head.Reset(this,0);
377     m_promoter_update_head.Set(0);
378     m_promoter_default_rates.ResizeClear( m_organism->GetGenome().GetSize() );
379     m_promoter_rates.ResizeClear( m_organism->GetGenome().GetSize() ); // Initialized in UpdatePromoterRates()
380     m_promoter_states.ResizeClear( m_organism->GetGenome().GetSize() );
381     m_promoter_occupied_sites.ResizeClear( m_organism->GetGenome().GetSize() );
382 
383     cInstruction promoter_inst = GetInstSet().GetInst(cStringUtil::Stringf("promoter"));
384     do {
385       m_promoter_default_rates[m_promoter_update_head.GetPosition()] =
386         (m_promoter_update_head.GetInst() == promoter_inst) ? 1 : m_world->GetConfig().IMPLICIT_BG_PROMOTER_RATE.Get();
387       m_promoter_states[m_promoter_update_head.GetPosition()] = 0.0;
388       m_promoter_occupied_sites[m_promoter_update_head.GetPosition()] = 0;
389       m_promoter_update_head++;
390     } while (m_promoter_update_head.GetPosition() != 0);
391 
392     AdjustPromoterRates();
393 
394     // \todo implement different initial conditions for created executable programids
395     m_promoter_update_head.Set(m_organism->GetGenome().GetSize() - 1); //So that ++ moves it to position zero
396     ProcessImplicitGeneExpression(1);
397   }
398 
399   m_current = m_programids.back();
400   m_mal_active = false;
401   m_executedmatchstrings = false;
402 
403 }
404 
405 
internalResetOnFailedDivide()406 void cHardwareGX::internalResetOnFailedDivide()
407 {
408 	internalReset();
409 }
410 
411 /*! In cHardwareGX, SingleProcess is something of a misnomer.  Each time this method
412   is called, each cProgramid executes a single instruction.
413   */
SingleProcess(cAvidaContext & ctx,bool speculative)414 bool cHardwareGX::SingleProcess(cAvidaContext& ctx, bool speculative)
415 {
416   if (speculative) return false;
417 
418   cPhenotype& phenotype = m_organism->GetPhenotype();
419 
420   // Turn over programids if using the implicit model
421   if ( m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get() )
422   {
423     m_recycle_state += (double)m_world->GetConfig().IMPLICIT_TURNOVER_RATE.Get();
424     int num_programids = m_programids.size();
425     while (m_recycle_state >= 1.0)
426     {
427       if (m_programids.size() > (unsigned int)m_world->GetConfig().MAX_PROGRAMIDS.Get())
428       {
429         RemoveProgramid(1);
430       }
431       else
432       {
433         num_programids++;
434       }
435       m_recycle_state -= 1.0;
436     }
437     ProcessImplicitGeneExpression(num_programids);
438   }
439 
440   m_organism->SetRunning(true);
441   m_just_divided = false;
442   phenotype.IncTimeUsed();
443 
444   // A temporary list of the current programids in this organism.
445   programid_list runnable(m_programids.begin(), m_programids.end());
446 
447   // Execute one instruction for each programid.
448   for(programid_list::iterator i=runnable.begin(); i!=runnable.end(); ++i) {
449     // Currently executing programid.
450     m_current = *i;
451 
452     // Print the status of this CPU at each step...
453     if (m_tracer != NULL) m_tracer->TraceHardware(ctx, *this);
454 
455     if(m_current->GetExecute()) {
456       // In case the IP is modified by this instruction, make sure that it wraps
457       // around to the beginning of the genome.
458       IP().Adjust();
459 
460       // Find the instruction to be executed.
461       const cInstruction& cur_inst = IP().GetInst();
462 
463       m_advance_ip = true;
464       m_reset_inputs = false;
465       m_reset_heads = false;
466       SingleProcess_ExecuteInst(ctx, cur_inst);
467 
468       // Break out if we just divided b/c the number of programids
469       // will have changed and it won't be obvious how to continue
470       // @JEB this organism may also have been replaced by its child,
471       // so we will not be able to continue safely!
472       if (m_just_divided) break;
473 
474       if (m_advance_ip == true) {
475         IP().Advance();
476       }
477 
478       // Update this programid stat
479       m_current->IncCPUCyclesUsed();
480     }
481   }
482   m_current = 0;
483 
484   // Now kill old programids.
485   unsigned int on_p = 0;
486   while(on_p < m_programids.size()) {
487     if(  ((m_world->GetConfig().MAX_PROGRAMID_AGE.Get() > 0) && (m_programids[on_p]->GetCPUCyclesUsed() > m_world->GetConfig().MAX_PROGRAMID_AGE.Get()) )
488       || m_programids[on_p]->m_marked_for_death) {
489       RemoveProgramid(on_p);
490     } else {
491       on_p++;
492     }
493   }
494 
495   m_current = m_programids.back(); // m_current must always point to a programid!
496 
497   // Update phenotype. Note the difference between these cpu cycles and the per-programid ones...
498   phenotype.IncCPUCyclesUsed();
499 
500   // Kill creatures who have reached their max num of instructions executed.
501   const int max_executed = m_organism->GetMaxExecuted();
502   if((max_executed > 0 && phenotype.GetTimeUsed() >= max_executed)
503       || phenotype.GetToDie() == true) {
504     m_organism->Die(ctx);
505   }
506 
507   // Kill organisms that have no active programids.
508   if(m_programids.size() == 0) {
509     m_organism->Die(ctx);
510   }
511 
512   m_organism->SetRunning(false);
513   CheckImplicitRepro(ctx);
514 
515   return true;
516 }
517 
518 /*! This method executes one instruction for one programid. */
SingleProcess_ExecuteInst(cAvidaContext & ctx,const cInstruction & cur_inst)519 bool cHardwareGX::SingleProcess_ExecuteInst(cAvidaContext& ctx, const cInstruction& cur_inst)
520 {
521   // Copy the instruction in case of execution errors.
522   cInstruction actual_inst = cur_inst;
523 
524 #ifdef EXECUTION_ERRORS
525   // If there is an execution error, execute a random instruction.
526   if (m_organism->TestExeErr()) actual_inst = m_inst_set->GetRandomInst(ctx);
527 #endif /* EXECUTION_ERRORS */
528 
529   // Get the index for the instruction.
530   int inst_idx = m_inst_set->GetLibFunctionIndex(actual_inst);
531 
532   // Mark the instruction as executed
533   IP().SetFlagExecuted();
534 
535   // instruction execution count incremeneted
536   m_organism->GetPhenotype().IncCurInstCount(actual_inst.GetOp());
537 
538   // And execute it.
539   const bool exec_success = (this->*(m_functions[inst_idx]))(ctx);
540 
541   // decremenet if the instruction was not executed successfully
542   if (exec_success == false) {
543     m_organism->GetPhenotype().DecCurInstCount(actual_inst.GetOp());
544   }
545 
546   return exec_success;
547 }
548 
549 
ProcessBonusInst(cAvidaContext & ctx,const cInstruction & inst)550 void cHardwareGX::ProcessBonusInst(cAvidaContext& ctx, const cInstruction& inst)
551 {
552   // Mark this organism as running...
553   bool prev_run_state = m_organism->IsRunning();
554   m_organism->SetRunning(true);
555 
556   if (m_tracer != NULL) m_tracer->TraceHardware(ctx, *this, true);
557 
558   SingleProcess_ExecuteInst(ctx, inst);
559 
560   m_organism->SetRunning(prev_run_state);
561 }
562 
563 
564 /*! \todo Revisit.
565 */
PrintStatus(ostream & fp)566 void cHardwareGX::PrintStatus(ostream& fp)
567 {
568   //\todo clean up references
569 
570   // Extra information about this programid
571   fp << "MemSpace:" << m_current->GetID() << "   Programid ID:" << m_current->m_unique_id;
572   if (m_current->GetExecute()) fp << " EXECUTING";
573   if (m_current->GetExecutable()) fp << " EXECUTABLE";
574   if (m_current->GetBindable()) fp << " BINDABLE";
575   if (m_current->GetReadable()) fp << " READABLE";
576   fp << endl;
577 
578   fp << m_organism->GetPhenotype().GetCPUCyclesUsed() << " ";
579   fp << "IP:" << IP().GetPosition() << "    ";
580 
581   for (int i = 0; i < NUM_REGISTERS; i++) {
582     fp << static_cast<char>('A' + i) << "X:" << GetRegister(i) << " ";
583     fp << setbase(16) << "[0x" << GetRegister(i) << "]  " << setbase(10);
584   }
585   fp << endl;
586 
587   fp << "  R-Head:" << GetHead(nHardware::HEAD_READ).GetMemSpace() << ":" << GetHead(nHardware::HEAD_READ).GetPosition() << " "
588     << "W-Head:" << GetHead(nHardware::HEAD_WRITE).GetMemSpace() << ":" << GetHead(nHardware::HEAD_WRITE).GetPosition() << " "
589     << "F-Head:" << GetHead(nHardware::HEAD_FLOW).GetMemSpace() << ":" << GetHead(nHardware::HEAD_FLOW).GetPosition() << "  "
590     << "RL:" << GetReadLabel().AsString() << "   "
591     << endl;
592 
593 // This will have to be revisited soon.
594 //  int number_of_stacks = GetNumStacks();
595 //  for (int stack_id = 0; stack_id < number_of_stacks; stack_id++) {
596 //    fp << ((m_threads[m_cur_thread].cur_stack == stack_id) ? '*' : ' ') << " Stack "
597 //          << stack_id << ":" << setbase(16) << setfill('0');
598 //    for (int i = 0; i < nHardware::STACK_SIZE; i++)
599 //      fp << " Ox" << setw(8) << GetStack(i, stack_id, 0);
600 //    fp << setfill(' ') << setbase(10) << endl;
601 //  }
602 
603   fp << "  Mem (" << GetMemory().GetSize() << "):"
604       << "  " << GetMemory().AsString()
605       << endl;
606   fp.flush();
607 }
608 
609 /////////////////////////////////////////////////////////////////////////
610 // Method: cHardwareGX::FindLabel(direction)
611 //
612 // Search in 'direction' (+ or - 1) from the instruction pointer for the
613 // compliment of the label in 'next_label' and return a pointer to the
614 // results.  If direction is 0, search from the beginning of the genome.
615 //
616 /////////////////////////////////////////////////////////////////////////
617 
FindLabel(int direction)618 cHeadCPU cHardwareGX::FindLabel(int direction)
619 {
620   cHeadCPU & inst_ptr = IP();
621 
622   // Start up a search head at the position of the instruction pointer.
623   cHeadCPU search_head(inst_ptr);
624   cCodeLabel & search_label = GetLabel();
625 
626   // Make sure the label is of size > 0.
627 
628   if (search_label.GetSize() == 0) {
629     return inst_ptr;
630   }
631 
632   // Call special functions depending on if jump is forwards or backwards.
633   int found_pos = 0;
634   if( direction < 0 ) {
635     found_pos = FindLabel_Backward(search_label, inst_ptr.GetMemory(),
636                                    inst_ptr.GetPosition() - search_label.GetSize());
637   }
638 
639   // Jump forward.
640   else if (direction > 0) {
641     found_pos = FindLabel_Forward(search_label, inst_ptr.GetMemory(),
642                                   inst_ptr.GetPosition());
643   }
644 
645   // Jump forward from the very beginning.
646   else {
647     found_pos = FindLabel_Forward(search_label, inst_ptr.GetMemory(), 0);
648   }
649 
650   // Return the last line of the found label, if it was found.
651   if (found_pos >= 0) search_head.Set(found_pos - 1);
652 
653   // Return the found position (still at start point if not found).
654   return search_head;
655 }
656 
657 
658 // Search forwards for search_label from _after_ position pos in the
659 // memory.  Return the first line _after_ the the found label.  It is okay
660 // to find search label's match inside another label.
661 
FindLabel_Forward(const cCodeLabel & search_label,const Sequence & search_genome,int pos)662 int cHardwareGX::FindLabel_Forward(const cCodeLabel & search_label,
663                                     const Sequence & search_genome, int pos)
664 {
665   assert (pos < search_genome.GetSize() && pos >= 0);
666 
667   int search_start = pos;
668   int label_size = search_label.GetSize();
669   bool found_label = false;
670 
671   // Move off the template we are on.
672   pos += label_size;
673 
674   // Search until we find the complement or exit the memory.
675   while (pos < search_genome.GetSize()) {
676 
677     // If we are within a label, rewind to the beginning of it and see if
678     // it has the proper sub-label that we're looking for.
679 
680     if (m_inst_set->IsNop(search_genome[pos])) {
681       // Find the start and end of the label we're in the middle of.
682 
683       int start_pos = pos;
684       int end_pos = pos + 1;
685       while (start_pos > search_start &&
686              m_inst_set->IsNop( search_genome[start_pos - 1] )) {
687         start_pos--;
688       }
689       while (end_pos < search_genome.GetSize() &&
690              m_inst_set->IsNop( search_genome[end_pos] )) {
691         end_pos++;
692       }
693       int test_size = end_pos - start_pos;
694 
695       // See if this label has the proper sub-label within it.
696       int max_offset = test_size - label_size + 1;
697       int offset = start_pos;
698       for (offset = start_pos; offset < start_pos + max_offset; offset++) {
699 
700         // Test the number of matches for this offset.
701         int matches;
702         for (matches = 0; matches < label_size; matches++) {
703           if (search_label[matches] !=
704               m_inst_set->GetNopMod( search_genome[offset + matches] )) {
705             break;
706           }
707         }
708 
709         // If we have found it, break out of this loop!
710         if (matches == label_size) {
711           found_label = true;
712           break;
713         }
714       }
715 
716       // If we've found the complement label, set the position to the end of
717       // the label we found it in, and break out.
718 
719       if (found_label == true) {
720         // pos = end_pos;
721         pos = label_size + offset;
722         break;
723       }
724 
725       // We haven't found it; jump pos to just after the current label being
726       // checked.
727       pos = end_pos;
728     }
729 
730     // Jump up a block to the next possible point to find a label,
731     pos += label_size;
732   }
733 
734   // If the label was not found return a -1.
735   if (found_label == false) pos = -1;
736 
737   return pos;
738 }
739 
740 // Search backwards for search_label from _before_ position pos in the
741 // memory.  Return the first line _after_ the the found label.  It is okay
742 // to find search label's match inside another label.
743 
FindLabel_Backward(const cCodeLabel & search_label,const Sequence & search_genome,int pos)744 int cHardwareGX::FindLabel_Backward(const cCodeLabel & search_label,
745                                      const Sequence & search_genome, int pos)
746 {
747   assert (pos < search_genome.GetSize());
748 
749   int search_start = pos;
750   int label_size = search_label.GetSize();
751   bool found_label = false;
752 
753   // Move off the template we are on.
754   pos -= label_size;
755 
756   // Search until we find the complement or exit the memory.
757   while (pos >= 0) {
758     // If we are within a label, rewind to the beginning of it and see if
759     // it has the proper sub-label that we're looking for.
760 
761     if (m_inst_set->IsNop( search_genome[pos] )) {
762       // Find the start and end of the label we're in the middle of.
763 
764       int start_pos = pos;
765       int end_pos = pos + 1;
766       while (start_pos > 0 && m_inst_set->IsNop(search_genome[start_pos - 1])) {
767         start_pos--;
768       }
769       while (end_pos < search_start &&
770              m_inst_set->IsNop(search_genome[end_pos])) {
771         end_pos++;
772       }
773       int test_size = end_pos - start_pos;
774 
775       // See if this label has the proper sub-label within it.
776       int max_offset = test_size - label_size + 1;
777       for (int offset = start_pos; offset < start_pos + max_offset; offset++) {
778 
779         // Test the number of matches for this offset.
780         int matches;
781         for (matches = 0; matches < label_size; matches++) {
782           if (search_label[matches] !=
783               m_inst_set->GetNopMod(search_genome[offset + matches])) {
784             break;
785           }
786         }
787 
788         // If we have found it, break out of this loop!
789         if (matches == label_size) {
790           found_label = true;
791           break;
792         }
793       }
794 
795       // If we've found the complement label, set the position to the end of
796       // the label we found it in, and break out.
797 
798       if (found_label == true) {
799         pos = end_pos;
800         break;
801       }
802 
803       // We haven't found it; jump pos to just before the current label
804       // being checked.
805       pos = start_pos - 1;
806     }
807 
808     // Jump up a block to the next possible point to find a label,
809     pos -= label_size;
810   }
811 
812   // If the label was not found return a -1.
813   if (found_label == false) pos = -1;
814 
815   return pos;
816 }
817 
818 // Search for 'in_label' anywhere in the hardware.
FindLabel(const cCodeLabel & in_label,int direction)819 cHeadCPU cHardwareGX::FindLabel(const cCodeLabel & in_label, int direction)
820 {
821   assert (in_label.GetSize() > 0);
822 
823   // IDEALY:
824   // Keep making jumps (in the proper direction) equal to the label
825   // length.  If we are inside of a label, check its size, and see if
826   // any of the sub-labels match properly.
827   // FOR NOW:
828   // Get something which works, no matter how inefficient!!!
829 
830   cHeadCPU temp_head(this);
831 
832   while (temp_head.InMemory()) {
833     // IDEALY: Analyze the label we are in; see if the one we are looking
834     // for could be a sub-label of it.  Skip past it if not.
835 
836     int i;
837     for (i = 0; i < in_label.GetSize(); i++) {
838       if (!m_inst_set->IsNop(temp_head.GetInst()) ||
839           in_label[i] != m_inst_set->GetNopMod(temp_head.GetInst())) {
840         break;
841       }
842     }
843     if (i == GetLabel().GetSize()) {
844       temp_head.AbsJump(i - 1);
845       return temp_head;
846     }
847 
848     temp_head.AbsJump(direction);     // IDEALY: MAKE LARGER JUMPS
849   }
850 
851   temp_head.AbsSet(-1);
852   return temp_head;
853 }
854 
855 
856 
857 
858 
ReadInst(const int in_inst)859 void cHardwareGX::ReadInst(const int in_inst)
860 {
861   if(m_inst_set->IsNop(cInstruction(in_inst))) {
862     GetReadLabel().AddNop(in_inst);
863   } else {
864     GetReadLabel().Clear();
865   }
866 }
867 
868 
AdjustHeads()869 void cHardwareGX::AdjustHeads()
870 {
871 //  for (int i = 0; i < GetNumThreads(); i++) {
872 //    for (int j = 0; j < NUM_HEADS; j++) {
873 //      m_threads[i].heads[j].Adjust();
874 //    }
875 //  }
876 }
877 
878 
879 
880 // This function looks at the current position in the info of a creature,
881 // and sets the next_label to be the sequence of nops which follows.  The
882 // instruction pointer is left on the last line of the label found.
883 
ReadLabel(int max_size)884 void cHardwareGX::ReadLabel(int max_size)
885 {
886   int count = 0;
887   cHeadCPU * inst_ptr = &( IP() );
888 
889   GetLabel().Clear();
890 
891   while (m_inst_set->IsNop(inst_ptr->GetNextInst()) &&
892          (count < max_size)) {
893     count++;
894     inst_ptr->Advance();
895     GetLabel().AddNop(m_inst_set->GetNopMod(inst_ptr->GetInst()));
896 
897     // If this is the first line of the template, mark it executed.
898     if (GetLabel().GetSize() <=	m_world->GetConfig().MAX_LABEL_EXE_SIZE.Get()) {
899       inst_ptr->SetFlagExecuted();
900     }
901   }
902 }
903 
904 
905 //bool cHardwareGX::ForkThread()
906 //{
907 //  const int num_threads = GetNumThreads();
908 //  if (num_threads == m_world->GetConfig().MAX_CPU_THREADS.Get()) return false;
909 //
910 //  // Make room for the new thread.
911 //  m_threads.Resize(num_threads + 1);
912 //
913 //  // Initialize the new thread to the same values as the current one.
914 //  m_threads[num_threads] = m_threads[m_cur_thread];
915 //
916 //  // Find the first free bit in m_thread_id_chart to determine the new
917 //  // thread id.
918 //  int new_id = 0;
919 //  while ( (m_thread_id_chart >> new_id) & 1 == 1) new_id++;
920 //  m_threads[num_threads].SetID(new_id);
921 //  m_thread_id_chart |= (1 << new_id);
922 //
923 //  return true;
924 //}
925 //
926 //
927 //bool cHardwareGX::KillThread()
928 //{
929 //  // Make sure that there is always at least one thread...
930 //  if (GetNumThreads() == 1) return false;
931 //
932 //  // Note the current thread and set the current back one.
933 //  const int kill_thread = m_cur_thread;
934 //  ThreadPrev();
935 //
936 //  // Turn off this bit in the m_thread_id_chart...
937 //  m_thread_id_chart ^= 1 << m_threads[kill_thread].GetID();
938 //
939 //  // Copy the last thread into the kill position
940 //  const int last_thread = GetNumThreads() - 1;
941 //  if (last_thread != kill_thread) {
942 //    m_threads[kill_thread] = m_threads[last_thread];
943 //  }
944 //
945 //  // Kill the thread!
946 //  m_threads.Resize(GetNumThreads() - 1);
947 //
948 //  if (m_cur_thread > kill_thread) m_cur_thread--;
949 //
950 //  return true;
951 //}
952 
953 ////////////////////////////
954 //  Instruction Helpers...
955 ////////////////////////////
956 
FindModifiedRegister(int default_register)957 inline int cHardwareGX::FindModifiedRegister(int default_register)
958 {
959   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
960 
961   if (m_inst_set->IsNop(IP().GetNextInst())) {
962     IP().Advance();
963     default_register = m_inst_set->GetNopMod(IP().GetInst());
964     IP().SetFlagExecuted();
965   }
966   return default_register;
967 }
968 
FindModifiedNextRegister(int default_register)969 inline int cHardwareGX::FindModifiedNextRegister(int default_register)
970 {
971   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
972 
973   if (m_inst_set->IsNop(IP().GetNextInst())) {
974     IP().Advance();
975     default_register = m_inst_set->GetNopMod(IP().GetInst());
976     IP().SetFlagExecuted();
977   } else {
978     default_register = (default_register + 1) % NUM_REGISTERS;
979   }
980   return default_register;
981 }
982 
FindModifiedPreviousRegister(int default_register)983 inline int cHardwareGX::FindModifiedPreviousRegister(int default_register)
984 {
985   assert(default_register < NUM_REGISTERS);  // Reg ID too high.
986 
987   if (m_inst_set->IsNop(IP().GetNextInst())) {
988     IP().Advance();
989     default_register = m_inst_set->GetNopMod(IP().GetInst());
990     IP().SetFlagExecuted();
991   } else {
992     default_register = (default_register + NUM_REGISTERS - 1) % NUM_REGISTERS;
993   }
994   return default_register;
995 }
996 
997 
FindModifiedHead(int default_head)998 inline int cHardwareGX::FindModifiedHead(int default_head)
999 {
1000   assert(default_head < NUM_HEADS); // Head ID too high.
1001 
1002   if (m_inst_set->IsNop(IP().GetNextInst())) {
1003     IP().Advance();
1004     default_head = m_inst_set->GetNopMod(IP().GetInst());
1005     IP().SetFlagExecuted();
1006   }
1007   return default_head;
1008 }
1009 
1010 
FindNextRegister(int base_reg)1011 inline int cHardwareGX::FindNextRegister(int base_reg)
1012 {
1013   return (base_reg + 1) % NUM_REGISTERS;
1014 }
1015 
1016 
Allocate_Necro(const int new_size)1017 bool cHardwareGX::Allocate_Necro(const int new_size)
1018 {
1019   GetMemory().ResizeOld(new_size);
1020   return true;
1021 }
1022 
Allocate_Random(cAvidaContext & ctx,const int old_size,const int new_size)1023 bool cHardwareGX::Allocate_Random(cAvidaContext& ctx, const int old_size, const int new_size)
1024 {
1025   GetMemory().Resize(new_size);
1026 
1027   for (int i = old_size; i < new_size; i++) {
1028     GetMemory()[i] = m_inst_set->GetRandomInst(ctx);
1029   }
1030   return true;
1031 }
1032 
Allocate_Default(const int new_size)1033 bool cHardwareGX::Allocate_Default(const int new_size)
1034 {
1035   GetMemory().Resize(new_size);
1036 
1037   // New space already defaults to default instruction...
1038 
1039   return true;
1040 }
1041 
Allocate_Main(cAvidaContext & ctx,const int allocated_size)1042 bool cHardwareGX::Allocate_Main(cAvidaContext& ctx, const int allocated_size)
1043 {
1044   // must do divide before second allocate & must allocate positive amount...
1045   if (m_world->GetConfig().REQUIRE_ALLOCATE.Get() && m_mal_active == true) {
1046     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR, "Allocate already active");
1047     return false;
1048   }
1049   if (allocated_size < 1) {
1050     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1051           cStringUtil::Stringf("Allocate of %d too small", allocated_size));
1052     return false;
1053   }
1054 
1055   const int old_size = GetMemory().GetSize();
1056   const int new_size = old_size + allocated_size;
1057 
1058   // Make sure that the new size is in range.
1059   if (new_size > MAX_GENOME_LENGTH  ||  new_size < MIN_GENOME_LENGTH) {
1060     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1061           cStringUtil::Stringf("Invalid post-allocate size (%d)",
1062                                new_size));
1063     return false;
1064   }
1065 
1066   const int max_alloc_size = (int) (old_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
1067   if (allocated_size > max_alloc_size) {
1068     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1069           cStringUtil::Stringf("Allocate too large (%d > %d)",
1070                                allocated_size, max_alloc_size));
1071     return false;
1072   }
1073 
1074   const int max_old_size =
1075     (int) (allocated_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
1076   if (old_size > max_old_size) {
1077     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
1078           cStringUtil::Stringf("Allocate too small (%d > %d)",
1079                                old_size, max_old_size));
1080     return false;
1081   }
1082 
1083   switch (m_world->GetConfig().ALLOC_METHOD.Get()) {
1084     case ALLOC_METHOD_NECRO:
1085       // Only break if this succeeds -- otherwise just do random.
1086       if (Allocate_Necro(new_size) == true) break;
1087     case ALLOC_METHOD_RANDOM:
1088       Allocate_Random(ctx, old_size, new_size);
1089       break;
1090     case ALLOC_METHOD_DEFAULT:
1091       Allocate_Default(new_size);
1092       break;
1093   }
1094 
1095   m_mal_active = true;
1096 
1097   return true;
1098 }
1099 
calcExecutedSize(const int parent_size)1100 int cHardwareGX::calcExecutedSize(const int parent_size)
1101 {
1102 /* @JEB - not really relevant to GX
1103   int executed_size = 0;
1104   const cCPUMemory& memory = GetMemory();
1105   for (int i = 0; i < parent_size; i++) {
1106     if (memory.FlagExecuted(i)) executed_size++;
1107   }
1108   return executed_size;
1109 */
1110   return parent_size;
1111 }
1112 
calcCopiedSize(const int parent_size,const int child_size)1113 int cHardwareGX::calcCopiedSize(const int parent_size, const int child_size)
1114 {
1115   return parent_size;
1116 
1117   //@JEB - this is used in a division test. Not clear how to translate to GX for now.
1118 
1119   //int copied_size = 0;
1120   //const cCPUMemory& memory = m_programids[GetHead(nHardware::HEAD_WRITE).GetMemSpace()]->GetMemory();
1121   //for (int i = 0; i < memory.GetSize(); i++) {
1122   //  if (memory.FlagCopied(i)) copied_size++;
1123   //}
1124   //return copied_size;
1125 }
1126 
1127 
1128 /*! Divide works a little differently in cHardwareGX than in other CPUs.  First,
1129 the cProgramid directly builds its offspring (rather than attaching its genome), so
1130 we don't need to do any genome splitting.  This also enables the offspring to be
1131 active during replication.  Second, we have to divvy up the other cProgramid objects
1132 between the parent and offspring.  We also have to be careful to make sure that
1133 we have two genomes!
1134 */
Divide_Main(cAvidaContext & ctx)1135 bool cHardwareGX::Divide_Main(cAvidaContext& ctx)
1136 {
1137   return true;
1138 }
1139 
1140 
1141 //////////////////////////
1142 // And the instructions...
1143 //////////////////////////
1144 
Inst_If0(cAvidaContext & ctx)1145 bool cHardwareGX::Inst_If0(cAvidaContext& ctx)          // Execute next if ?bx? ==0.
1146 {
1147   const int reg_used = FindModifiedRegister(REG_BX);
1148   if (GetRegister(reg_used) != 0)  IP().Advance();
1149   return true;
1150 }
1151 
Inst_IfNot0(cAvidaContext & ctx)1152 bool cHardwareGX::Inst_IfNot0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
1153 {
1154   const int reg_used = FindModifiedRegister(REG_BX);
1155   if (GetRegister(reg_used) == 0)  IP().Advance();
1156   return true;
1157 }
1158 
Inst_IfEqu(cAvidaContext & ctx)1159 bool cHardwareGX::Inst_IfEqu(cAvidaContext& ctx)      // Execute next if bx == ?cx?
1160 {
1161   const int op1 = FindModifiedRegister(REG_BX);
1162   const int op2 = FindNextRegister(op1);
1163   if (GetRegister(op1) != GetRegister(op2))  IP().Advance();
1164   return true;
1165 }
1166 
Inst_IfNEqu(cAvidaContext & ctx)1167 bool cHardwareGX::Inst_IfNEqu(cAvidaContext& ctx)     // Execute next if bx != ?cx?
1168 {
1169   const int op1 = FindModifiedRegister(REG_BX);
1170   const int op2 = FindNextRegister(op1);
1171   if (GetRegister(op1) == GetRegister(op2))  IP().Advance();
1172   return true;
1173 }
1174 
Inst_IfGr0(cAvidaContext & ctx)1175 bool cHardwareGX::Inst_IfGr0(cAvidaContext& ctx)       // Execute next if ?bx? ! < 0.
1176 {
1177   const int reg_used = FindModifiedRegister(REG_BX);
1178   if (GetRegister(reg_used) <= 0)  IP().Advance();
1179   return true;
1180 }
1181 
Inst_IfGr(cAvidaContext & ctx)1182 bool cHardwareGX::Inst_IfGr(cAvidaContext& ctx)       // Execute next if bx > ?cx?
1183 {
1184   const int op1 = FindModifiedRegister(REG_BX);
1185   const int op2 = FindNextRegister(op1);
1186   if (GetRegister(op1) <= GetRegister(op2))  IP().Advance();
1187   return true;
1188 }
1189 
Inst_IfGrEqu0(cAvidaContext & ctx)1190 bool cHardwareGX::Inst_IfGrEqu0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
1191 {
1192   const int reg_used = FindModifiedRegister(REG_BX);
1193   if (GetRegister(reg_used) < 0)  IP().Advance();
1194   return true;
1195 }
1196 
Inst_IfGrEqu(cAvidaContext & ctx)1197 bool cHardwareGX::Inst_IfGrEqu(cAvidaContext& ctx)       // Execute next if bx > ?cx?
1198 {
1199   const int op1 = FindModifiedRegister(REG_BX);
1200   const int op2 = FindNextRegister(op1);
1201   if (GetRegister(op1) < GetRegister(op2)) IP().Advance();
1202   return true;
1203 }
1204 
Inst_IfLess0(cAvidaContext & ctx)1205 bool cHardwareGX::Inst_IfLess0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
1206 {
1207   const int reg_used = FindModifiedRegister(REG_BX);
1208   if (GetRegister(reg_used) >= 0)  IP().Advance();
1209   return true;
1210 }
1211 
Inst_IfLess(cAvidaContext & ctx)1212 bool cHardwareGX::Inst_IfLess(cAvidaContext& ctx)       // Execute next if ?bx? < ?cx?
1213 {
1214   const int op1 = FindModifiedRegister(REG_BX);
1215   const int op2 = FindNextRegister(op1);
1216   if (GetRegister(op1) >=  GetRegister(op2))  IP().Advance();
1217   return true;
1218 }
1219 
Inst_IfLsEqu0(cAvidaContext & ctx)1220 bool cHardwareGX::Inst_IfLsEqu0(cAvidaContext& ctx)       // Execute next if ?bx? != 0.
1221 {
1222   const int reg_used = FindModifiedRegister(REG_BX);
1223   if (GetRegister(reg_used) > 0) IP().Advance();
1224   return true;
1225 }
1226 
Inst_IfLsEqu(cAvidaContext & ctx)1227 bool cHardwareGX::Inst_IfLsEqu(cAvidaContext& ctx)       // Execute next if bx > ?cx?
1228 {
1229   const int op1 = FindModifiedRegister(REG_BX);
1230   const int op2 = FindNextRegister(op1);
1231   if (GetRegister(op1) >  GetRegister(op2))  IP().Advance();
1232   return true;
1233 }
1234 
Inst_IfBit1(cAvidaContext & ctx)1235 bool cHardwareGX::Inst_IfBit1(cAvidaContext& ctx)
1236 {
1237   const int reg_used = FindModifiedRegister(REG_BX);
1238   if ((GetRegister(reg_used) & 1) == 0)  IP().Advance();
1239   return true;
1240 }
1241 
Inst_IfANotEqB(cAvidaContext & ctx)1242 bool cHardwareGX::Inst_IfANotEqB(cAvidaContext& ctx)     // Execute next if AX != BX
1243 {
1244   if (GetRegister(REG_AX) == GetRegister(REG_BX) )  IP().Advance();
1245   return true;
1246 }
1247 
Inst_IfBNotEqC(cAvidaContext & ctx)1248 bool cHardwareGX::Inst_IfBNotEqC(cAvidaContext& ctx)     // Execute next if BX != CX
1249 {
1250   if (GetRegister(REG_BX) == GetRegister(REG_CX) )  IP().Advance();
1251   return true;
1252 }
1253 
Inst_IfANotEqC(cAvidaContext & ctx)1254 bool cHardwareGX::Inst_IfANotEqC(cAvidaContext& ctx)     // Execute next if AX != BX
1255 {
1256   if (GetRegister(REG_AX) == GetRegister(REG_CX) )  IP().Advance();
1257   return true;
1258 }
1259 
1260 
Inst_Call(cAvidaContext & ctx)1261 bool cHardwareGX::Inst_Call(cAvidaContext& ctx)
1262 {
1263   // Put the starting location onto the stack
1264   const int location = IP().GetPosition();
1265   StackPush(location);
1266 
1267   // Jump to the compliment label (or by the ammount in the bx register)
1268   ReadLabel();
1269   GetLabel().Rotate(1, NUM_NOPS);
1270 
1271   if (GetLabel().GetSize() == 0) {
1272     IP().Jump(GetRegister(REG_BX));
1273     return true;
1274   }
1275 
1276   const cHeadCPU jump_location(FindLabel(1));
1277   if (jump_location.GetPosition() != -1) {
1278     IP().Set(jump_location);
1279     return true;
1280   }
1281 
1282   // If complement label was not found; record an error.
1283   m_organism->Fault(FAULT_LOC_JUMP, FAULT_TYPE_ERROR,
1284                   "call: no complement label");
1285   return false;
1286 }
1287 
Inst_Return(cAvidaContext & ctx)1288 bool cHardwareGX::Inst_Return(cAvidaContext& ctx)
1289 {
1290   IP().Set(StackPop());
1291   return true;
1292 }
1293 
Inst_Throw(cAvidaContext & ctx)1294 bool cHardwareGX::Inst_Throw(cAvidaContext& ctx)
1295 {
1296   // Only initialize this once to save some time...
1297   static cInstruction catch_inst = GetInstSet().GetInst(cStringUtil::Stringf("catch"));
1298 
1299   //Look for the label directly (no complement)
1300   ReadLabel();
1301 
1302   cHeadCPU search_head(IP());
1303   int start_pos = search_head.GetPosition();
1304   search_head++;
1305 
1306   while (start_pos != search_head.GetPosition())
1307   {
1308     // If we find a catch instruction, compare the NOPs following it
1309     if (search_head.GetInst() == catch_inst)
1310     {
1311       int catch_pos = search_head.GetPosition();
1312       search_head++;
1313 
1314       // Continue to examine the label after the catch
1315       //  (1) It ends (=> use the catch!)
1316       //  (2) It becomes longer than the throw label (=> use the catch!)
1317       //  (3) We find a NOP that doesnt match the throw (=> DON'T use the catch...)
1318 
1319       bool match = true;
1320       int size_matched = 0;
1321       while ( match && m_inst_set->IsNop(search_head.GetInst()) && (size_matched < GetLabel().GetSize()) )
1322       {
1323         if ( GetLabel()[size_matched] != m_inst_set->GetNopMod( search_head.GetInst()) ) match = false;
1324         search_head++;
1325         size_matched++;
1326       }
1327 
1328       // We found a matching catch instruction
1329       if (match)
1330       {
1331         IP().Set(catch_pos);
1332         m_advance_ip = false; // Don't automatically move the IP
1333                               // so we mark the catch as executed.
1334         return true;
1335       }
1336 
1337       //If we advanced past NOPs during testing, retreat
1338       if ( !m_inst_set->IsNop(search_head.GetInst()) ) search_head--;
1339     }
1340     search_head.Advance();
1341   }
1342 
1343   return false;
1344 }
1345 
1346 
Inst_ThrowIfNot0(cAvidaContext & ctx)1347 bool cHardwareGX::Inst_ThrowIfNot0(cAvidaContext& ctx)
1348 {
1349   if (GetRegister(REG_BX) == 0) return false;
1350   return Inst_Throw(ctx);
1351 }
1352 
Inst_ThrowIf0(cAvidaContext & ctx)1353 bool cHardwareGX::Inst_ThrowIf0(cAvidaContext& ctx)
1354 {
1355   if (GetRegister(REG_BX) != 0) return false;
1356   return Inst_Throw(ctx);
1357 }
1358 
Inst_Goto(cAvidaContext & ctx)1359 bool cHardwareGX::Inst_Goto(cAvidaContext& ctx)
1360 {
1361   // Only initialize this once to save some time...
1362   static cInstruction label_inst = GetInstSet().GetInst(cStringUtil::Stringf("label"));
1363 
1364   //Look for an EXACT label match after a 'label' instruction
1365   ReadLabel();
1366 
1367   cHeadCPU search_head(IP());
1368   int start_pos = search_head.GetPosition();
1369   search_head++;
1370 
1371   while (start_pos != search_head.GetPosition())
1372   {
1373     if (search_head.GetInst() == label_inst)
1374     {
1375       int label_pos = search_head.GetPosition();
1376       search_head++;
1377       int size_matched = 0;
1378       while ( size_matched < GetLabel().GetSize() )
1379       {
1380         if ( !m_inst_set->IsNop(search_head.GetInst()) ) break;
1381         if ( GetLabel()[size_matched] != m_inst_set->GetNopMod( search_head.GetInst()) ) break;
1382         if ( !m_inst_set->IsNop(search_head.GetInst()) ) break;
1383 
1384         size_matched++;
1385         search_head++;
1386       }
1387 
1388       // We found a matching 'label' instruction only if the next
1389       // instruction (at the search head now) is also not a NOP
1390       if ( (size_matched == GetLabel().GetSize()) && !m_inst_set->IsNop(search_head.GetInst()) )
1391       {
1392         IP().Set(label_pos);
1393         m_advance_ip = false; // Don't automatically move the IP
1394                               // so we mark the catch as executed.
1395         return true;
1396       }
1397 
1398       //If we advanced past NOPs during testing, retreat
1399       if ( !m_inst_set->IsNop(search_head.GetInst()) ) search_head--;
1400     }
1401     search_head++;
1402   }
1403 
1404   return false;
1405 }
1406 
1407 
Inst_GotoIfNot0(cAvidaContext & ctx)1408 bool cHardwareGX::Inst_GotoIfNot0(cAvidaContext& ctx)
1409 {
1410   if (GetRegister(REG_BX) == 0) return false;
1411   return Inst_Goto(ctx);
1412 }
1413 
Inst_GotoIf0(cAvidaContext & ctx)1414 bool cHardwareGX::Inst_GotoIf0(cAvidaContext& ctx)
1415 {
1416   if (GetRegister(REG_BX) != 0) return false;
1417   return Inst_Goto(ctx);
1418 }
1419 
1420 
Inst_Pop(cAvidaContext & ctx)1421 bool cHardwareGX::Inst_Pop(cAvidaContext& ctx)
1422 {
1423   const int reg_used = FindModifiedRegister(REG_BX);
1424   GetRegister(reg_used) = StackPop();
1425   return true;
1426 }
1427 
Inst_Push(cAvidaContext & ctx)1428 bool cHardwareGX::Inst_Push(cAvidaContext& ctx)
1429 {
1430   const int reg_used = FindModifiedRegister(REG_BX);
1431   StackPush(GetRegister(reg_used));
1432   return true;
1433 }
1434 
Inst_HeadPop(cAvidaContext & ctx)1435 bool cHardwareGX::Inst_HeadPop(cAvidaContext& ctx)
1436 {
1437   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
1438   GetHead(head_used).Set(StackPop());
1439   return true;
1440 }
1441 
Inst_HeadPush(cAvidaContext & ctx)1442 bool cHardwareGX::Inst_HeadPush(cAvidaContext& ctx)
1443 {
1444   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
1445   StackPush(GetHead(head_used).GetPosition());
1446   if (head_used == nHardware::HEAD_IP) {
1447     GetHead(head_used).Set(GetHead(nHardware::HEAD_FLOW));
1448     m_advance_ip = false;
1449   }
1450   return true;
1451 }
1452 
1453 
Inst_PopA(cAvidaContext & ctx)1454 bool cHardwareGX::Inst_PopA(cAvidaContext& ctx) { GetRegister(REG_AX) = StackPop(); return true;}
Inst_PopB(cAvidaContext & ctx)1455 bool cHardwareGX::Inst_PopB(cAvidaContext& ctx) { GetRegister(REG_BX) = StackPop(); return true;}
Inst_PopC(cAvidaContext & ctx)1456 bool cHardwareGX::Inst_PopC(cAvidaContext& ctx) { GetRegister(REG_CX) = StackPop(); return true;}
1457 
Inst_PushA(cAvidaContext & ctx)1458 bool cHardwareGX::Inst_PushA(cAvidaContext& ctx) { StackPush(GetRegister(REG_AX)); return true;}
Inst_PushB(cAvidaContext & ctx)1459 bool cHardwareGX::Inst_PushB(cAvidaContext& ctx) { StackPush(GetRegister(REG_BX)); return true;}
Inst_PushC(cAvidaContext & ctx)1460 bool cHardwareGX::Inst_PushC(cAvidaContext& ctx) { StackPush(GetRegister(REG_CX)); return true;}
1461 
Inst_SwitchStack(cAvidaContext & ctx)1462 bool cHardwareGX::Inst_SwitchStack(cAvidaContext& ctx) { SwitchStack(); return true;}
Inst_FlipStack(cAvidaContext & ctx)1463 bool cHardwareGX::Inst_FlipStack(cAvidaContext& ctx)   { StackFlip(); return true;}
1464 
Inst_Swap(cAvidaContext & ctx)1465 bool cHardwareGX::Inst_Swap(cAvidaContext& ctx)
1466 {
1467   const int op1 = FindModifiedRegister(REG_BX);
1468   const int op2 = FindNextRegister(op1);
1469   Swap(GetRegister(op1), GetRegister(op2));
1470   return true;
1471 }
1472 
Inst_SwapAB(cAvidaContext & ctx)1473 bool cHardwareGX::Inst_SwapAB(cAvidaContext& ctx)\
1474 {
1475   Swap(GetRegister(REG_AX), GetRegister(REG_BX)); return true;
1476 }
Inst_SwapBC(cAvidaContext & ctx)1477 bool cHardwareGX::Inst_SwapBC(cAvidaContext& ctx)
1478 {
1479   Swap(GetRegister(REG_BX), GetRegister(REG_CX)); return true;
1480 }
Inst_SwapAC(cAvidaContext & ctx)1481 bool cHardwareGX::Inst_SwapAC(cAvidaContext& ctx)
1482 {
1483   Swap(GetRegister(REG_AX), GetRegister(REG_CX)); return true;
1484 }
1485 
Inst_CopyReg(cAvidaContext & ctx)1486 bool cHardwareGX::Inst_CopyReg(cAvidaContext& ctx)
1487 {
1488   const int src = FindModifiedRegister(REG_BX);
1489   const int dst = FindNextRegister(src);
1490   GetRegister(dst) = GetRegister(src);
1491   return true;
1492 }
1493 
Inst_CopyRegAB(cAvidaContext & ctx)1494 bool cHardwareGX::Inst_CopyRegAB(cAvidaContext& ctx)
1495 {
1496   GetRegister(REG_AX) = GetRegister(REG_BX);   return true;
1497 }
Inst_CopyRegAC(cAvidaContext & ctx)1498 bool cHardwareGX::Inst_CopyRegAC(cAvidaContext& ctx)
1499 {
1500   GetRegister(REG_AX) = GetRegister(REG_CX);   return true;
1501 }
Inst_CopyRegBA(cAvidaContext & ctx)1502 bool cHardwareGX::Inst_CopyRegBA(cAvidaContext& ctx)
1503 {
1504   GetRegister(REG_BX) = GetRegister(REG_AX);   return true;
1505 }
Inst_CopyRegBC(cAvidaContext & ctx)1506 bool cHardwareGX::Inst_CopyRegBC(cAvidaContext& ctx)
1507 {
1508   GetRegister(REG_BX) = GetRegister(REG_CX);   return true;
1509 }
Inst_CopyRegCA(cAvidaContext & ctx)1510 bool cHardwareGX::Inst_CopyRegCA(cAvidaContext& ctx)
1511 {
1512   GetRegister(REG_CX) = GetRegister(REG_AX);   return true;
1513 }
Inst_CopyRegCB(cAvidaContext & ctx)1514 bool cHardwareGX::Inst_CopyRegCB(cAvidaContext& ctx)
1515 {
1516   GetRegister(REG_CX) = GetRegister(REG_BX);   return true;
1517 }
1518 
Inst_Reset(cAvidaContext & ctx)1519 bool cHardwareGX::Inst_Reset(cAvidaContext& ctx)
1520 {
1521   GetRegister(REG_AX) = 0;
1522   GetRegister(REG_BX) = 0;
1523   GetRegister(REG_CX) = 0;
1524   StackClear();
1525   return true;
1526 }
1527 
Inst_ShiftR(cAvidaContext & ctx)1528 bool cHardwareGX::Inst_ShiftR(cAvidaContext& ctx)
1529 {
1530   const int reg_used = FindModifiedRegister(REG_BX);
1531   GetRegister(reg_used) >>= 1;
1532   return true;
1533 }
1534 
Inst_ShiftL(cAvidaContext & ctx)1535 bool cHardwareGX::Inst_ShiftL(cAvidaContext& ctx)
1536 {
1537   const int reg_used = FindModifiedRegister(REG_BX);
1538   GetRegister(reg_used) <<= 1;
1539   return true;
1540 }
1541 
Inst_Bit1(cAvidaContext & ctx)1542 bool cHardwareGX::Inst_Bit1(cAvidaContext& ctx)
1543 {
1544   const int reg_used = FindModifiedRegister(REG_BX);
1545   GetRegister(reg_used) |=  1;
1546   return true;
1547 }
1548 
Inst_SetNum(cAvidaContext & ctx)1549 bool cHardwareGX::Inst_SetNum(cAvidaContext& ctx)
1550 {
1551   ReadLabel();
1552   GetRegister(REG_BX) = GetLabel().AsInt(NUM_NOPS);
1553   return true;
1554 }
1555 
Inst_ValGrey(cAvidaContext & ctx)1556 bool cHardwareGX::Inst_ValGrey(cAvidaContext& ctx) {
1557   ReadLabel();
1558   GetRegister(REG_BX) = GetLabel().AsIntGreyCode(NUM_NOPS);
1559   return true;
1560 }
1561 
Inst_ValDir(cAvidaContext & ctx)1562 bool cHardwareGX::Inst_ValDir(cAvidaContext& ctx) {
1563   ReadLabel();
1564   GetRegister(REG_BX) = GetLabel().AsIntDirect(NUM_NOPS);
1565   return true;
1566 }
1567 
Inst_ValAddP(cAvidaContext & ctx)1568 bool cHardwareGX::Inst_ValAddP(cAvidaContext& ctx) {
1569   ReadLabel();
1570   GetRegister(REG_BX) = GetLabel().AsIntAdditivePolynomial(NUM_NOPS);
1571   return true;
1572 }
1573 
Inst_ValFib(cAvidaContext & ctx)1574 bool cHardwareGX::Inst_ValFib(cAvidaContext& ctx) {
1575   ReadLabel();
1576   GetRegister(REG_BX) = GetLabel().AsIntFib(NUM_NOPS);
1577   return true;
1578 }
1579 
Inst_ValPolyC(cAvidaContext & ctx)1580 bool cHardwareGX::Inst_ValPolyC(cAvidaContext& ctx) {
1581   ReadLabel();
1582   GetRegister(REG_BX) = GetLabel().AsIntPolynomialCoefficent(NUM_NOPS);
1583   return true;
1584 }
1585 
Inst_Inc(cAvidaContext & ctx)1586 bool cHardwareGX::Inst_Inc(cAvidaContext& ctx)
1587 {
1588   const int reg_used = FindModifiedRegister(REG_BX);
1589   GetRegister(reg_used) += 1;
1590   return true;
1591 }
1592 
Inst_Dec(cAvidaContext & ctx)1593 bool cHardwareGX::Inst_Dec(cAvidaContext& ctx)
1594 {
1595   const int reg_used = FindModifiedRegister(REG_BX);
1596   GetRegister(reg_used) -= 1;
1597   return true;
1598 }
1599 
Inst_Zero(cAvidaContext & ctx)1600 bool cHardwareGX::Inst_Zero(cAvidaContext& ctx)
1601 {
1602   const int reg_used = FindModifiedRegister(REG_BX);
1603   GetRegister(reg_used) = 0;
1604   return true;
1605 }
1606 
Inst_Neg(cAvidaContext & ctx)1607 bool cHardwareGX::Inst_Neg(cAvidaContext& ctx)
1608 {
1609   const int src = FindModifiedRegister(REG_BX);
1610   const int dst = src;
1611   GetRegister(dst) = -GetRegister(src);
1612   return true;
1613 }
1614 
Inst_Square(cAvidaContext & ctx)1615 bool cHardwareGX::Inst_Square(cAvidaContext& ctx)
1616 {
1617   const int src = FindModifiedRegister(REG_BX);
1618   const int dst = src;
1619   GetRegister(dst) = GetRegister(src) * GetRegister(src);
1620   return true;
1621 }
1622 
Inst_Sqrt(cAvidaContext & ctx)1623 bool cHardwareGX::Inst_Sqrt(cAvidaContext& ctx)
1624 {
1625   const int src = FindModifiedRegister(REG_BX);
1626   const int dst = src;
1627   const int value = GetRegister(src);
1628   if (value > 1) GetRegister(dst) = static_cast<int>(sqrt(static_cast<double>(value)));
1629   else if (value < 0) {
1630     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "sqrt: value is negative");
1631     return false;
1632   }
1633   return true;
1634 }
1635 
Inst_Log(cAvidaContext & ctx)1636 bool cHardwareGX::Inst_Log(cAvidaContext& ctx)
1637 {
1638   const int src = FindModifiedRegister(REG_BX);
1639   const int dst = src;
1640   const int value = GetRegister(src);
1641   if (value >= 1) GetRegister(dst) = static_cast<int>(log(static_cast<double>(value)));
1642   else if (value < 0) {
1643     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "log: value is negative");
1644     return false;
1645   }
1646   return true;
1647 }
1648 
Inst_Log10(cAvidaContext & ctx)1649 bool cHardwareGX::Inst_Log10(cAvidaContext& ctx)
1650 {
1651   const int src = FindModifiedRegister(REG_BX);
1652   const int dst = src;
1653   const int value = GetRegister(src);
1654   if (value >= 1) GetRegister(dst) = static_cast<int>(log10(static_cast<double>(value)));
1655   else if (value < 0) {
1656     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "log10: value is negative");
1657     return false;
1658   }
1659   return true;
1660 }
1661 
Inst_Add(cAvidaContext & ctx)1662 bool cHardwareGX::Inst_Add(cAvidaContext& ctx)
1663 {
1664   const int dst = FindModifiedRegister(REG_BX);
1665   const int op1 = REG_BX;
1666   const int op2 = REG_CX;
1667   GetRegister(dst) = GetRegister(op1) + GetRegister(op2);
1668   return true;
1669 }
1670 
Inst_Sub(cAvidaContext & ctx)1671 bool cHardwareGX::Inst_Sub(cAvidaContext& ctx)
1672 {
1673   const int dst = FindModifiedRegister(REG_BX);
1674   const int op1 = REG_BX;
1675   const int op2 = REG_CX;
1676   GetRegister(dst) = GetRegister(op1) - GetRegister(op2);
1677   return true;
1678 }
1679 
Inst_Mult(cAvidaContext & ctx)1680 bool cHardwareGX::Inst_Mult(cAvidaContext& ctx)
1681 {
1682   const int dst = FindModifiedRegister(REG_BX);
1683   const int op1 = REG_BX;
1684   const int op2 = REG_CX;
1685   GetRegister(dst) = GetRegister(op1) * GetRegister(op2);
1686   return true;
1687 }
1688 
Inst_Div(cAvidaContext & ctx)1689 bool cHardwareGX::Inst_Div(cAvidaContext& ctx)
1690 {
1691   const int dst = FindModifiedRegister(REG_BX);
1692   const int op1 = REG_BX;
1693   const int op2 = REG_CX;
1694   if (GetRegister(op2) != 0) {
1695     if (0-INT_MAX > GetRegister(op1) && GetRegister(op2) == -1)
1696       m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "div: Float exception");
1697     else
1698       GetRegister(dst) = GetRegister(op1) / GetRegister(op2);
1699   } else {
1700     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "div: dividing by 0");
1701     return false;
1702   }
1703   return true;
1704 }
1705 
Inst_Mod(cAvidaContext & ctx)1706 bool cHardwareGX::Inst_Mod(cAvidaContext& ctx)
1707 {
1708   const int dst = FindModifiedRegister(REG_BX);
1709   const int op1 = REG_BX;
1710   const int op2 = REG_CX;
1711   if (GetRegister(op2) != 0) {
1712     GetRegister(dst) = GetRegister(op1) % GetRegister(op2);
1713   } else {
1714     m_organism->Fault(FAULT_LOC_MATH, FAULT_TYPE_ERROR, "mod: modding by 0");
1715     return false;
1716   }
1717   return true;
1718 }
1719 
1720 
Inst_Nand(cAvidaContext & ctx)1721 bool cHardwareGX::Inst_Nand(cAvidaContext& ctx)
1722 {
1723   const int dst = FindModifiedRegister(REG_BX);
1724   const int op1 = REG_BX;
1725   const int op2 = REG_CX;
1726   GetRegister(dst) = ~(GetRegister(op1) & GetRegister(op2));
1727   return true;
1728 }
1729 
Inst_Nor(cAvidaContext & ctx)1730 bool cHardwareGX::Inst_Nor(cAvidaContext& ctx)
1731 {
1732   const int dst = FindModifiedRegister(REG_BX);
1733   const int op1 = REG_BX;
1734   const int op2 = REG_CX;
1735   GetRegister(dst) = ~(GetRegister(op1) | GetRegister(op2));
1736   return true;
1737 }
1738 
Inst_And(cAvidaContext & ctx)1739 bool cHardwareGX::Inst_And(cAvidaContext& ctx)
1740 {
1741   const int dst = FindModifiedRegister(REG_BX);
1742   const int op1 = REG_BX;
1743   const int op2 = REG_CX;
1744   GetRegister(dst) = (GetRegister(op1) & GetRegister(op2));
1745   return true;
1746 }
1747 
Inst_Not(cAvidaContext & ctx)1748 bool cHardwareGX::Inst_Not(cAvidaContext& ctx)
1749 {
1750   const int src = FindModifiedRegister(REG_BX);
1751   const int dst = src;
1752   GetRegister(dst) = ~(GetRegister(src));
1753   return true;
1754 }
1755 
Inst_Order(cAvidaContext & ctx)1756 bool cHardwareGX::Inst_Order(cAvidaContext& ctx)
1757 {
1758   const int op1 = REG_BX;
1759   const int op2 = REG_CX;
1760   if (GetRegister(op1) > GetRegister(op2)) {
1761     Swap(GetRegister(op1), GetRegister(op2));
1762   }
1763   return true;
1764 }
1765 
Inst_Xor(cAvidaContext & ctx)1766 bool cHardwareGX::Inst_Xor(cAvidaContext& ctx)
1767 {
1768   const int dst = FindModifiedRegister(REG_BX);
1769   const int op1 = REG_BX;
1770   const int op2 = REG_CX;
1771   GetRegister(dst) = GetRegister(op1) ^ GetRegister(op2);
1772   return true;
1773 }
1774 
Inst_Copy(cAvidaContext & ctx)1775 bool cHardwareGX::Inst_Copy(cAvidaContext& ctx)
1776 {
1777   const int op1 = REG_BX;
1778   const int op2 = REG_AX;
1779 
1780   const cHeadCPU from(this, GetRegister(op1));
1781   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
1782 
1783   if (m_organism->TestCopyMut(ctx)) {
1784     to.SetInst(m_inst_set->GetRandomInst(ctx));
1785     to.SetFlagMutated();  // Mark this instruction as mutated...
1786     to.SetFlagCopyMut();  // Mark this instruction as copy mut...
1787   } else {
1788     to.SetInst(from.GetInst());
1789     to.ClearFlagMutated();  // UnMark
1790     to.ClearFlagCopyMut();  // UnMark
1791   }
1792 
1793   to.SetFlagCopied();  // Set the copied flag.
1794   return true;
1795 }
1796 
Inst_ReadInst(cAvidaContext & ctx)1797 bool cHardwareGX::Inst_ReadInst(cAvidaContext& ctx)
1798 {
1799   const int dst = FindModifiedRegister(REG_CX);
1800   const int src = REG_BX;
1801 
1802   const cHeadCPU from(this, GetRegister(src));
1803 
1804   // Dis-allowing mutations on read, for the moment (write only...)
1805   // @CAO This allows perfect error-correction...
1806   GetRegister(dst) = from.GetInst().GetOp();
1807   return true;
1808 }
1809 
Inst_WriteInst(cAvidaContext & ctx)1810 bool cHardwareGX::Inst_WriteInst(cAvidaContext& ctx)
1811 {
1812   const int src = FindModifiedRegister(REG_CX);
1813   const int op1 = REG_BX;
1814   const int op2 = REG_AX;
1815 
1816   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
1817   const int value = Mod(GetRegister(src), m_inst_set->GetSize());
1818 
1819   // Change value on a mutation...
1820   if (m_organism->TestCopyMut(ctx)) {
1821     to.SetInst(m_inst_set->GetRandomInst(ctx));
1822     to.SetFlagMutated();      // Mark this instruction as mutated...
1823     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
1824   } else {
1825     to.SetInst(cInstruction(value));
1826     to.ClearFlagMutated();     // UnMark
1827     to.ClearFlagCopyMut();     // UnMark
1828   }
1829 
1830   to.SetFlagCopied();  // Set the copied flag.
1831   return true;
1832 }
1833 
Inst_StackReadInst(cAvidaContext & ctx)1834 bool cHardwareGX::Inst_StackReadInst(cAvidaContext& ctx)
1835 {
1836   const int reg_used = FindModifiedRegister(REG_CX);
1837   cHeadCPU from(this, GetRegister(reg_used));
1838   StackPush(from.GetInst().GetOp());
1839   return true;
1840 }
1841 
Inst_StackWriteInst(cAvidaContext & ctx)1842 bool cHardwareGX::Inst_StackWriteInst(cAvidaContext& ctx)
1843 {
1844   const int dst = FindModifiedRegister(REG_BX);
1845   const int op1 = REG_AX;
1846   cHeadCPU to(this, GetRegister(op1) + GetRegister(dst));
1847   const int value = Mod(StackPop(), m_inst_set->GetSize());
1848 
1849   // Change value on a mutation...
1850   if (m_organism->TestCopyMut(ctx)) {
1851     to.SetInst(m_inst_set->GetRandomInst(ctx));
1852     to.SetFlagMutated();      // Mark this instruction as mutated...
1853     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
1854   } else {
1855     to.SetInst(cInstruction(value));
1856     to.ClearFlagMutated();     // UnMark
1857     to.ClearFlagCopyMut();     // UnMark
1858   }
1859 
1860   to.SetFlagCopied();  // Set the copied flag.
1861   return true;
1862 }
1863 
Inst_Compare(cAvidaContext & ctx)1864 bool cHardwareGX::Inst_Compare(cAvidaContext& ctx)
1865 {
1866   const int dst = FindModifiedRegister(REG_CX);
1867   const int op1 = REG_BX;
1868   const int op2 = REG_AX;
1869 
1870   cHeadCPU from(this, GetRegister(op1));
1871   cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
1872 
1873   // Compare is dangerous -- it can cause mutations!
1874   if (m_organism->TestCopyMut(ctx)) {
1875     to.SetInst(m_inst_set->GetRandomInst(ctx));
1876     to.SetFlagMutated();      // Mark this instruction as mutated...
1877     to.SetFlagCopyMut();      // Mark this instruction as copy mut...
1878   }
1879 
1880   GetRegister(dst) = from.GetInst().GetOp() - to.GetInst().GetOp();
1881 
1882   return true;
1883 }
1884 
Inst_IfNCpy(cAvidaContext & ctx)1885 bool cHardwareGX::Inst_IfNCpy(cAvidaContext& ctx)
1886 {
1887   const int op1 = REG_BX;
1888   const int op2 = REG_AX;
1889 
1890   const cHeadCPU from(this, GetRegister(op1));
1891   const cHeadCPU to(this, GetRegister(op2) + GetRegister(op1));
1892 
1893   // Allow for errors in this test...
1894   if (m_organism->TestCopyMut(ctx)) {
1895     if (from.GetInst() != to.GetInst()) IP().Advance();
1896   } else {
1897     if (from.GetInst() == to.GetInst()) IP().Advance();
1898   }
1899   return true;
1900 }
1901 
Inst_Allocate(cAvidaContext & ctx)1902 bool cHardwareGX::Inst_Allocate(cAvidaContext& ctx)   // Allocate bx more space...
1903 {
1904   const int src = REG_BX;
1905   const int dst = REG_AX;
1906   const int size = GetMemory().GetSize();
1907   if (Allocate_Main(ctx, GetRegister(src))) {
1908     GetRegister(dst) = size;
1909     return true;
1910   } else return false;
1911 }
1912 
1913 
Inst_CAlloc(cAvidaContext & ctx)1914 bool cHardwareGX::Inst_CAlloc(cAvidaContext& ctx)
1915 {
1916   return Allocate_Main(ctx, GetMemory().GetSize());
1917 }
1918 
Inst_MaxAlloc(cAvidaContext & ctx)1919 bool cHardwareGX::Inst_MaxAlloc(cAvidaContext& ctx)   // Allocate maximal more
1920 {
1921   const int dst = REG_AX;
1922   const int cur_size = GetMemory().GetSize();
1923   const int alloc_size = Min((int) (m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get() * cur_size),
1924                              MAX_GENOME_LENGTH - cur_size);
1925   if (Allocate_Main(ctx, alloc_size)) {
1926     GetRegister(dst) = cur_size;
1927     return true;
1928   } else return false;
1929 }
1930 
Inst_Repro(cAvidaContext & ctx)1931 bool cHardwareGX::Inst_Repro(cAvidaContext& ctx)
1932 {
1933   // Setup child
1934   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
1935   child_genome = m_organism->GetGenome().GetSequence();
1936   m_organism->OffspringGenome().SetHardwareType(GetType());
1937   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
1938   m_organism->GetPhenotype().SetLinesCopied(m_organism->GetGenome().GetSize());
1939 
1940   Divide_DoMutations(ctx);
1941 
1942   bool viable = Divide_CheckViable(ctx, m_organism->GetGenome().GetSize(), child_genome.GetSize());
1943   //if the offspring is not viable (due to splippage mutations), then what do we do?
1944   if (viable == false) return false;
1945 
1946   // Many tests will require us to run the offspring through a test CPU;
1947   // this is, for example, to see if mutations need to be reverted or if
1948   // lineages need to be updated.
1949   Divide_TestFitnessMeasures(ctx);
1950 
1951   // reset first time instruction costs
1952   for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
1953     m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
1954   }
1955 
1956   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
1957     m_advance_ip = false;
1958   }
1959 
1960   // Activate the child
1961   bool parent_alive = m_organism->ActivateDivide(ctx);
1962 
1963   // Do more work if the parent lives through the birth of the offspring
1964   if (parent_alive) {
1965     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
1966   }
1967 
1968   m_just_divided = true;
1969   return true;
1970 }
1971 
Inst_SpawnDeme(cAvidaContext & ctx)1972 bool cHardwareGX::Inst_SpawnDeme(cAvidaContext& ctx)
1973 {
1974   m_organism->SpawnDeme(ctx);
1975   return true;
1976 }
1977 
Inst_Kazi(cAvidaContext & ctx)1978 bool cHardwareGX::Inst_Kazi(cAvidaContext& ctx)
1979 {
1980   const int reg_used = FindModifiedRegister(REG_AX);
1981   double percentProb = ((double) (GetRegister(reg_used) % 100)) / 100.0;
1982   if ( ctx.GetRandom().P(percentProb) ) m_organism->Kaboom(0, ctx);
1983   return true;
1984 }
1985 
Inst_Kazi5(cAvidaContext & ctx)1986 bool cHardwareGX::Inst_Kazi5(cAvidaContext& ctx)
1987 {
1988   const int reg_used = FindModifiedRegister(REG_AX);
1989   double percentProb = ((double) (GetRegister(reg_used) % 100)) / 100.0;
1990   if ( ctx.GetRandom().P(percentProb) ) m_organism->Kaboom(5, ctx);
1991   return true;
1992 }
1993 
Inst_Die(cAvidaContext & ctx)1994 bool cHardwareGX::Inst_Die(cAvidaContext& ctx)
1995 {
1996   m_organism->Die(ctx);
1997   return true;
1998 }
1999 
2000 
2001 
Inst_TaskGet(cAvidaContext & ctx)2002 bool cHardwareGX::Inst_TaskGet(cAvidaContext& ctx)
2003 {
2004   const int reg_used = FindModifiedRegister(REG_CX);
2005   const int value = m_organism->GetNextInput(m_current->m_input_pointer);
2006   GetRegister(reg_used) = value;
2007   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value);  // Check for tasks completed.
2008   return true;
2009 }
2010 
2011 
2012 // @JEB - this instruction does more than two "gets" together
2013 // it also (1) resets the inputs and (2) resets an organisms task counts
Inst_TaskGet2(cAvidaContext & ctx)2014 bool cHardwareGX::Inst_TaskGet2(cAvidaContext& ctx)
2015 {
2016   // Randomize the inputs so they can't save numbers
2017   m_organism->GetOrgInterface().ResetInputs(ctx);   // Now re-randomize the inputs this organism sees
2018   m_current->m_input_buf.Clear();
2019   //m_organism->ClearInput();                         // Also clear their input buffers, or they can still claim
2020                                                   // rewards for numbers no longer in their environment!
2021 
2022   const int reg_used_1 = FindModifiedRegister(REG_BX);
2023   const int reg_used_2 = FindNextRegister(reg_used_1);
2024 
2025   const int value1 = m_organism->GetNextInput(m_current->m_input_pointer);
2026   GetRegister(reg_used_1) = value1;
2027   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value1);
2028 
2029   const int value2 = m_organism->GetNextInput(m_current->m_input_pointer);
2030   GetRegister(reg_used_2) = value2;
2031   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value2);
2032 
2033   // Clear the task number
2034   m_organism->GetPhenotype().ClearEffTaskCount();
2035 
2036   return true;
2037 }
2038 
Inst_TaskStackGet(cAvidaContext & ctx)2039 bool cHardwareGX::Inst_TaskStackGet(cAvidaContext& ctx)
2040 {
2041   const int value = m_organism->GetNextInput(m_current->m_input_pointer);
2042   StackPush(value);
2043   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value);
2044   return true;
2045 }
2046 
Inst_TaskStackLoad(cAvidaContext & ctx)2047 bool cHardwareGX::Inst_TaskStackLoad(cAvidaContext& ctx)
2048 {
2049   // @DMB - TODO: this should look at the input_size...
2050   for (int i = 0; i < 3; i++)
2051     StackPush( m_organism->GetNextInput(m_current->m_input_pointer) );
2052   return true;
2053 }
2054 
Inst_TaskPut(cAvidaContext & ctx)2055 bool cHardwareGX::Inst_TaskPut(cAvidaContext& ctx)
2056 {
2057   const int reg_used = FindModifiedRegister(REG_BX);
2058   const int value = GetRegister(reg_used);
2059   GetRegister(reg_used) = 0;
2060   m_organism->DoOutput(ctx, value);
2061   return true;
2062 }
2063 
Inst_TaskPutResetInputs(cAvidaContext & ctx)2064 bool cHardwareGX::Inst_TaskPutResetInputs(cAvidaContext& ctx)
2065 {
2066   bool return_value = Inst_TaskPut(ctx);          // Do a normal put
2067   m_organism->GetOrgInterface().ResetInputs(ctx);   // Now re-randomize the inputs this organism sees
2068   m_current->m_input_buf.Clear();               // Also clear their input buffers, or they can still claim
2069                                                   // rewards for numbers no longer in their environment!
2070   return return_value;
2071 }
2072 
Inst_TaskIO(cAvidaContext & ctx)2073 bool cHardwareGX::Inst_TaskIO(cAvidaContext& ctx)
2074 {
2075   const int reg_used = FindModifiedRegister(REG_BX);
2076 
2077   // Do the "put" component
2078   const int value_out = GetRegister(reg_used);
2079   m_organism->DoOutput(ctx, m_current->m_input_buf, m_current->m_output_buf, value_out);  // Check for tasks completed.
2080 
2081   // Do the "get" component
2082   const int value_in = m_organism->GetNextInput(m_current->m_input_pointer);
2083   GetRegister(reg_used) = value_in;
2084   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value_in);  // Check for tasks completed.
2085   return true;
2086 }
2087 
Inst_TaskIO_DecayBonus(cAvidaContext & ctx)2088 bool cHardwareGX::Inst_TaskIO_DecayBonus(cAvidaContext& ctx)
2089 {
2090   (void) Inst_TaskIO(ctx);
2091   m_organism->GetPhenotype().SetCurBonus(m_organism->GetPhenotype().GetCurBonus() * 0.99);
2092   return true;
2093 }
2094 
Inst_TaskIO_Feedback(cAvidaContext & ctx)2095 bool cHardwareGX::Inst_TaskIO_Feedback(cAvidaContext& ctx)
2096 {
2097   const int reg_used = FindModifiedRegister(REG_BX);
2098 
2099   //check cur_bonus before the output
2100   double preOutputBonus = m_organism->GetPhenotype().GetCurBonus();
2101 
2102   // Do the "put" component
2103   const int value_out = GetRegister(reg_used);
2104   m_organism->DoOutput(ctx, m_current->m_input_buf, m_current->m_output_buf, value_out);  // Check for tasks completed.
2105 
2106   //check cur_merit after the output
2107   double postOutputBonus = m_organism->GetPhenotype().GetCurBonus();
2108 
2109   //push the effect of the IO on merit (+,0,-) to the active stack
2110   if (preOutputBonus > postOutputBonus){
2111     StackPush(-1);
2112   }
2113   else if (preOutputBonus == postOutputBonus){
2114     StackPush(0);
2115   }
2116   else if (preOutputBonus < postOutputBonus){
2117     StackPush(1);
2118   }
2119   else {
2120     assert(0);
2121     //Bollocks. There was an error.
2122   }
2123 
2124   // Do the "get" component
2125   const int value_in = m_organism->GetNextInput(m_current->m_input_pointer);
2126   GetRegister(reg_used) = value_in;
2127   m_organism->DoInput(m_current->m_input_buf, m_current->m_output_buf, value_in);  // Check for tasks completed.
2128   return true;
2129 }
2130 
Inst_MatchStrings(cAvidaContext & ctx)2131 bool cHardwareGX::Inst_MatchStrings(cAvidaContext& ctx)
2132 {
2133 	if (m_executedmatchstrings)
2134 		return false;
2135 	m_organism->DoOutput(ctx, 357913941);
2136 	m_executedmatchstrings = true;
2137 	return true;
2138 }
2139 
Inst_Sell(cAvidaContext & ctx)2140 bool cHardwareGX::Inst_Sell(cAvidaContext& ctx)
2141 {
2142 	int search_label = GetLabel().AsInt(3) % MARKET_SIZE;
2143 	int send_value = GetRegister(REG_BX);
2144 	int sell_price = m_world->GetConfig().SELL_PRICE.Get();
2145 	m_organism->SellValue(send_value, search_label, sell_price);
2146 	return true;
2147 }
2148 
Inst_Buy(cAvidaContext & ctx)2149 bool cHardwareGX::Inst_Buy(cAvidaContext& ctx)
2150 {
2151 	int search_label = GetLabel().AsInt(3) % MARKET_SIZE;
2152 	int buy_price = m_world->GetConfig().BUY_PRICE.Get();
2153 	GetRegister(REG_BX) = m_organism->BuyValue(search_label, buy_price);
2154 	return true;
2155 }
2156 
Inst_Send(cAvidaContext & ctx)2157 bool cHardwareGX::Inst_Send(cAvidaContext& ctx)
2158 {
2159   const int reg_used = FindModifiedRegister(REG_BX);
2160   m_organism->SendValue(GetRegister(reg_used));
2161   GetRegister(reg_used) = 0;
2162   return true;
2163 }
2164 
Inst_Receive(cAvidaContext & ctx)2165 bool cHardwareGX::Inst_Receive(cAvidaContext& ctx)
2166 {
2167   const int reg_used = FindModifiedRegister(REG_BX);
2168   GetRegister(reg_used) = m_organism->ReceiveValue();
2169   return true;
2170 }
2171 
Inst_SenseLog2(cAvidaContext & ctx)2172 bool cHardwareGX::Inst_SenseLog2(cAvidaContext& ctx)
2173 {
2174   return DoSense(ctx, 0, 2);
2175 }
2176 
Inst_SenseUnit(cAvidaContext & ctx)2177 bool cHardwareGX::Inst_SenseUnit(cAvidaContext& ctx)
2178 {
2179   return DoSense(ctx, 1, 1);
2180 }
2181 
Inst_SenseMult100(cAvidaContext & ctx)2182 bool cHardwareGX::Inst_SenseMult100(cAvidaContext& ctx)
2183 {
2184   return DoSense(ctx, 1, 100);
2185 }
2186 
DoSense(cAvidaContext & ctx,int conversion_method,double base)2187 bool cHardwareGX::DoSense(cAvidaContext& ctx, int conversion_method, double base)
2188 {
2189   // Returns the log2 amount of a resource or resources
2190   // specified by modifying NOPs into register BX
2191   const tArray<double> res_count = m_organism->GetOrgInterface().GetResources(ctx) +
2192     m_organism->GetOrgInterface().GetDemeResources(m_organism->GetOrgInterface().GetDemeID(), ctx);
2193 
2194   // Arbitrarily set to BX since the conditionals use this directly.
2195   int reg_to_set = REG_BX;
2196 
2197   // There are no resources, return
2198   if (res_count.GetSize() == 0) return false;
2199 
2200   // Only recalculate logs if these values have changed
2201   static int last_num_resources = 0;
2202   static int max_label_length = 0;
2203   int num_nops = GetInstSet().GetNumNops();
2204 
2205   if ((last_num_resources != res_count.GetSize()))
2206   {
2207       max_label_length = (int) ceil(log((double)res_count.GetSize())/log((double)num_nops));
2208       last_num_resources = res_count.GetSize();
2209   }
2210 
2211   // Convert modifying NOPs to the index of the resource.
2212   // If there are fewer than the number of NOPs required
2213   // to uniquely specify a resource, then add together
2214   // a subset of resources (motivation: regulation can evolve
2215   // to be more specific if there is an advantage)
2216 
2217   // Find the maximum number of NOPs needed to specify this number of resources
2218   // Note: It's a bit wasteful to recalculate this every time and organisms will
2219   // definitely be confused if the number of resources changes during a run
2220   // because their mapping to resources will be disrupted
2221 
2222   // Attempt to read a label with this maximum length
2223   cHardwareGX::ReadLabel(max_label_length);
2224 
2225   // Find the length of the label that we actually obtained (max is max_reg_needed)
2226   int real_label_length = GetLabel().GetSize();
2227 
2228   // Start and end labels to define the start and end indices of
2229   // resources that we need to add together
2230   cCodeLabel start_label = cCodeLabel(GetLabel());
2231   cCodeLabel   end_label = cCodeLabel(GetLabel());
2232 
2233   for (int i = 0; i < max_label_length - real_label_length; i++)
2234   {
2235     start_label.AddNop(0);
2236     end_label.AddNop(num_nops-1);
2237   }
2238 
2239   int start_index = start_label.AsInt(num_nops);
2240   int   end_index =   end_label.AsInt(num_nops);
2241 
2242   // If the label refers to ONLY resources that
2243   // do not exist, then the operation fails
2244   if (start_index >= res_count.GetSize()) return false;
2245 
2246   // Otherwise sum all valid resources that it might refer to
2247   // (this will only be ONE if the label was of the maximum length).
2248   int resource_result = 0;
2249   for (int i = start_index; i <= end_index; i++)
2250   {
2251     // if it's a valid resource
2252     if (i < res_count.GetSize())
2253     {
2254       if (conversion_method == 0) // Log2
2255       {
2256         // (alternately you could assign min_int for zero resources, but
2257         // that would cause wierdness when adding sense values together)
2258         if (res_count[i] > 0) resource_result += (int)(log(res_count[i])/log(base));
2259       }
2260       else if (conversion_method == 1) // Addition of multiplied resource amount
2261       {
2262         int add_amount = (int) (res_count[i] * base);
2263         // Do some range checking to make sure we don't overflow
2264         resource_result = (INT_MAX - resource_result <= add_amount) ? INT_MAX : resource_result + add_amount;
2265       }
2266     }
2267   }
2268 
2269   //Dump this value into an arbitrary register: BX
2270   GetRegister(reg_to_set) = resource_result;
2271 
2272   //We have to convert this to a different index that includes all degenerate labels possible: shortest to longest
2273   int sensed_index = 0;
2274   int on = 1;
2275   for (int i = 0; i < real_label_length; i++)
2276   {
2277     sensed_index += on;
2278     on *= num_nops;
2279   }
2280   sensed_index+= GetLabel().AsInt(num_nops);
2281   m_organism->GetPhenotype().IncSenseCount(sensed_index);
2282 
2283   return true;
2284 
2285   // Note that we are converting <double> resources to <int> register values
2286 }
2287 
DoDonate(cOrganism * to_org)2288 void cHardwareGX::DoDonate(cOrganism* to_org)
2289 {
2290   assert(to_org != NULL);
2291 
2292   const double merit_given = m_world->GetConfig().MERIT_GIVEN.Get();
2293   const double merit_received = m_world->GetConfig().MERIT_RECEIVED.Get();
2294 
2295   double cur_merit = m_organism->GetPhenotype().GetMerit().GetDouble();
2296   cur_merit -= merit_given;
2297   if(cur_merit < 0) cur_merit=0;
2298 
2299   // Plug the current merit back into this organism and notify the scheduler.
2300   m_organism->UpdateMerit(cur_merit);
2301 
2302   // Update the merit of the organism being donated to...
2303   double other_merit = to_org->GetPhenotype().GetMerit().GetDouble();
2304   other_merit += merit_received;
2305   to_org->UpdateMerit(other_merit);
2306 }
2307 
Inst_DonateRandom(cAvidaContext & ctx)2308 bool cHardwareGX::Inst_DonateRandom(cAvidaContext& ctx)
2309 {
2310 
2311   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2312     return false;
2313   }
2314 
2315   m_organism->GetPhenotype().IncDonates();
2316   m_organism->GetPhenotype().SetIsDonorRand();
2317 
2318   // Turn to a random neighbor, get it, and turn back...
2319   int neighbor_id = ctx.GetRandom().GetInt(m_organism->GetNeighborhoodSize());
2320   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2321   cOrganism * neighbor = m_organism->GetNeighbor();
2322   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2323 
2324   // Donate only if we have found a neighbor.
2325   if (neighbor != NULL) {
2326     DoDonate(neighbor);
2327     neighbor->GetPhenotype().SetIsReceiverRand();
2328   }
2329 
2330   return true;
2331 }
2332 
2333 
2334 
Inst_DonateEditDist(cAvidaContext & ctx)2335 bool cHardwareGX::Inst_DonateEditDist(cAvidaContext& ctx)
2336 {
2337   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2338     return false;
2339   }
2340 
2341   m_organism->GetPhenotype().IncDonates();
2342   m_organism->GetPhenotype().SetIsDonorEdit();
2343 
2344   // Find the target as the first Kin found in the neighborhood.
2345   const int num_neighbors = m_organism->GetNeighborhoodSize();
2346 
2347   // Turn to face a random neighbor
2348   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
2349   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2350   cOrganism* neighbor = m_organism->GetNeighbor();
2351 
2352   // If there is no max edit distance, take the random neighbor we're facing.
2353   const int max_dist = m_world->GetConfig().MAX_DONATE_EDIT_DIST.Get();
2354   if (max_dist != -1) {
2355     int max_id = neighbor_id + num_neighbors;
2356     bool found = false;
2357     while (neighbor_id < max_id) {
2358       neighbor = m_organism->GetNeighbor();
2359       int edit_dist = max_dist + 1;
2360       if (neighbor != NULL) {
2361         edit_dist = Sequence::FindEditDistance(m_organism->GetGenome().GetSequence(),
2362                                                   neighbor->GetGenome().GetSequence());
2363       }
2364       if (edit_dist <= max_dist) {
2365         found = true;
2366         break;
2367       }
2368       m_organism->Rotate(1);
2369       neighbor_id++;
2370     }
2371     if (found == false) neighbor = NULL;
2372   }
2373 
2374   // Put the facing back where it was.
2375   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2376 
2377   // Donate only if we have found a close enough relative...
2378   if (neighbor != NULL){
2379     DoDonate(neighbor);
2380     neighbor->GetPhenotype().SetIsReceiverEdit();
2381   }
2382   return true;
2383 }
2384 
Inst_DonateGreenBeardGene(cAvidaContext & ctx)2385 bool cHardwareGX::Inst_DonateGreenBeardGene(cAvidaContext& ctx)
2386 {
2387   //this donates to organisms that have this instruction anywhere
2388   //in their genome (see Dawkins 1976, The Selfish Gene, for
2389   //the history of the theory and the name 'green beard'
2390   cPhenotype & phenotype = m_organism->GetPhenotype();
2391 
2392   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2393     return false;
2394   }
2395 
2396   phenotype.IncDonates();
2397   phenotype.SetIsDonorGbg();
2398 
2399   // Find the target as the first match found in the neighborhood.
2400 
2401   //get the neighborhood size
2402   const int num_neighbors = m_organism->GetNeighborhoodSize();
2403 
2404   // Turn to face a random neighbor
2405   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
2406   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2407   cOrganism * neighbor = m_organism->GetNeighbor();
2408 
2409   int max_id = neighbor_id + num_neighbors;
2410 
2411   //we have not found a match yet
2412   bool found = false;
2413 
2414   // rotate through orgs in neighborhood
2415   while (neighbor_id < max_id) {
2416       neighbor = m_organism->GetNeighbor();
2417 
2418       //if neighbor exists, do they have the green beard gene?
2419       if (neighbor != NULL) {
2420           const Sequence & neighbor_genome = neighbor->GetGenome().GetSequence();
2421 
2422           // for each instruction in the genome...
2423           for(int i=0;i<neighbor_genome.GetSize();i++){
2424 
2425             // ...see if it is donate-gbg
2426             if (neighbor_genome[i] == IP().GetInst()) {
2427               found = true;
2428               break;
2429             }
2430 
2431           }
2432       }
2433 
2434       // stop searching through the neighbors if we already found one
2435       if (found == true) break;
2436 
2437       m_organism->Rotate(1);
2438       neighbor_id++;
2439   }
2440 
2441     if (found == false) neighbor = NULL;
2442 
2443   // Put the facing back where it was.
2444   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2445 
2446   // Donate only if we have found a close enough relative...
2447   if (neighbor != NULL) {
2448     DoDonate(neighbor);
2449     neighbor->GetPhenotype().SetIsReceiverGbg();
2450   }
2451 
2452   return true;
2453 
2454 }
2455 
Inst_DonateTrueGreenBeard(cAvidaContext & ctx)2456 bool cHardwareGX::Inst_DonateTrueGreenBeard(cAvidaContext& ctx)
2457 {
2458   //this donates to organisms that have this instruction anywhere
2459   //in their genome AND their parents excuted it
2460   //(see Dawkins 1976, The Selfish Gene, for
2461   //the history of the theory and the name 'green beard'
2462   //  cout << "i am about to donate to a green beard" << endl;
2463   cPhenotype & phenotype = m_organism->GetPhenotype();
2464 
2465   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2466     return false;
2467   }
2468 
2469   phenotype.IncDonates();
2470   phenotype.SetIsDonorTrueGb();
2471 
2472   // Find the target as the first match found in the neighborhood.
2473 
2474   //get the neighborhood size
2475   const int num_neighbors = m_organism->GetNeighborhoodSize();
2476 
2477   // Turn to face a random neighbor
2478   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
2479   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2480   cOrganism * neighbor = m_organism->GetNeighbor();
2481 
2482   int max_id = neighbor_id + num_neighbors;
2483 
2484   //we have not found a match yet
2485   bool found = false;
2486 
2487   // rotate through orgs in neighborhood
2488   while (neighbor_id < max_id) {
2489       neighbor = m_organism->GetNeighbor();
2490       //if neighbor exists, AND if their parent attempted to donate,
2491       if (neighbor != NULL && neighbor->GetPhenotype().IsDonorTrueGbLast()) {
2492           const Sequence& neighbor_genome = neighbor->GetGenome().GetSequence();
2493 
2494           // for each instruction in the genome...
2495           for(int i=0;i<neighbor_genome.GetSize();i++){
2496 
2497             // ...see if it is donate-tgb, if so, we found a target
2498             if (neighbor_genome[i] == IP().GetInst()) {
2499               found = true;
2500               break;
2501             }
2502 
2503           }
2504       }
2505 
2506       // stop searching through the neighbors if we already found one
2507       if (found == true) break;
2508 
2509       m_organism->Rotate(1);
2510       neighbor_id++;
2511   }
2512 
2513     if (found == false) neighbor = NULL;
2514 
2515   // Put the facing back where it was.
2516   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2517 
2518   // Donate only if we have found a close enough relative...
2519   if (neighbor != NULL) {
2520     DoDonate(neighbor);
2521     neighbor->GetPhenotype().SetIsReceiverTrueGb();
2522   }
2523 
2524 
2525   return true;
2526 
2527 }
2528 
Inst_DonateThreshGreenBeard(cAvidaContext & ctx)2529 bool cHardwareGX::Inst_DonateThreshGreenBeard(cAvidaContext& ctx)
2530 {
2531   //this donates to organisms that have this instruction anywhere
2532   //in their genome AND their parents excuted it >=THRESHOLD number of times
2533   //(see Dawkins 1976, The Selfish Gene, for
2534   //the history of the theory and the name 'green beard'
2535   //  cout << "i am about to donate to a green beard" << endl;
2536   cPhenotype & phenotype = m_organism->GetPhenotype();
2537 
2538   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2539     return false;
2540   }
2541 
2542 
2543   phenotype.IncDonates();
2544   phenotype.SetIsDonorThreshGb();
2545   phenotype.IncNumThreshGbDonations();
2546 
2547   // Find the target as the first match found in the neighborhood.
2548 
2549   //get the neighborhood size
2550   const int num_neighbors = m_organism->GetNeighborhoodSize();
2551 
2552   // Turn to face a random neighbor
2553   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
2554   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2555   cOrganism * neighbor = m_organism->GetNeighbor();
2556 
2557   int max_id = neighbor_id + num_neighbors;
2558 
2559   //we have not found a match yet
2560   bool found = false;
2561 
2562   // rotate through orgs in neighborhood
2563   while (neighbor_id < max_id) {
2564       neighbor = m_organism->GetNeighbor();
2565       //if neighbor exists, AND if their parent attempted to donate >= threshhold,
2566       if (neighbor != NULL && neighbor->GetPhenotype().GetNumThreshGbDonationsLast()>= m_world->GetConfig().MIN_GB_DONATE_THRESHOLD.Get() ) {
2567           const Sequence & neighbor_genome = neighbor->GetGenome().GetSequence();
2568 
2569           // for each instruction in the genome...
2570           for(int i=0;i<neighbor_genome.GetSize();i++){
2571 
2572 	         // ...see if it is donate-threshgb, if so, we found a target
2573             if (neighbor_genome[i] == IP().GetInst()) {
2574               found = true;
2575               break;
2576             }
2577 
2578           }
2579       }
2580 
2581       // stop searching through the neighbors if we already found one
2582       if (found == true) break;
2583 
2584       m_organism->Rotate(1);
2585       neighbor_id++;
2586   }
2587 
2588     if (found == false) neighbor = NULL;
2589 
2590   // Put the facing back where it was.
2591   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2592 
2593   // Donate only if we have found a close enough relative...
2594   if (neighbor != NULL) {
2595     DoDonate(neighbor);
2596     neighbor->GetPhenotype().SetIsReceiverThreshGb();
2597     // cout << "************ neighbor->GetPhenotype().GetNumThreshGbDonationsLast() is " << neighbor->GetPhenotype().GetNumThreshGbDonationsLast() << endl;
2598 
2599   }
2600 
2601   return true;
2602 
2603 }
2604 
2605 
Inst_DonateQuantaThreshGreenBeard(cAvidaContext & ctx)2606 bool cHardwareGX::Inst_DonateQuantaThreshGreenBeard(cAvidaContext& ctx)
2607 {
2608   // this donates to organisms that have this instruction anywhere in their
2609   // genome AND their parents excuted it more than a THRESHOLD number of times
2610   // where that threshold depend on the number of times the individual's
2611   // parents attempted to donate using this instruction.  The threshold levels
2612   // are multiples of the quanta value set in avida.cfg, and the highest level
2613   // that the donor qualifies for is the one used.
2614 
2615   // (see Dawkins 1976, The Selfish Gene, for the history of the theory and
2616   // the name 'green beard'
2617   //  cout << "i am about to donate to a green beard" << endl;
2618   cPhenotype & phenotype = m_organism->GetPhenotype();
2619 
2620   if (phenotype.GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2621     return false;
2622   }
2623 
2624   phenotype.IncDonates();
2625   phenotype.SetIsDonorQuantaThreshGb();
2626   phenotype.IncNumQuantaThreshGbDonations();
2627   //cout << endl << "quanta_threshgb attempt.. " ;
2628 
2629 
2630   // Find the target as the first match found in the neighborhood.
2631 
2632   //get the neighborhood size
2633   const int num_neighbors = m_organism->GetNeighborhoodSize();
2634 
2635   // Turn to face a random neighbor
2636   int neighbor_id = ctx.GetRandom().GetInt(num_neighbors);
2637   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(1);
2638   cOrganism * neighbor = m_organism->GetNeighbor();
2639 
2640   int max_id = neighbor_id + num_neighbors;
2641 
2642   //we have not found a match yet
2643   bool found = false;
2644 
2645   // Get the quanta (step size) between threshold levels.
2646   const int donate_quanta = m_world->GetConfig().DONATE_THRESH_QUANTA.Get();
2647 
2648   // Calculate what quanta level we should be at for this individual.  We do a
2649   // math trick to make sure its the next lowest event multiple of donate_quanta.
2650   const int quanta_donate_thresh =
2651     (phenotype.GetNumQuantaThreshGbDonationsLast() / donate_quanta) * donate_quanta;
2652   //cout << " phenotype.GetNumQuantaThreshGbDonationsLast() is " << phenotype.GetNumQuantaThreshGbDonationsLast();
2653   //cout << " quanta thresh=  " << quanta_donate_thresh;
2654   // rotate through orgs in neighborhood
2655   while (neighbor_id < max_id) {
2656       neighbor = m_organism->GetNeighbor();
2657       //if neighbor exists, AND if their parent attempted to donate >= threshhold,
2658       if (neighbor != NULL &&
2659 	  neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast() >= quanta_donate_thresh) {
2660 
2661           const Sequence & neighbor_genome = neighbor->GetGenome().GetSequence();
2662 
2663           // for each instruction in the genome...
2664           for(int i=0;i<neighbor_genome.GetSize();i++){
2665 
2666 	         // ...see if it is donate-quantagb, if so, we found a target
2667             if (neighbor_genome[i] == IP().GetInst()) {
2668               found = true;
2669               break;
2670             }
2671 
2672           }
2673       }
2674 
2675       // stop searching through the neighbors if we already found one
2676       if (found == true) break;
2677 
2678       m_organism->Rotate(1);
2679       neighbor_id++;
2680   }
2681 
2682     if (found == false) neighbor = NULL;
2683 
2684   // Put the facing back where it was.
2685   for (int i = 0; i < neighbor_id; i++) m_organism->Rotate(-1);
2686 
2687   // Donate only if we have found a close enough relative...
2688   if (neighbor != NULL) {
2689     DoDonate(neighbor);
2690     neighbor->GetPhenotype().SetIsReceiverQuantaThreshGb();
2691     //cout << " ************ neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast() is " << neighbor->GetPhenotype().GetNumQuantaThreshGbDonationsLast();
2692 
2693   }
2694 
2695   return true;
2696 
2697 }
2698 
2699 
Inst_DonateNULL(cAvidaContext & ctx)2700 bool cHardwareGX::Inst_DonateNULL(cAvidaContext& ctx)
2701 {
2702   if (m_organism->GetPhenotype().GetCurNumDonates() > m_world->GetConfig().MAX_DONATES.Get()) {
2703     return false;
2704   }
2705 
2706   m_organism->GetPhenotype().IncDonates();
2707   m_organism->GetPhenotype().SetIsDonorNull();
2708 
2709   // This is a fake donate command that causes the organism to lose merit,
2710   // but no one else to gain any.
2711 
2712   const double merit_given = m_world->GetConfig().MERIT_GIVEN.Get();
2713   double cur_merit = m_organism->GetPhenotype().GetMerit().GetDouble();
2714   cur_merit -= merit_given;
2715 
2716   // Plug the current merit back into this organism and notify the scheduler.
2717   m_organism->UpdateMerit(cur_merit);
2718 
2719   return true;
2720 }
2721 
2722 
Inst_SearchF(cAvidaContext & ctx)2723 bool cHardwareGX::Inst_SearchF(cAvidaContext& ctx)
2724 {
2725   ReadLabel();
2726   GetLabel().Rotate(1, NUM_NOPS);
2727   const int search_size = FindLabel(1).GetPosition() - IP().GetPosition();
2728   GetRegister(REG_BX) = search_size;
2729   GetRegister(REG_CX) = GetLabel().GetSize();
2730   return true;
2731 }
2732 
Inst_SearchB(cAvidaContext & ctx)2733 bool cHardwareGX::Inst_SearchB(cAvidaContext& ctx)
2734 {
2735   ReadLabel();
2736   GetLabel().Rotate(1, NUM_NOPS);
2737   const int search_size = IP().GetPosition() - FindLabel(-1).GetPosition();
2738   GetRegister(REG_BX) = search_size;
2739   GetRegister(REG_CX) = GetLabel().GetSize();
2740   return true;
2741 }
2742 
Inst_MemSize(cAvidaContext & ctx)2743 bool cHardwareGX::Inst_MemSize(cAvidaContext& ctx)
2744 {
2745   GetRegister(FindModifiedRegister(REG_BX)) = GetMemory().GetSize();
2746   return true;
2747 }
2748 
2749 
Inst_RotateL(cAvidaContext & ctx)2750 bool cHardwareGX::Inst_RotateL(cAvidaContext& ctx)
2751 {
2752   const int num_neighbors = m_organism->GetNeighborhoodSize();
2753 
2754   // If this organism has no neighbors, ignore rotate.
2755   if (num_neighbors == 0) return false;
2756 
2757   ReadLabel();
2758 
2759   // Always rotate at least once.
2760   m_organism->Rotate(-1);
2761 
2762   // If there is no label, then the one rotation was all we want.
2763   if (!GetLabel().GetSize()) return true;
2764 
2765   // Rotate until a complement label is found (or all have been checked).
2766   GetLabel().Rotate(1, NUM_NOPS);
2767   for (int i = 1; i < num_neighbors; i++) {
2768     cOrganism* neighbor = m_organism->GetNeighbor();
2769 
2770     if (neighbor != NULL && neighbor->GetHardware().FindLabelFull(GetLabel()).InMemory()) return true;
2771 
2772     // Otherwise keep rotating...
2773     m_organism->Rotate(-1);
2774   }
2775   return true;
2776 }
2777 
Inst_RotateR(cAvidaContext & ctx)2778 bool cHardwareGX::Inst_RotateR(cAvidaContext& ctx)
2779 {
2780   const int num_neighbors = m_organism->GetNeighborhoodSize();
2781 
2782   // If this m_organism has no neighbors, ignore rotate.
2783   if (num_neighbors == 0) return false;
2784 
2785   ReadLabel();
2786 
2787   // Always rotate at least once.
2788   m_organism->Rotate(1);
2789 
2790   // If there is no label, then the one rotation was all we want.
2791   if (!GetLabel().GetSize()) return true;
2792 
2793   // Rotate until a complement label is found (or all have been checked).
2794   GetLabel().Rotate(1, NUM_NOPS);
2795   for (int i = 1; i < num_neighbors; i++) {
2796     cOrganism* neighbor = m_organism->GetNeighbor();
2797 
2798     if (neighbor != NULL && neighbor->GetHardware().FindLabelFull(GetLabel()).InMemory()) return true;
2799 
2800     // Otherwise keep rotating...
2801     m_organism->Rotate(1);
2802   }
2803   return true;
2804 }
2805 
Inst_SetCopyMut(cAvidaContext & ctx)2806 bool cHardwareGX::Inst_SetCopyMut(cAvidaContext& ctx)
2807 {
2808   const int reg_used = FindModifiedRegister(REG_BX);
2809   const int new_mut_rate = Max(GetRegister(reg_used), 1 );
2810   m_organism->SetCopyMutProb(static_cast<double>(new_mut_rate) / 10000.0);
2811   return true;
2812 }
2813 
Inst_ModCopyMut(cAvidaContext & ctx)2814 bool cHardwareGX::Inst_ModCopyMut(cAvidaContext& ctx)
2815 {
2816   const int reg_used = FindModifiedRegister(REG_BX);
2817   const double new_mut_rate = m_organism->GetCopyMutProb() + static_cast<double>(GetRegister(reg_used)) / 10000.0;
2818   if (new_mut_rate > 0.0) m_organism->SetCopyMutProb(new_mut_rate);
2819   return true;
2820 }
2821 
2822 // Energy use
2823 
Inst_ZeroEnergyUsed(cAvidaContext & ctx)2824 bool cHardwareGX::Inst_ZeroEnergyUsed(cAvidaContext& ctx)
2825 {
2826   // Typically, this instruction should be triggered by a REACTION
2827   m_organism->GetPhenotype().SetTimeUsed(0);
2828   return true;
2829 }
2830 
2831 
2832 // Head-based instructions
2833 
2834 //bool cHardwareGX::Inst_SetHead(cAvidaContext& ctx)
2835 //{
2836 //  const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2837 //  m_threads[m_cur_thread].cur_head = static_cast<unsigned char>(head_used);
2838 //  return true;
2839 //}
2840 
Inst_AdvanceHead(cAvidaContext & ctx)2841 bool cHardwareGX::Inst_AdvanceHead(cAvidaContext& ctx)
2842 {
2843   const int head_used = FindModifiedHead(nHardware::HEAD_WRITE);
2844   GetHead(head_used).Advance();
2845   return true;
2846 }
2847 
Inst_MoveHead(cAvidaContext & ctx)2848 bool cHardwareGX::Inst_MoveHead(cAvidaContext& ctx)
2849 {
2850   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2851   const int target = nHardware::HEAD_FLOW;
2852   GetHead(head_used).Set(GetHead(target));
2853   if (head_used == nHardware::HEAD_IP) m_advance_ip = false;
2854   return true;
2855 }
2856 
Inst_JumpHead(cAvidaContext & ctx)2857 bool cHardwareGX::Inst_JumpHead(cAvidaContext& ctx)
2858 {
2859   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2860   GetHead(head_used).Jump(GetRegister(REG_CX) );
2861   // JEB - probably shouldn't advance inst ptr after jumping here?
2862   // Any negative number jumps to the beginning of the genome (pos 0)
2863   // and then we immediately advance past that first instruction.
2864   return true;
2865 }
2866 
Inst_GetHead(cAvidaContext & ctx)2867 bool cHardwareGX::Inst_GetHead(cAvidaContext& ctx)
2868 {
2869   const int head_used = FindModifiedHead(nHardware::HEAD_IP);
2870   GetRegister(REG_CX) = GetHead(head_used).GetPosition();
2871   return true;
2872 }
2873 
Inst_IfLabel(cAvidaContext & ctx)2874 bool cHardwareGX::Inst_IfLabel(cAvidaContext& ctx)
2875 {
2876   ReadLabel();
2877   GetLabel().Rotate(1, NUM_NOPS);
2878   if (GetLabel() != GetReadLabel())  IP().Advance();
2879   return true;
2880 }
2881 
2882 // This is a variation on IfLabel that will skip the next command if the "if"
2883 // is false, but it will also skip all nops following that command.
Inst_IfLabel2(cAvidaContext & ctx)2884 bool cHardwareGX::Inst_IfLabel2(cAvidaContext& ctx)
2885 {
2886   ReadLabel();
2887   GetLabel().Rotate(1, NUM_NOPS);
2888   if (GetLabel() != GetReadLabel()) {
2889     IP().Advance();
2890     if (m_inst_set->IsNop( IP().GetNextInst() ))  IP().Advance();
2891   }
2892   return true;
2893 }
2894 
2895 
Inst_HeadDivide(cAvidaContext & ctx)2896 bool cHardwareGX::Inst_HeadDivide(cAvidaContext& ctx)
2897 {
2898   return Divide_Main(ctx);
2899 }
2900 
2901 
Inst_HeadRead(cAvidaContext & ctx)2902 bool cHardwareGX::Inst_HeadRead(cAvidaContext& ctx)
2903 {
2904   const int dst = REG_BX;
2905 
2906   const int head_id = FindModifiedHead(nHardware::HEAD_READ);
2907   GetHead(head_id).Adjust();
2908 
2909     // <--- GX addition
2910   if ( !m_programids[GetHead(head_id).GetMemSpace()]->GetReadable() ) return false;
2911   // --->
2912 
2913   // Mutations only occur on the read, for the moment.
2914   int read_inst = 0;
2915   if (m_organism->TestCopyMut(ctx)) {
2916     read_inst = m_inst_set->GetRandomInst(ctx).GetOp();
2917   } else {
2918     read_inst = GetHead(head_id).GetInst().GetOp();
2919   }
2920   GetRegister(dst) = read_inst;
2921   ReadInst(read_inst);
2922 
2923   GetHead(head_id).Advance();
2924   return true;
2925 }
2926 
Inst_HeadWrite(cAvidaContext & ctx)2927 bool cHardwareGX::Inst_HeadWrite(cAvidaContext& ctx)
2928 {
2929   const int src = REG_BX;
2930   const int head_id = FindModifiedHead(nHardware::HEAD_WRITE);
2931   cHeadCPU& active_head = GetHead(head_id);
2932 
2933   // <--- GX addition
2934   if ( !m_programids[GetHead(head_id).GetMemSpace()]->GetReadable() ) return false;
2935   // --->
2936 
2937   active_head.Adjust();
2938 
2939   int value = GetRegister(src);
2940   if (value < 0 || value >= m_inst_set->GetSize()) value = 0;
2941 
2942   active_head.SetInst(cInstruction(value));
2943   active_head.SetFlagCopied();
2944 
2945   // Advance the head after write...
2946   active_head++;
2947   return true;
2948 }
2949 
Inst_HeadCopy(cAvidaContext & ctx)2950 bool cHardwareGX::Inst_HeadCopy(cAvidaContext& ctx)
2951 {
2952   // For the moment, this cannot be nop-modified.
2953   cHeadCPU& read_head = GetHead(nHardware::HEAD_READ);
2954   cHeadCPU& write_head = GetHead(nHardware::HEAD_WRITE);
2955 
2956   read_head.Adjust();
2957   write_head.Adjust();
2958 
2959   // Do mutations.
2960   cInstruction read_inst = read_head.GetInst();
2961   ReadInst(read_inst.GetOp());
2962   if (m_organism->TestCopyMut(ctx)) {
2963     read_inst = m_inst_set->GetRandomInst(ctx);
2964     write_head.SetFlagMutated();
2965     write_head.SetFlagCopyMut();
2966   }
2967 
2968   write_head.SetInst(read_inst);
2969   write_head.SetFlagCopied();  // Set the copied flag...
2970 
2971   read_head.Advance();
2972   write_head.Advance();
2973   return true;
2974 }
2975 
HeadCopy_ErrorCorrect(cAvidaContext & ctx,double reduction)2976 bool cHardwareGX::HeadCopy_ErrorCorrect(cAvidaContext& ctx, double reduction)
2977 {
2978   // For the moment, this cannot be nop-modified.
2979   cHeadCPU & read_head = GetHead(nHardware::HEAD_READ);
2980   cHeadCPU & write_head = GetHead(nHardware::HEAD_WRITE);
2981 
2982   read_head.Adjust();
2983   write_head.Adjust();
2984 
2985   // Do mutations.
2986   cInstruction read_inst = read_head.GetInst();
2987   ReadInst(read_inst.GetOp());
2988   if ( ctx.GetRandom().P(m_organism->GetCopyMutProb() / reduction) ) {
2989     read_inst = m_inst_set->GetRandomInst(ctx);
2990     write_head.SetFlagMutated();
2991     write_head.SetFlagCopyMut();
2992   }
2993 
2994   write_head.SetInst(read_inst);
2995   write_head.SetFlagCopied();  // Set the copied flag...
2996 
2997   read_head.Advance();
2998   write_head.Advance();
2999   return true;
3000 }
3001 
Inst_HeadCopy2(cAvidaContext & ctx)3002 bool cHardwareGX::Inst_HeadCopy2(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 2); }
Inst_HeadCopy3(cAvidaContext & ctx)3003 bool cHardwareGX::Inst_HeadCopy3(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 3); }
Inst_HeadCopy4(cAvidaContext & ctx)3004 bool cHardwareGX::Inst_HeadCopy4(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 4); }
Inst_HeadCopy5(cAvidaContext & ctx)3005 bool cHardwareGX::Inst_HeadCopy5(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 5); }
Inst_HeadCopy6(cAvidaContext & ctx)3006 bool cHardwareGX::Inst_HeadCopy6(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 6); }
Inst_HeadCopy7(cAvidaContext & ctx)3007 bool cHardwareGX::Inst_HeadCopy7(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 7); }
Inst_HeadCopy8(cAvidaContext & ctx)3008 bool cHardwareGX::Inst_HeadCopy8(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 8); }
Inst_HeadCopy9(cAvidaContext & ctx)3009 bool cHardwareGX::Inst_HeadCopy9(cAvidaContext& ctx)  { return HeadCopy_ErrorCorrect(ctx, 9); }
Inst_HeadCopy10(cAvidaContext & ctx)3010 bool cHardwareGX::Inst_HeadCopy10(cAvidaContext& ctx) { return HeadCopy_ErrorCorrect(ctx, 10); }
3011 
Inst_HeadSearch(cAvidaContext & ctx)3012 bool cHardwareGX::Inst_HeadSearch(cAvidaContext& ctx)
3013 {
3014   ReadLabel();
3015   GetLabel().Rotate(1, NUM_NOPS);
3016   cHeadCPU found_pos = FindLabel(0);
3017   const int search_size = found_pos.GetPosition() - IP().GetPosition();
3018   GetRegister(REG_BX) = search_size;
3019   GetRegister(REG_CX) = GetLabel().GetSize();
3020   GetHead(nHardware::HEAD_FLOW).Set(found_pos);
3021   GetHead(nHardware::HEAD_FLOW).Advance();
3022   return true;
3023 }
3024 
Inst_SetFlow(cAvidaContext & ctx)3025 bool cHardwareGX::Inst_SetFlow(cAvidaContext& ctx)
3026 {
3027   const int reg_used = FindModifiedRegister(REG_CX);
3028   GetHead(nHardware::HEAD_FLOW).Set(GetRegister(reg_used));
3029 return true;
3030 }
3031 
3032 //// Placebo insts ////
Inst_Skip(cAvidaContext & ctx)3033 bool cHardwareGX::Inst_Skip(cAvidaContext& ctx)
3034 {
3035   IP().Advance();
3036   return true;
3037 }
3038 
3039 /*! This instruction allocates a new programid with a zero length genome
3040 and moves the write head of the current programid to it.
3041 */
Inst_NewProgramid(cAvidaContext & ctx,bool executable,bool bindable,bool readable)3042 bool cHardwareGX::Inst_NewProgramid(cAvidaContext& ctx, bool executable, bool bindable, bool readable)
3043 {
3044   m_reset_inputs = true;
3045 
3046   // Do some maintenance on the programid where the write head was previously.
3047   // (1) Adjust the number of heads on it; this could make it executable!
3048   // (2) \todo Delete if it has no instructions or is below a certain size?
3049   int write_head_contacted = GetHead(nHardware::HEAD_WRITE).GetMemSpace();
3050   m_programids[write_head_contacted]->RemoveContactingHead(GetHead(nHardware::HEAD_WRITE));
3051   GetHead(nHardware::HEAD_WRITE).Set(0, m_current->m_id); // Immediately set the write head back to itself
3052 
3053   // If we've reached a programid limit, then deal with that
3054   if ( (int)m_programids.size() >= m_world->GetConfig().MAX_PROGRAMIDS.Get() ) {
3055 
3056     //Decide on a programid to destroy, currently highest number of cpu cycles executed
3057     //\todo more methods of choosing..
3058 
3059     if (PROGRAMID_REPLACEMENT_METHOD == 0) {
3060       // Don't replace (they can still die of old age!)
3061       return false;
3062     } else if(PROGRAMID_REPLACEMENT_METHOD == 1) {
3063       // Replace oldest programid
3064       int destroy_index = -1;
3065       int max_cpu_cycles_used = -1;
3066       for (unsigned int i=0; i<m_programids.size(); i++) {
3067         if (m_programids[i]->GetCPUCyclesUsed() > max_cpu_cycles_used) {
3068           max_cpu_cycles_used = m_programids[i]->GetCPUCyclesUsed();
3069           destroy_index = i;
3070         }
3071       }
3072       assert(destroy_index>=0);
3073       RemoveProgramid(destroy_index);
3074 
3075       // Also replace anything that its WRITE head contacted (unless itself)...
3076       // to prevent accumulating partially copied programids
3077       if(write_head_contacted != destroy_index) {
3078         RemoveProgramid(write_head_contacted);
3079       }
3080     }
3081   }
3082 
3083   // Create the new programid and add it to the list
3084   Sequence new_genome(1);
3085   programid_ptr new_programid = new cProgramid(new_genome, this);
3086   new_programid->m_executable = executable;
3087   new_programid->m_bindable = bindable;
3088   new_programid->m_readable = readable;
3089   AddProgramid(new_programid);
3090 
3091   // Set the write head to the newly allocated programid
3092   new_programid->AddContactingHead(GetHead(nHardware::HEAD_WRITE));
3093   GetHead(nHardware::HEAD_WRITE).Set(0, new_programid->GetID());
3094 
3095   return true;
3096 }
3097 
Inst_Site(cAvidaContext & ctx)3098 bool cHardwareGX::Inst_Site(cAvidaContext& ctx)
3099 {
3100   // Do nothing except move past the label
3101   ReadLabel();
3102   return true;
3103 }
3104 
3105 /*! This instruction reads the trailing label and tries to match it against other
3106 programids in the CPU.  Note: labels that follow a match instruction in the
3107 programid to be matched against are *ignored*.  Note that match should be a
3108 'free' instruction, that is, it should not cost anything to execute.
3109 
3110 \todo Determine if Inst_Match should wait for a match, as opposed to letting the
3111 cProgramid continue.  This seems like a good idea...
3112 
3113 \todo Have to determine the correct placement of the heads on Bind.  If we're not
3114 careful, we'll allow two RNAPs to bind to each other and start copying each other's
3115 genome.  Probably a bad idea. @JEB Well, at least those selfish solutions would die.
3116 Temp Soln @JEB -- added a flag to programids so that only certain programids are bindable
3117 */
Inst_Bind(cAvidaContext & ctx)3118 bool cHardwareGX::Inst_Bind(cAvidaContext& ctx)
3119 {
3120   m_reset_inputs = true;
3121 
3122   // Get the label that we're trying to match.
3123   // Do this first to advance IP past it.
3124   ReadLabel();
3125 
3126   // Binding fails if we are already bound!
3127   cHeadProgramid& read = GetHead(nHardware::HEAD_READ);
3128   if(read.GetMemSpace() != m_current->GetID()) return false;
3129   cHeadProgramid& write = GetHead(nHardware::HEAD_WRITE);
3130 
3131   // Now, select another programid to match against.
3132   // Go through all *other* programids looking for matches
3133   std::vector<cMatchSite> all_matches;
3134   for(programid_list::iterator i=m_programids.begin(); i!=m_programids.end(); ++i) {
3135     // Don't bind to ourself, or to whatever programid our write head is attached to.
3136     if((*i != m_current) && ((*i)->GetID() != write.GetMemSpace())) {
3137       std::vector<cMatchSite> matches = (*i)->Sites(GetLabel());
3138       all_matches.insert(all_matches.end(), matches.begin(), matches.end());
3139     }
3140   }
3141 
3142   // The instruction failed if there were no matches
3143   if(all_matches.size() == 0) return false;
3144 
3145   // Otherwise set the read head to a random match
3146   unsigned int c = ctx.GetRandom().GetUInt(all_matches.size());
3147 
3148   // Ok, it matched.  Bind the current programid's read head to the matched site.
3149   m_current->Bind(nHardware::HEAD_READ, all_matches[c]);
3150 
3151   // And we're done.
3152   return true;
3153 }
3154 
3155 
3156 /*! This instruction attempts to locate two programids that have the same site.
3157 If two such programids are found, BX is set to 2, otherwise BX is set to 0.
3158 
3159 This instruction is well-suited for finding two genomes.  For example, the following
3160 instruction sequence may be used to locate two genomes with an origin of replication,
3161 and if found, trigger a cell division:
3162 bind2
3163 nop-B
3164 nop-C
3165 if-not-0
3166 p-divide
3167 */
Inst_Bind2(cAvidaContext & ctx)3168 bool cHardwareGX::Inst_Bind2(cAvidaContext& ctx)
3169 {
3170   m_reset_inputs = true;
3171 
3172   // Get the label we're searching for.
3173   ReadLabel();
3174 
3175   // Search for matches to this label.
3176   std::vector<cMatchSite> bindable;
3177   for(programid_list::iterator i=m_programids.begin(); i!=m_programids.end(); ++i) {
3178     if(*i != m_current) {
3179       std::vector<cMatchSite> matches = (*i)->Sites(GetLabel());
3180       // Now, we only want one match from each programid; we'll take a random one.
3181       if(matches.size()>0) {
3182         bindable.push_back(matches[ctx.GetRandom().GetInt(matches.size())]);
3183       }
3184     }
3185   }
3186 
3187   // Select two of the matches at random.
3188   if(bindable.size()>=2) {
3189     int first = ctx.GetRandom().GetInt(bindable.size());
3190     int second = ctx.GetRandom().GetInt(bindable.size());
3191     while(first == second) { second = ctx.GetRandom().GetUInt(bindable.size()); }
3192     assert(bindable[first].m_programid->GetID() != bindable[second].m_programid->GetID());
3193     assert(bindable[first].m_programid->GetBindable());
3194     assert(bindable[second].m_programid->GetBindable());
3195     assert(bindable[first].m_programid->GetReadable());
3196     assert(bindable[second].m_programid->GetReadable());
3197 
3198     // If the caller is already bound to other programids, detach.
3199     m_current->Detach();
3200 
3201     // And attach this programid's read and write heads to the indexed organisms.
3202     // It *is* possible that the caller could do "bad things" now.
3203     m_current->Bind(nHardware::HEAD_READ, bindable[first]);
3204     m_current->Bind(nHardware::HEAD_WRITE, bindable[second]);
3205 
3206     // Finally, set BX to indicate that bind2 worked, and return.
3207     GetRegister(REG_BX) = 2;
3208     return true;
3209   }
3210 
3211   // Bind2 didn't work.
3212   GetRegister(REG_BX) = 0;
3213   return false;
3214 }
3215 
3216 
Inst_IfBind(cAvidaContext & ctx)3217 bool cHardwareGX::Inst_IfBind(cAvidaContext& ctx)
3218 {
3219   // Normal Bind
3220   bool ret = Inst_Bind(ctx);
3221 
3222   //Skip the next instruction if binding was not successful
3223   if (!ret) IP().Advance();
3224 
3225   return ret;
3226 }
3227 
3228 
Inst_IfBind2(cAvidaContext & ctx)3229 bool cHardwareGX::Inst_IfBind2(cAvidaContext& ctx)
3230 {
3231   // Normal Bind2
3232   bool ret = Inst_Bind2(ctx);
3233 
3234   //Skip the next instruction if binding was not successful
3235   if (!ret) IP().Advance();
3236 
3237   return ret;
3238 }
3239 
3240 
3241 /*! This instruction puts the total number of binding sites found in BX
3242 Currently it is used to keep track of whether genome division has completed.*/
Inst_NumSites(cAvidaContext & ctx)3243 bool cHardwareGX::Inst_NumSites(cAvidaContext& ctx)
3244 {
3245   // Get the label that we're trying to match.
3246   ReadLabel();
3247 
3248   // Go through all *other* programids counting matches
3249   int num_sites = 0;
3250   for(programid_list::iterator i=m_programids.begin(); i!=m_programids.end(); ++i) {
3251     if (*i != m_current) {
3252       num_sites += (*i)->Sites(GetLabel()).size();
3253     }
3254   }
3255 
3256   GetRegister(REG_BX) = num_sites;
3257   return true;
3258 }
3259 
3260 
3261 /*! This instruction is like h-copy, except:
3262 (1) It does nothing if the read and write head are not on OTHER programids
3263 (2) It dissociates the read head if it encounters the complement of the label that was used in the
3264     match instruction that put the read head on its current target
3265 */
Inst_ProgramidCopy(cAvidaContext & ctx)3266 bool cHardwareGX::Inst_ProgramidCopy(cAvidaContext& ctx)
3267 {
3268   m_reset_inputs = true;
3269 
3270   cHeadProgramid& write = GetHead(nHardware::HEAD_WRITE);
3271   cHeadProgramid& read = GetHead(nHardware::HEAD_READ);
3272   read.Adjust(); // Strange things can happen (like we're reading from a programid that was being written).
3273   write.Adjust(); // Always adjust if the memory spaces themselves are accessed.
3274 
3275   // Don't copy if this programid's write or read head is on itself
3276   if(read.GetMemSpace() == m_current->GetID()) return false;
3277   if(write.GetMemSpace() == m_current->GetID()) return false;
3278 
3279   // Don't copy if the source is not readable
3280   if(!m_programids[read.GetMemSpace()]->GetReadable()) return false;
3281 
3282   // If a copy is mutated in after a bind2, then the read head could be at the
3283   // end of a genome.  The copy fails, and we should probably break the bind, too.
3284   if(read.GetPosition() >= read.GetMemory().GetSize()) {
3285     m_current->Detach();
3286     return false;
3287   }
3288 
3289   // Keep track of whether the last non-NOP we copied was a site
3290   if(GetInstSet().IsNop(read.GetInst())) {
3291     m_current->m_copying_label.AddNop(GetInstSet().GetNopMod(read.GetInst()));
3292   } else {
3293     m_current->m_copying_site = (read.GetInst() == GetInstSet().GetInst("site"));
3294     m_current->m_copying_label.Clear();
3295   }
3296 
3297   // Allocate space for one additional instruction if the write head is at the end
3298   if(write.GetMemory().GetSize() == write.GetPosition() + 1) {
3299     write.GetMemory().Resize(write.GetMemory().GetSize() + 1);
3300   }
3301 
3302   // \todo The timing of deletion, change, insertion mutation checks matters
3303   // I'm not sure this is right @JEB
3304 
3305   bool ret = true;
3306   // Normal h-copy, unless a deletion occured
3307   if (!m_organism->TestDivideDel(ctx)) {
3308       // Normal h-copy
3309     ret = Inst_HeadCopy(ctx);
3310   }
3311 
3312   // Divide Insertion
3313   if (m_organism->TestDivideIns(ctx)) {
3314     write.GetMemory().Insert(write.GetPosition(), GetInstSet().GetRandomInst(ctx));
3315     // Advance the write head;
3316     write++;
3317   }
3318 
3319   // "Jump" Mutations
3320 
3321   if ( ctx.GetRandom().P(0.0000) )
3322   {
3323     // Set the read head to a random position
3324     int new_read_pos = ctx.GetRandom().GetInt(read.GetMemory().GetSize());
3325     read.Set(new_read_pos, read.GetMemSpace());
3326 
3327     // Reset any start/end labels that we might have been copying.
3328     m_current->m_copying_site = false;
3329     m_current->m_copying_label.Clear();
3330   }
3331 
3332 
3333   // Peek at the next inst to see if it is a NOP
3334   // If it isn't, then we can compare the label and possibly fall off
3335   if(m_current->m_copying_site) {
3336     if((!GetInstSet().IsNop(read.GetInst()) && (m_current->m_terminator_label == m_current->m_copying_label))) {
3337       // Move read head off of old target and back to itself
3338       read.GetProgramid()->RemoveContactingHead(read);
3339       read.Set(0, m_current->m_id);
3340 
3341       //Shrink the programid we were on by one inst
3342       if (write.GetMemory().GetSize()>1)
3343       {
3344         write.GetMemory().Resize( write.GetMemory().GetSize() - 1 );
3345       }
3346 
3347       // \to do, we would apply insertion/deletion on divide instructions here
3348       // if we want them to happen for each new programid that is produced
3349       //  // Handle Divide Mutations...
3350 
3351       // This would be equivalent to
3352       // Divide_DoMutations(ctx, mut_multiplier);
3353       // But that operates on m_child_genome, currently
3354 
3355       return true;
3356     }
3357   }
3358 
3359   // Check our processivity - read and write heads fall off with some probability
3360   // What kind of programid are we writing?
3361   double terminate_p =  1 - ((m_programids[read.GetMemSpace()]->GetReadable()) ? READABLE_COPY_PROCESSIVITY : EXECUTABLE_COPY_PROCESSIVITY);
3362   if ( ctx.GetRandom().P(terminate_p) ) m_reset_heads = true;
3363 
3364   return ret;
3365 }
3366 
3367 /*! This instruction creates a new organism by randomly dividing the programids with
3368 the daughter cell. Currently we convert the daughter genomes back into one list with pseudo-instructions
3369 telling us where new programids start and some of their properties. This is pretty inefficient.
3370 */
Inst_ProgramidDivide(cAvidaContext & ctx)3371 bool cHardwareGX::Inst_ProgramidDivide(cAvidaContext& ctx)
3372 {
3373   // Even if unsuccessful, we reset task inputs
3374   m_reset_inputs = true;
3375 
3376   //This stuff is usually set by Divide_CheckViable, leaving it zero causes problems
3377   m_organism->GetPhenotype().SetLinesExecuted(1);
3378   m_organism->GetPhenotype().SetLinesCopied(1);
3379 
3380   // Let's make sure that things seem sane.
3381   cHeadProgramid& read = GetHead(nHardware::HEAD_READ); // The parent.
3382   cHeadProgramid& write = GetHead(nHardware::HEAD_WRITE); // The offspring.
3383 
3384   // If either of these heads are on m_current, this instruction fails.
3385   if(read.GetMemSpace() == m_current->GetID()) return false;
3386   if(write.GetMemSpace() == m_current->GetID()) return false;
3387 
3388   // It should never be the case that the read and write heads are on the same programid.
3389   assert(read.GetMemSpace() != write.GetMemSpace());
3390   // Actually, it can happen with bind2 @JEB
3391 
3392   // If the read and write heads are on the same programid, then fail
3393   if (read.GetMemSpace() == write.GetMemSpace()) return false;
3394 
3395   // If we're not bound to two bindable programids, this instruction fails.
3396   if(!m_programids[read.GetMemSpace()]->GetBindable()) return false;
3397   if(!m_programids[write.GetMemSpace()]->GetBindable()) return false;
3398 
3399   // Now, let's keep track of two different lists of programids, one for the parent,
3400   // and one for the offspring.
3401   programid_list parent;
3402   programid_list offspring;
3403   // We're also going to do all our work on a temporary list, so that we can fail
3404   // without affecting the state of the caller.
3405   programid_list all(m_programids);
3406   // This is a list of fragments, to be deleted once we've passed the viability check.
3407   programid_list fragments;
3408 
3409   // The currently executing programid called the divide instruction.  The caller
3410   // is (hopefully) a DNA polymerase, therefore it knows which genome fragments go where.
3411   parent.push_back(m_programids[read.GetMemSpace()]); // The parent's genome.
3412   all[read.GetMemSpace()] = 0;
3413   offspring.push_back(m_programids[write.GetMemSpace()]); // The offspring's genome.
3414   //offspring.back()->SetBindable(true);
3415   all[write.GetMemSpace()] = 0;
3416 
3417   // Locate and remove all incomplete genomes, identified by programids that have
3418   // write heads on them.
3419   for(programid_list::iterator i=all.begin(); i!=all.end(); ++i) {
3420     // Does this programid currently have it's write head somewhere?
3421     if((*i != 0) && ((*i)->GetHead(nHardware::HEAD_WRITE).GetMemSpace() != (*i)->GetID())) {
3422       // Yes - It is likely an incomplete genome fragment, so don't
3423       // allow it to propagate.
3424       fragments.push_back(all[(*i)->GetHead(nHardware::HEAD_WRITE).GetMemSpace()]);
3425       all[(*i)->GetHead(nHardware::HEAD_WRITE).GetMemSpace()] = 0;
3426     }
3427   }
3428 
3429   // Divvy up the programids.
3430   for(programid_list::iterator i=all.begin(); i!=all.end(); ++i) {
3431     if(*i != 0) {
3432       if(ctx.GetRandom().GetUInt(2) == 0) {
3433         // Offspring!
3434         offspring.push_back(*i);
3435       } else {
3436         // Parent!
3437         parent.push_back(*i);
3438       }
3439     }
3440   }
3441 
3442   ///// Failure conditions (custom divide_check_viable)
3443   // It is possible that the divide kills the child and the parent
3444   // Each must have genomic programids of some minimum length
3445   // and an executable programid (otherwise it is inviable)
3446   // For now we leave a zombie mother to die of old age
3447   // but do not permit creating an inviable daughter
3448 
3449   // Conditions for successful replication
3450   int num_daughter_programids = 0;
3451   int daughter_genome_length = 0;
3452   bool daughter_has_executable = false;
3453   bool daughter_has_bindable = false;
3454 
3455   // Calculate these conditions for offspring.
3456   for(programid_list::iterator i=offspring.begin(); i!=offspring.end(); ++i) {
3457     ++num_daughter_programids;
3458     if((*i)->GetReadable()) {
3459       daughter_genome_length += (*i)->GetMemory().GetSize();
3460     }
3461     daughter_has_executable = daughter_has_executable || (*i)->GetExecutable();
3462     daughter_has_bindable = daughter_has_bindable || (*i)->GetBindable();
3463   }
3464   assert(daughter_has_bindable); // We know this should be there...
3465 
3466   int num_mother_programids = 0;
3467   int mother_genome_length = 0;
3468   bool mother_has_executable = false;
3469   bool mother_has_bindable = false;
3470 
3471   // Calculate these conditions for parent.
3472   for(programid_list::iterator i=parent.begin(); i!=parent.end(); ++i) {
3473     ++num_mother_programids;
3474     if((*i)->GetReadable()) {
3475       mother_genome_length += (*i)->GetMemory().GetSize();
3476     }
3477     mother_has_executable = mother_has_executable || (*i)->GetExecutable();
3478     mother_has_bindable = mother_has_bindable || (*i)->GetBindable();
3479   }
3480   assert(mother_has_bindable); // We know this should be there...
3481 
3482   // And check them.  Note that if this check fails, we have *not* modified the
3483   // state of the calling programid.
3484   if((num_daughter_programids == 0)
3485      || (!daughter_has_executable)
3486      || (daughter_genome_length < 50)) {
3487     // \todo link to original genome length
3488     return false;
3489   }
3490   if((num_mother_programids == 0)
3491      || (!mother_has_executable)
3492      || (mother_genome_length < 50)) {
3493     // \todo link to original genome length
3494     return false;
3495   }
3496 
3497   // Ok, we're good to go.  We have to create the offspring's genome and delete the
3498   // offspring's programids from m_programids.
3499   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
3500   child_genome.Resize(1);
3501   m_organism->OffspringGenome().SetHardwareType(GetType());
3502   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
3503   if (m_world->GetVerbosity() >= VERBOSE_DETAILS) std::cout << "-=OFFSPRING=-" << endl;
3504   for(programid_list::iterator i=offspring.begin(); i!=offspring.end(); ++i) {
3505     (*i)->AppendLinearGenome(child_genome);
3506     if (m_world->GetVerbosity() >= VERBOSE_DETAILS) (*i)->PrintGenome(std::cout);
3507     delete *i;
3508     *i = 0;
3509   }
3510 
3511   // Now clean up the parent.
3512   m_programids.clear();
3513   if (m_world->GetVerbosity() >= VERBOSE_DETAILS) std::cout << "-=PARENT=-" << endl;
3514   for(programid_list::iterator i=parent.begin(); i!=parent.end(); ++i) {
3515     AddProgramid(*i);
3516     if (m_world->GetVerbosity() >= VERBOSE_DETAILS) (*i)->PrintGenome(std::cout);
3517   }
3518 
3519   // And delete the fragments.
3520   for(programid_list::iterator i=fragments.begin(); i!=fragments.end(); ++i) {
3521     delete *i;
3522   }
3523 
3524   // Activate the child
3525   m_organism->ActivateDivide(ctx);
3526 
3527   // Mother viability checks could go here.
3528   m_just_divided = true;
3529   return true;
3530 }
3531 
3532 /* Implicit RNAP Model
3533 Allocate a new genome programid and place the write head on it.
3534 */
Inst_ProgramidImplicitAllocate(cAvidaContext & ctx)3535 bool cHardwareGX::Inst_ProgramidImplicitAllocate(cAvidaContext& ctx)
3536 {
3537   const int dst = REG_BX;
3538   const int cur_size = m_programids[0]->GetMemory().GetSize();
3539   const int old_size = cur_size;
3540   const int allocated_size = Min((int) (m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get() * cur_size), MAX_GENOME_LENGTH);
3541 
3542   // Modified Allocate_Main()
3543     // must do divide before second allocate & must allocate positive amount...
3544   if (m_world->GetConfig().REQUIRE_ALLOCATE.Get() && m_mal_active == true) {
3545     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR, "Allocate already active");
3546     return false;
3547   }
3548   if (allocated_size < 1) {
3549     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
3550           cStringUtil::Stringf("Allocate of %d too small", allocated_size));
3551     return false;
3552   }
3553 
3554 
3555   const int max_alloc_size = (int) (old_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
3556   if (allocated_size > max_alloc_size) {
3557     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
3558           cStringUtil::Stringf("Allocate too large (%d > %d)",
3559                                allocated_size, max_alloc_size));
3560     return false;
3561   }
3562 
3563   const int max_old_size =
3564     (int) (allocated_size * m_world->GetConfig().OFFSPRING_SIZE_RANGE.Get());
3565   if (old_size > max_old_size) {
3566     m_organism->Fault(FAULT_LOC_ALLOC, FAULT_TYPE_ERROR,
3567           cStringUtil::Stringf("Allocate too small (%d > %d)",
3568                                old_size, max_old_size));
3569     return false;
3570   }
3571 
3572   Sequence new_genome(allocated_size);
3573   programid_ptr new_programid = new cProgramid(new_genome, this);
3574   new_programid->SetBindable(true);
3575   new_programid->SetReadable(true);
3576   AddProgramid(new_programid);
3577 
3578 /*  switch (m_world->GetConfig().ALLOC_METHOD.Get()) {
3579     case ALLOC_METHOD_NECRO:
3580       // Only break if this succeeds -- otherwise just do random.
3581       if (Allocate_Necro(new_size) == true) break;
3582     case ALLOC_METHOD_RANDOM:
3583       Allocate_Random(ctx, old_size, new_size);
3584       break;
3585     case ALLOC_METHOD_DEFAULT:
3586       Allocate_Default(new_size);
3587       break;
3588   } */
3589   m_mal_active = true;
3590   //--> End modified Main_Alloc
3591 
3592   // Set the write head to the newly allocated programid
3593   GetHead(nHardware::HEAD_WRITE).Set(0, new_programid->GetID());
3594   // Set the read head to the first programid (=current genome)
3595   GetHead(nHardware::HEAD_READ).Set(0, 0);
3596   GetRegister(dst) = cur_size;
3597 
3598   return true;
3599 }
3600 
3601 /* Implicit RNAP Model
3602 Create a new organism with a genome based on the current position
3603 of th write head.
3604 */
Inst_ProgramidImplicitDivide(cAvidaContext & ctx)3605 bool cHardwareGX::Inst_ProgramidImplicitDivide(cAvidaContext& ctx)
3606 {
3607   cHeadProgramid write_head = GetHead(nHardware::HEAD_WRITE);
3608   int child_end =  GetHead(nHardware::HEAD_WRITE).GetPosition();
3609 
3610   // Make sure this divide will produce a viable offspring.
3611   const bool viable = Divide_CheckViable(ctx, m_organism->GetGenome().GetSequence().GetSize(), child_end);
3612   if (viable == false) return false;
3613 
3614   // Since the divide will now succeed, set up the information to be sent
3615   // to the new organism
3616   Sequence& child_genome = m_organism->OffspringGenome().GetSequence();
3617   child_genome = m_programids[write_head.GetMemSpace()]->GetMemory();
3618   child_genome = child_genome.Crop(0, child_end);
3619   m_organism->OffspringGenome().SetHardwareType(GetType());
3620   m_organism->OffspringGenome().SetInstSet(m_inst_set->GetInstSetName());
3621 
3622 
3623   // Handle Divide Mutations...
3624   Divide_DoMutations(ctx);
3625 
3626   // Many tests will require us to run the offspring through a test CPU;
3627   // this is, for example, to see if mutations need to be reverted or if
3628   // lineages need to be updated.
3629   Divide_TestFitnessMeasures(ctx);
3630 
3631   // reset first time instruction costs
3632   for (int i = 0; i < m_inst_ft_cost.GetSize(); i++) {
3633     m_inst_ft_cost[i] = m_inst_set->GetFTCost(cInstruction(i));
3634   }
3635 
3636   m_mal_active = false;
3637   if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) {
3638     m_advance_ip = false;
3639   }
3640 
3641   // Activate the child
3642   bool parent_alive = m_organism->ActivateDivide(ctx);
3643 
3644   // Do more work if the parent lives through the birth of the offspring
3645   if (parent_alive) {
3646     if (m_world->GetConfig().DIVIDE_METHOD.Get() == DIVIDE_METHOD_SPLIT) Reset(ctx);
3647   }
3648 
3649   m_just_divided = true;
3650   return true;
3651 }
3652 
Inst_EndProgramidExecution(cAvidaContext & ctx)3653 bool cHardwareGX::Inst_EndProgramidExecution(cAvidaContext& ctx)
3654 {
3655   m_current->m_marked_for_death = true; //Mark us for death
3656   return true;
3657 }
3658 
3659 /* Full Implict Model*/
3660 
Inst_Promoter(cAvidaContext & ctx)3661 bool cHardwareGX::Inst_Promoter(cAvidaContext& ctx)
3662 {
3663   // Promoters don't do anything themselves
3664   return true;
3665 }
3666 
Inst_Terminator(cAvidaContext & ctx)3667 bool cHardwareGX::Inst_Terminator(cAvidaContext& ctx)
3668 {
3669   // Terminators don't do anything themselves
3670   return true;
3671 }
3672 
3673 /*
3674 Place the write head of this programid on the next available match
3675 in the genome. Upgrade to promoter rate at the final position of the label.
3676 */
Inst_HeadActivate(cAvidaContext & ctx)3677 bool cHardwareGX::Inst_HeadActivate(cAvidaContext& ctx)
3678 {
3679   // Remove current regulation first
3680   m_current->RemoveRegulation();
3681 
3682   // Find next best match.
3683   ReadLabel();
3684   GetLabel().Rotate(1, NUM_NOPS);
3685 
3686   int match_pos = FindRegulatoryMatch( GetLabel() );
3687   if (match_pos == -1) return false;
3688 
3689   GetHead(nHardware::HEAD_WRITE).Set(match_pos, 0); // Used to track regulation
3690   GetHead(nHardware::HEAD_FLOW).Set(match_pos+GetLabel().GetSize(), 0); // Used to track regulation
3691 
3692   int regulatory_footprint = 5;  // Positions ahead and behind label that it covers
3693   match_pos = (match_pos - regulatory_footprint + m_programids[0]->GetMemory().GetSize() ) %  m_programids[0]->GetMemory().GetSize();
3694 
3695   cHeadProgramid h(this);
3696   h.Set(match_pos, 0);
3697   for (int i=0; i < 2*regulatory_footprint + GetLabel().GetSize(); i++)
3698   {
3699     m_promoter_occupied_sites[h.GetPosition()] = -1; // Repress overlap
3700     // Except where we create a new promoter that starts expression right after the matched label
3701     if (i == regulatory_footprint + GetLabel().GetSize() - 1)
3702     {
3703           m_promoter_occupied_sites[h.GetPosition()] = +1;
3704     }
3705 
3706     h++;
3707   }
3708 
3709   AdjustPromoterRates();
3710 
3711   if (m_world->GetVerbosity() >= VERBOSE_DETAILS)
3712 	{
3713     cout << "Activate: position " << match_pos << " length " << 2*regulatory_footprint + GetLabel().GetSize() << endl;
3714     for (int i=0; i < m_programids[0]->GetMemory().GetSize(); i++)
3715     {
3716       cout << i << " " << m_promoter_rates[i] << " " << m_promoter_default_rates[i] << " " << m_promoter_occupied_sites[i] << endl;
3717     }
3718   }
3719   return true;
3720 }
3721 
3722 /*
3723 Place the write head of this programid on the next available match
3724 in the genome. Downgrade promoter rates to background for 5 instructions on each side.
3725 */
Inst_HeadRepress(cAvidaContext & ctx)3726 bool cHardwareGX::Inst_HeadRepress(cAvidaContext& ctx)
3727 {
3728   // Remove current regulation first
3729   m_current->RemoveRegulation();
3730 
3731   // Find next best match.
3732   ReadLabel();
3733   GetLabel().Rotate(1, NUM_NOPS);
3734 
3735   int match_pos = FindRegulatoryMatch( GetLabel() );
3736   if (match_pos == -1) return false;
3737 
3738   GetHead(nHardware::HEAD_WRITE).Set(match_pos, 0); // Used to track regulation
3739   GetHead(nHardware::HEAD_FLOW).Set(match_pos+GetLabel().GetSize(), 0); // Used to track regulation
3740 
3741   int regulatory_footprint = 5;  // Positions ahead and behind label that it covers
3742   match_pos = (match_pos - regulatory_footprint + m_programids[0]->GetMemory().GetSize() ) %  m_programids[0]->GetMemory().GetSize();
3743 
3744   cHeadProgramid h(this);
3745   h.Set(match_pos, 0);
3746   for (int i=0; i < 2*regulatory_footprint + GetLabel().GetSize(); i++)
3747   {
3748     m_promoter_occupied_sites[h.GetPosition()] = -1;
3749     h++;
3750   }
3751 
3752   AdjustPromoterRates();
3753 
3754    if (m_world->GetVerbosity() >= VERBOSE_DETAILS)
3755 	{
3756     cout << "Repress: position " << match_pos << " length " << 2*regulatory_footprint + GetLabel().GetSize() << endl;
3757     for (int i=0; i < m_programids[0]->GetMemory().GetSize(); i++)
3758     {
3759       cout << i << " " << m_promoter_rates[i] << " " <<m_promoter_default_rates[i] << " " << m_promoter_occupied_sites[i] << endl;
3760     }
3761   }
3762 
3763   return true;
3764 }
3765 
3766 //! Adds a new programid to the current cHardwareGX.
AddProgramid(programid_ptr programid)3767 void cHardwareGX::AddProgramid(programid_ptr programid)
3768 {
3769   programid->m_id = m_programids.size();
3770   programid->ResetHeads();
3771 //  programid->ResetCPUCyclesUsed();
3772   programid->m_contacting_heads = 0;
3773   m_programids.push_back(programid);
3774 }
3775 
3776 
RemoveProgramid(unsigned int remove_index)3777 void cHardwareGX::RemoveProgramid(unsigned int remove_index)
3778 {
3779   assert(remove_index<m_programids.size());
3780 
3781   programid_ptr save=m_current;
3782   m_current = m_programids[remove_index];
3783 
3784   // Remove regulation if in implicit GX mode
3785   if (m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get() == 1) m_current->RemoveRegulation();
3786 
3787   if (m_world->GetVerbosity() >= VERBOSE_DETAILS)
3788   {
3789     cout << "Programid removed. Start position = " << m_current->GetHead(nHardware::HEAD_READ).GetPosition();
3790     cout << " length = " <<  m_current->m_memory.GetSize() << endl;
3791   }
3792 
3793   unsigned int write_head_contacted = (unsigned int)GetHead(nHardware::HEAD_WRITE).GetMemSpace();
3794 
3795   // First update the contacting head count for any cProgramids the heads
3796   // of the programid to be removed might have been on
3797 
3798   // The contacting head count is not used in the implicit model (and will be incorrect)
3799 
3800   if (!m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get()) m_current->Detach();
3801 
3802 
3803 //  m_programids[GetHead(nHardware::HEAD_READ).GetMemSpace()]->RemoveContactingHead(GetHead(nHardware::HEAD_READ));
3804 //  m_programids[GetHead(nHardware::HEAD_WRITE).GetMemSpace()]->RemoveContactingHead(GetHead(nHardware::HEAD_WRITE));
3805 
3806   // Update the programid list
3807   delete *(m_programids.begin()+remove_index);
3808   m_programids.erase(m_programids.begin()+remove_index);
3809   // Add adjust all the programid ids from the removed programid to the end.
3810   for(programid_list::iterator i=m_programids.begin()+remove_index; i!=m_programids.end(); ++i) {
3811     --(*i)->m_id;
3812   }
3813 
3814   // We also need to make sure heads are on the correct memory
3815   // spaces, since that indexing changes with the programid list
3816   for(unsigned int i=0; i< m_programids.size(); i++) {
3817     programid_ptr p = m_programids[i];
3818     for(int j=0; j<NUM_HEADS; j++) {
3819       // We removed the thing they were writing from or reading to
3820       // For now, just put the write head back on themselves (inactivating further copies)
3821       // Might want to also reset the read head..
3822       if (p->m_heads[j].GetMemSpace() == (int)remove_index) {
3823         p->m_heads[j].Set(0, p->m_id);
3824       } else if (p->m_heads[j].GetMemSpace() > (int)remove_index) {
3825         p->m_heads[j].Set(p->m_heads[j].GetPosition(), p->m_heads[j].GetMemSpace() - 1);
3826       }
3827     }
3828   }
3829 
3830   // Finally, also delete whatever programid our write head contacted (if not ourself!)
3831   // DON'T DO THIS in implicit mode, sine the write head means something different (regulation)
3832   if (m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get() == 0)
3833   {
3834     if(write_head_contacted != remove_index) {
3835       RemoveProgramid( (write_head_contacted > remove_index) ? write_head_contacted - 1 : write_head_contacted);
3836     }
3837   }
3838   m_current = save;
3839 }
3840 
3841 
ProcessImplicitGeneExpression(int in_limit)3842 void cHardwareGX::ProcessImplicitGeneExpression(int in_limit)
3843 {
3844   // If organism has no active promoters, catch us before we enter an infinite loop...
3845   if (m_promoter_sum == 0.0) return;
3846 
3847   static cInstruction terminator_inst = GetInstSet().GetInst(cStringUtil::Stringf("terminator"));
3848 
3849   if (in_limit == -1 ) in_limit = m_world->GetConfig().MAX_PROGRAMIDS.Get();
3850   if (in_limit > m_world->GetConfig().MAX_PROGRAMIDS.Get()) in_limit = m_world->GetConfig().MAX_PROGRAMIDS.Get();
3851 
3852   // Create executable programids up to the limit
3853   //const int genome_size = m_programids[m_promoter_update_head.GetMemSpace()]->GetMemory().GetSize();
3854   //const int inc = Min(genome_size, m_world->GetConfig().IMPLICIT_MAX_PROGRAMID_LENGTH.Get());
3855 
3856   while ( m_programids.size() < (unsigned int)in_limit )
3857   {
3858     // Update promoter states according to rates until one fires
3859 
3860     do  {
3861       // This way goes straight through the genome
3862       m_promoter_update_head++;
3863 
3864       // This way goes interspersed through the genome -- Add as a config option @JEB
3865       /*
3866       int new_pos = m_promoter_update_head.GetPosition();
3867       new_pos += inc;
3868       if ( new_pos >= genome_size )
3869       {
3870         new_pos++;
3871         new_pos %= inc;
3872       }
3873       */
3874 
3875       m_promoter_states[m_promoter_update_head.GetPosition()] += m_promoter_rates[m_promoter_update_head.GetPosition()];
3876       if ( (m_world->GetVerbosity() >= VERBOSE_DETAILS) && (m_promoter_states[m_promoter_update_head.GetPosition()] > 0) )
3877       {
3878         cout << "Promoter position " <<  m_promoter_update_head.GetPosition() << " value " << m_promoter_states[m_promoter_update_head.GetPosition()] << endl;
3879       }
3880     } while (m_promoter_states[m_promoter_update_head.GetPosition()] < 1.0);
3881 
3882     m_promoter_states[m_promoter_update_head.GetPosition()] -= 1.0;
3883 
3884     // Create new programid
3885     Sequence new_genome(m_world->GetConfig().IMPLICIT_MAX_PROGRAMID_LENGTH.Get());
3886     programid_ptr new_programid = new cProgramid(new_genome, this);
3887     new_programid->SetExecutable(true);
3888     AddProgramid(new_programid);
3889 
3890     cHeadProgramid read_head(m_promoter_update_head);
3891     read_head++; //Don't copy the promoter instruction itself (we start after that position)
3892     cHeadProgramid write_head(this, 0, new_programid->GetID());
3893     int copied = 0;
3894     cInstruction inst;
3895     do {
3896       inst = read_head.GetInst();
3897       if (inst == terminator_inst) break; // Early termination
3898       write_head.SetInst(inst);
3899       write_head++;
3900       read_head++;
3901       copied++;
3902     } while (write_head.GetPosition() != 0);
3903 
3904     // Set the read head of this programid to where it began so that we can keep track in trace files.
3905     new_programid->GetHead(nHardware::HEAD_READ).Set(m_promoter_update_head.GetPosition(),0);
3906     // Adjust length downward if prematurely terminated...
3907     if (inst == terminator_inst)
3908     {
3909       new_programid->m_memory.ResizeOld( Max(1, copied) );
3910       // If the length was zero, then we are left with a single NOP.
3911     }
3912 
3913     if (m_world->GetVerbosity() >= VERBOSE_DETAILS)
3914     {
3915       cout << "New programid created. Start position = " << new_programid->GetHead(nHardware::HEAD_READ).GetPosition();
3916       cout << " length = " <<  new_programid->m_memory.GetSize() << endl;
3917     }
3918 
3919     m_promoter_update_head++; //move on to the next position
3920   }
3921 }
3922 
3923 
AdjustPromoterRates()3924 void cHardwareGX::AdjustPromoterRates()
3925 {
3926   cHeadProgramid h(this);
3927   h.Set(0,0);
3928 
3929   m_promoter_sum = 0.0;
3930 
3931   do {
3932     switch (m_promoter_occupied_sites[h.GetPosition()])
3933     {
3934       case +1: // Activated
3935       m_promoter_rates[h.GetPosition()] = 1;
3936       break;
3937       case 0:
3938       m_promoter_rates[h.GetPosition()] = m_promoter_default_rates[h.GetPosition()];
3939       break;
3940       case -1: // Repressed
3941       m_promoter_rates[h.GetPosition()] = m_world->GetConfig().IMPLICIT_BG_PROMOTER_RATE.Get();
3942       break;
3943       default: //Error
3944       assert(1);
3945    }
3946 
3947     m_promoter_sum += m_promoter_rates[h.GetPosition()];
3948     h++;
3949 
3950   } while (h.GetPosition() != 0);
3951 
3952 }
3953 
FindRegulatoryMatch(const cCodeLabel & label)3954 int cHardwareGX::FindRegulatoryMatch(const cCodeLabel& label)
3955 {
3956   // Examine number of sites matched by overlaying input label and this space in genome
3957   // Skip a site if it is already occupied by a regulator.
3958   cHeadProgramid h;
3959   h.Reset(this,0);
3960 
3961   int best_site = -1; // No match found
3962   int best_site_matched_positions = 0;
3963   do {
3964     int matched_positions = 0;
3965     cHeadProgramid m(h);
3966     for (int i=0; i<label.GetSize(); i++)
3967     {
3968       // Don't allow a site that overlaps current regulation
3969       if (m_promoter_occupied_sites[m.GetPosition()] != 0)
3970       {
3971         matched_positions = 0;
3972         break;
3973       }
3974 
3975       if ((m_inst_set->IsNop(m.GetInst())) && (label[i] == m_inst_set->GetNopMod( m.GetInst() )))
3976       {
3977         matched_positions++;
3978       }
3979       m++;
3980     }
3981 
3982     // Keep new bests
3983     if (matched_positions > best_site_matched_positions)
3984     {
3985       best_site = h.GetPosition();
3986       best_site_matched_positions = matched_positions;
3987       // If we find an exact match, we can bail early
3988       if (best_site_matched_positions == label.GetSize()) return best_site;
3989     }
3990 
3991     h++;
3992   } while (h.GetPosition() != 0);
3993 
3994   return best_site;
3995 }
3996 
3997 /*! Construct this cProgramid, and initialize hardware resources.
3998 */
cProgramid(const Sequence & genome,cHardwareGX * hardware)3999 cHardwareGX::cProgramid::cProgramid(const Sequence& genome, cHardwareGX* hardware)
4000 : m_gx_hardware(hardware)
4001 , m_unique_id(hardware->m_last_unique_id_assigned++)
4002 , m_executable(false)
4003 , m_bindable(false)
4004 , m_readable(false)
4005 , m_marked_for_death(false)
4006 , m_cpu_cycles_used(0)
4007 , m_copying_site(false)
4008 , m_memory(genome)
4009 , m_input_buf(m_gx_hardware->m_world->GetEnvironment().GetInputSize())
4010 , m_output_buf(m_gx_hardware->m_world->GetEnvironment().GetOutputSize())
4011 {
4012   assert(m_gx_hardware!=0);
4013   for(int i=0; i<NUM_HEADS; ++i) {
4014     m_heads[i].Reset(hardware);
4015   }
4016 
4017   if (!m_gx_hardware->m_world->GetConfig().IMPLICIT_GENE_EXPRESSION.Get())
4018   {
4019     // Check what flags should be set on this programid.
4020     for(int i=0; i<m_memory.GetSize();) {
4021       if(m_memory[i]==GetInst("PROGRAMID")) {
4022         m_memory.Remove(i);
4023         continue;
4024       }
4025       if(m_memory[i]==GetInst("EXECUTABLE")) {
4026         m_memory.Remove(i);
4027         m_executable=true;
4028         continue;
4029       }
4030       if(m_memory[i]==GetInst("BINDABLE")) {
4031         m_memory.Remove(i);
4032         m_bindable=true;
4033         continue;
4034       }
4035       if(m_memory[i]==GetInst("READABLE")) {
4036         m_memory.Remove(i);
4037         m_readable=true;
4038         continue;
4039       }
4040       ++i;
4041     }
4042   }
4043 
4044   Reset();
4045 }
4046 
ResetHeads()4047 void cHardwareGX::cProgramid::ResetHeads()
4048 {
4049   for(int i=0; i<NUM_HEADS; ++i) {
4050     m_heads[i].SetProgramid(this);
4051     m_heads[i].Reset(m_gx_hardware, m_id);
4052   }
4053 }
4054 
Reset()4055 void cHardwareGX::cProgramid::Reset()
4056 {
4057   for (int i = 0; i < NUM_REGISTERS; i++) m_regs[i] = 0;
4058   ResetHeads();
4059 
4060   m_stack.Clear();
4061   m_read_label.Clear();
4062   m_next_label.Clear();
4063 }
4064 
4065 /*! Append this programid's genome to the passed in genome.  Include the tags
4066 that specify what this programid is capable of.
4067 */
AppendLinearGenome(Sequence & genome)4068 void cHardwareGX::cProgramid::AppendLinearGenome(Sequence& genome) {
4069   genome.Append(GetInst("PROGRAMID"));
4070   if(GetExecutable()) { genome.Append(GetInst("EXECUTABLE")); }
4071   if(GetBindable()) { genome.Append(GetInst("BINDABLE")); }
4072   if(GetReadable()) { genome.Append(GetInst("READABLE")); }
4073   genome.Append(m_memory);
4074 }
4075 
4076 
PrintGenome(std::ostream & out)4077 void cHardwareGX::cProgramid::PrintGenome(std::ostream& out) {
4078   out << "Programid ID: " << m_id << " UID:" << m_unique_id << endl;
4079   if(GetExecutable()) out << " EXECUTABLE";
4080   if(GetBindable()) out << " BINDABLE";
4081   if(GetReadable()) out << " READABLE";
4082   out << endl;
4083   out << " Mem (" << GetMemory().GetSize() << "):" << " " << GetMemory().AsString() << endl;
4084   out.flush();
4085 }
4086 
4087 
4088 /*! This method attempts to match this cProgramid with the passed-in label.  If the
4089 match is succesful, it returns true and a cMatchSite object that may be used to bind
4090 to the programid.  If the match is unsuccessful, it return false and the cMatchSite
4091 object points to null.
4092 
4093 A "successful" match is one where this cProgramid has a series of NOPs that are similar
4094 to the the passed-in label.  A number of configuration options (will eventually)
4095 control how precisely the NOPs must be related (e.g., exact, all-but-one, etc.).
4096 */
Sites(const cCodeLabel & label)4097 std::vector<cHardwareGX::cMatchSite> cHardwareGX::cProgramid::Sites(const cCodeLabel& label)
4098 {
4099   std::vector<cHardwareGX::cMatchSite> matches;
4100   if(!m_bindable) return matches;
4101 
4102   cInstruction site_inst = m_gx_hardware->GetInstSet().GetInst("site");
4103 
4104   // Create a new search head at the beginning of our memory space
4105   // \to do doesn't properly find wrap-around matches overlapping the origin of the memory
4106 
4107   //Find the first non-NOP and start there (this allows ups to wrap around correctly)
4108   cHeadCPU search_head(m_gx_hardware, 0, m_id);
4109   int first_non_nop = -1;
4110   do {
4111     if ( !m_gx_hardware->m_inst_set->IsNop(search_head.GetInst()) )
4112     {
4113       first_non_nop = search_head.GetPosition();
4114       break;
4115     }
4116     search_head++;
4117   } while (search_head.GetPosition() != 0);
4118 
4119   // This genome is all NOPs...
4120   if (first_non_nop == -1) return matches;
4121 
4122   //keep track of the first time we find a non-NOP instruction (finish when we reach it a second time)
4123   int site_pos = -1;
4124   cCodeLabel site_label;
4125 
4126   // Start at this instruction
4127   search_head.Set(first_non_nop, m_id);
4128   do {
4129 
4130     if (search_head.GetInst() == site_inst)
4131     {
4132       site_pos = search_head.GetPosition();
4133       site_label.Clear();
4134     }
4135     else if ( m_gx_hardware->m_inst_set->IsNop(search_head.GetInst()) && (site_pos != -1) )
4136     {
4137       // Add NOPs to the current label
4138       site_label.AddNop( m_gx_hardware->m_inst_set->GetNopMod( search_head.GetInst() ) );
4139     }
4140     else // Any other non-NOP instruction means to stop looking for terminator matches
4141     {
4142       site_pos = -1;
4143     }
4144 
4145     // Is the next inst a NOP?
4146     // If not, then check our current label for termination
4147     if (site_pos != -1)
4148     {
4149       int old_pos = search_head.GetPosition();
4150       search_head++;
4151       if ( !m_gx_hardware->m_inst_set->IsNop( search_head.GetInst()) )
4152       {
4153         if ( site_label == label )
4154         {
4155           cMatchSite match;
4156           match.m_programid = this;
4157           match.m_site = site_pos; // We return is exactly on the site
4158           match.m_label = site_label;
4159           matches.push_back(match);
4160         }
4161       }
4162 
4163       // Grrr. Heads don't wrap backwards properly!~! Can't just search_head--; No idea why.
4164       search_head.Set(old_pos, m_id);
4165     }
4166 
4167     search_head++;
4168   } while ( search_head.GetPosition() != first_non_nop ); // back at the beginning
4169 
4170   return matches;
4171 }
4172 
4173 
4174 /*! Bind attaches parts of this cProgramid to the cProgramid specified in the
4175 passed-in cMatchSite.  Currently, we only support binding the read head to a
4176 location in the genome of the other cProgramid, but this will be extended later.
4177 */
Bind(nHardware::tHeads head,cMatchSite & site)4178 void cHardwareGX::cProgramid::Bind(nHardware::tHeads head, cMatchSite& site) {
4179   // We set the terminator site label to the complement of the one that was bound.
4180   m_terminator_label = site.m_label;
4181   m_terminator_label.Rotate(1, NUM_NOPS);
4182 
4183   // Set the head.
4184   if(GetHead(head).GetMemSpace() != GetID()) {
4185     // Head is somewhere else; remove it
4186     m_gx_hardware->m_programids[GetHead(head).GetMemSpace()]->RemoveContactingHead(GetHead(head));
4187   }
4188 
4189   // Now attach it to the passed-in match site
4190   m_gx_hardware->m_programids[site.m_programid->GetID()]->AddContactingHead(GetHead(head));
4191   GetHead(head).Set(site.m_site, site.m_programid->GetID());
4192 }
4193 
4194 
4195 /*! This method detaches the caller's heads from programids that it is connected
4196 to.  It also updates the head contact counts.
4197 */
Detach()4198 void cHardwareGX::cProgramid::Detach() {
4199   int head = GetHead(nHardware::HEAD_WRITE).GetMemSpace();
4200   m_gx_hardware->m_programids[head]->RemoveContactingHead(GetHead(nHardware::HEAD_WRITE));
4201   GetHead(nHardware::HEAD_WRITE).Set(0, GetID());
4202 
4203   head = GetHead(nHardware::HEAD_READ).GetMemSpace();
4204   m_gx_hardware->m_programids[head]->RemoveContactingHead(GetHead(nHardware::HEAD_READ));
4205   GetHead(nHardware::HEAD_READ).Set(0, GetID());
4206 }
4207 
4208 /* End current regulation in implicit GX mode
4209 */
RemoveRegulation()4210 void cHardwareGX::cProgramid::RemoveRegulation()
4211 {
4212   if (GetHead(nHardware::HEAD_WRITE).GetMemSpace() != 0) return;
4213   int _pos = GetHead(nHardware::HEAD_WRITE).GetPosition();
4214 
4215   // Slow but reliable to cycling way of calculating size
4216   cHeadProgramid t(GetHead(nHardware::HEAD_WRITE));
4217   int _label_size = 0;
4218   while (t.GetPosition() != GetHead(nHardware::HEAD_FLOW).GetPosition())
4219   {
4220     _label_size++;
4221     t++;
4222   }
4223 
4224   //Reset heads
4225   GetHead(nHardware::HEAD_WRITE).Set(0, m_id);
4226   GetHead(nHardware::HEAD_FLOW).Set(0, m_id);
4227 
4228   int regulatory_footprint = 5;  // Positions ahead and behind label that it covers
4229   int match_pos = (_pos - regulatory_footprint + m_gx_hardware->m_programids[0]->GetMemory().GetSize() ) %  m_gx_hardware->m_programids[0]->GetMemory().GetSize();
4230 
4231   cHeadProgramid h(m_gx_hardware);
4232   h.Set(match_pos, 0);
4233   for (int i=0; i < 2*regulatory_footprint + _label_size; i++)
4234   {
4235     m_gx_hardware->m_promoter_occupied_sites[h.GetPosition()] = 0; //Zero regulation
4236     h++;
4237   }
4238 
4239   m_gx_hardware->AdjustPromoterRates();
4240 }
4241